Vendor deps.
This commit is contained in:
parent
294527085e
commit
91e18fde3a
|
|
@ -0,0 +1,15 @@
|
||||||
|
[source.crates-io]
|
||||||
|
replace-with = "vendored-sources"
|
||||||
|
|
||||||
|
[source."git+https://git.jpace121.net/public/limbo_graph.git?branch=main"]
|
||||||
|
git = "https://git.jpace121.net/public/limbo_graph.git"
|
||||||
|
branch = "main"
|
||||||
|
replace-with = "vendored-sources"
|
||||||
|
|
||||||
|
[source."git+ssh://git@git.jpace121.net:2222/public/j7s_diagnostics.git?branch=main"]
|
||||||
|
git = "ssh://git@git.jpace121.net:2222/public/j7s_diagnostics.git"
|
||||||
|
branch = "main"
|
||||||
|
replace-with = "vendored-sources"
|
||||||
|
|
||||||
|
[source.vendored-sources]
|
||||||
|
directory = "vendor"
|
||||||
|
|
@ -17,6 +17,7 @@ checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682"
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "j7s_diagnostics"
|
name = "j7s_diagnostics"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
|
source = "git+ssh://git@git.jpace121.net:2222/public/j7s_diagnostics.git?branch=main#c8b5db719c0de550a22b87f88c34ac7c0489f78c"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"limbo_graph",
|
"limbo_graph",
|
||||||
"serde",
|
"serde",
|
||||||
|
|
@ -163,7 +164,7 @@ checksum = "e7a5d71263a5a7d47b41f6b3f06ba276f10cc18b0931f1799f710578e2309348"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 3.0.3",
|
"syn 3.0.6",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|
@ -192,9 +193,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "syn"
|
name = "syn"
|
||||||
version = "3.0.3"
|
version = "3.0.6"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "53e9bae58849f64dfa4f5d5ae372c8341f7305f82a3868709269343628b659a3"
|
checksum = "8593e8e72159ed2257d083c7a454a85cbf854f37a0966d8d483aff8c8a3ebcee"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
|
|
@ -224,14 +225,14 @@ checksum = "bc04cd3e1236dd4a98afca4569f2deb3f120e5422a4023be2cb683f8486292af"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 3.0.3",
|
"syn 3.0.6",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "unicode-ident"
|
name = "unicode-ident"
|
||||||
version = "1.0.24"
|
version = "1.0.25"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75"
|
checksum = "ab72a15cf68d77cb0987d3684aa8a45c5ef827e8cb49ee2f30bfd7ba2feb519f"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "zmij"
|
name = "zmij"
|
||||||
|
|
|
||||||
|
|
@ -10,4 +10,4 @@ crate-type = ["cdylib"]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
pyo3 = "0.29.0"
|
pyo3 = "0.29.0"
|
||||||
j7s_diagnostics = { path="../j7s_diagnostics/", features=["std"] }
|
j7s_diagnostics = { branch="main", git="ssh://git@git.jpace121.net:2222/public/j7s_diagnostics.git", features=["std"] }
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
{"files":{".cargo_vcs_info.json":"9fe8de8b6d00ac74ff6fd3e25edbed562193b0441d891bb005bcb6e94b983019","CHANGELOG.md":"972078362c7c30856e5ef46aa52c1c0ec3de40f417544566e225204b4cd4982a","Cargo.toml":"db0e63b72de157a2f5194458b73b6542c3f4e17e33ab34a71d0260bfc035467e","Cargo.toml.orig":"f2ce51ef3c464f05e45c5ce01bbc40c90c8fd31885ed7b3b8bf831fd8cf4ad4f","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"7b63ecd5f1902af1b63729947373683c32745c16a10e8e6292e2e2dcd7e90ae0","README.md":"c3c627aa49e64826aaf4914e5a3bd0aa2d1b304464c3e99cb6507190d3620a85","src/kebab.rs":"3075cf72c95404e6b5800494a5d8a3c5f6dd5066593ddb249cefcb376e30b450","src/lib.rs":"bffcc5144da472d2f915696d4654f7608e60861d168d3dd07b5dcb8f14211153","src/lower_camel.rs":"3b1e367db1ae22aa8c49b6800abf5e23e6befadf7cc89a252534f7286676e11f","src/shouty_kebab.rs":"8539eeddd4d78c10a8d0df3e19ad171409e95429debcdc6b7dbefd82d37b6928","src/shouty_snake.rs":"e8b6dcb77de87e2355067d5d47037537b68fa51c2601924a6acfae409c6d9920","src/snake.rs":"e13e8a4373e9388044bd91edff496362a1e7f6bd52f5f6be14a043878035245d","src/title.rs":"a12abc5057b48b8d5922d2a11b6029b230e13ae9a04109a40407d19505c2521b","src/train.rs":"0cbe348135852c12e9c56ab93233ca5c044218bc1b8818b620c3e80cd19973c2","src/upper_camel.rs":"9036542a600fd261b046ac4574622f831335abcf1366665aab56f4045fceb0d5"},"package":"2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"}
|
||||||
|
|
@ -0,0 +1,6 @@
|
||||||
|
{
|
||||||
|
"git": {
|
||||||
|
"sha1": "070693322aee7c5c7fbee7c9964bf8d7d3a29c96"
|
||||||
|
},
|
||||||
|
"path_in_vcs": ""
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,25 @@
|
||||||
|
# unreleased
|
||||||
|
|
||||||
|
# 0.5.0
|
||||||
|
|
||||||
|
- Add `no_std` support.
|
||||||
|
- Remove non-additive `unicode` feature. The library now uses `char::is_alphanumeric`
|
||||||
|
instead of the `unicode-segmentation` library to determine word boundaries in all cases.
|
||||||
|
|
||||||
|
# 0.4.1
|
||||||
|
|
||||||
|
Improvements:
|
||||||
|
|
||||||
|
- Add Train-Case support
|
||||||
|
|
||||||
|
# 0.4.0
|
||||||
|
|
||||||
|
Breaking changes:
|
||||||
|
|
||||||
|
* Make unicode support optional (off by default). Enable the `unicode` crate
|
||||||
|
feature if you need unicode support.
|
||||||
|
* Rename all traits from `SomeCase` to `ToSomeCase`, matching `std`s convention
|
||||||
|
of beginning trait names with a verb (`ToOwned`, `AsRef`, …)
|
||||||
|
* Rename `ToMixedCase` to `ToLowerCamelCase`
|
||||||
|
* Rename `ToCamelCase` to `ToUpperCamelCase`
|
||||||
|
* Add `ToPascalCase` as an alias to `ToUpperCamelCase`
|
||||||
|
|
@ -0,0 +1,34 @@
|
||||||
|
# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO
|
||||||
|
#
|
||||||
|
# When uploading crates to the registry Cargo will automatically
|
||||||
|
# "normalize" Cargo.toml files for maximal compatibility
|
||||||
|
# with all versions of Cargo and also rewrite `path` dependencies
|
||||||
|
# to registry (e.g., crates.io) dependencies.
|
||||||
|
#
|
||||||
|
# If you are reading this file be aware that the original Cargo.toml
|
||||||
|
# will likely look very different (and much more reasonable).
|
||||||
|
# See Cargo.toml.orig for the original contents.
|
||||||
|
|
||||||
|
[package]
|
||||||
|
edition = "2021"
|
||||||
|
rust-version = "1.56"
|
||||||
|
name = "heck"
|
||||||
|
version = "0.5.0"
|
||||||
|
include = [
|
||||||
|
"src/**/*",
|
||||||
|
"LICENSE-*",
|
||||||
|
"README.md",
|
||||||
|
"CHANGELOG.md",
|
||||||
|
]
|
||||||
|
description = "heck is a case conversion library."
|
||||||
|
readme = "README.md"
|
||||||
|
keywords = [
|
||||||
|
"string",
|
||||||
|
"case",
|
||||||
|
"camel",
|
||||||
|
"snake",
|
||||||
|
"unicode",
|
||||||
|
]
|
||||||
|
categories = ["no-std"]
|
||||||
|
license = "MIT OR Apache-2.0"
|
||||||
|
repository = "https://github.com/withoutboats/heck"
|
||||||
|
|
@ -0,0 +1,11 @@
|
||||||
|
[package]
|
||||||
|
name = "heck"
|
||||||
|
version = "0.5.0"
|
||||||
|
edition = "2021"
|
||||||
|
rust-version = "1.56"
|
||||||
|
license = "MIT OR Apache-2.0"
|
||||||
|
description = "heck is a case conversion library."
|
||||||
|
repository = "https://github.com/withoutboats/heck"
|
||||||
|
keywords = ["string", "case", "camel", "snake", "unicode"]
|
||||||
|
categories = ["no-std"]
|
||||||
|
include = ["src/**/*", "LICENSE-*", "README.md", "CHANGELOG.md"]
|
||||||
|
|
@ -0,0 +1,201 @@
|
||||||
|
Apache License
|
||||||
|
Version 2.0, January 2004
|
||||||
|
http://www.apache.org/licenses/
|
||||||
|
|
||||||
|
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||||
|
|
||||||
|
1. Definitions.
|
||||||
|
|
||||||
|
"License" shall mean the terms and conditions for use, reproduction,
|
||||||
|
and distribution as defined by Sections 1 through 9 of this document.
|
||||||
|
|
||||||
|
"Licensor" shall mean the copyright owner or entity authorized by
|
||||||
|
the copyright owner that is granting the License.
|
||||||
|
|
||||||
|
"Legal Entity" shall mean the union of the acting entity and all
|
||||||
|
other entities that control, are controlled by, or are under common
|
||||||
|
control with that entity. For the purposes of this definition,
|
||||||
|
"control" means (i) the power, direct or indirect, to cause the
|
||||||
|
direction or management of such entity, whether by contract or
|
||||||
|
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||||
|
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||||
|
|
||||||
|
"You" (or "Your") shall mean an individual or Legal Entity
|
||||||
|
exercising permissions granted by this License.
|
||||||
|
|
||||||
|
"Source" form shall mean the preferred form for making modifications,
|
||||||
|
including but not limited to software source code, documentation
|
||||||
|
source, and configuration files.
|
||||||
|
|
||||||
|
"Object" form shall mean any form resulting from mechanical
|
||||||
|
transformation or translation of a Source form, including but
|
||||||
|
not limited to compiled object code, generated documentation,
|
||||||
|
and conversions to other media types.
|
||||||
|
|
||||||
|
"Work" shall mean the work of authorship, whether in Source or
|
||||||
|
Object form, made available under the License, as indicated by a
|
||||||
|
copyright notice that is included in or attached to the work
|
||||||
|
(an example is provided in the Appendix below).
|
||||||
|
|
||||||
|
"Derivative Works" shall mean any work, whether in Source or Object
|
||||||
|
form, that is based on (or derived from) the Work and for which the
|
||||||
|
editorial revisions, annotations, elaborations, or other modifications
|
||||||
|
represent, as a whole, an original work of authorship. For the purposes
|
||||||
|
of this License, Derivative Works shall not include works that remain
|
||||||
|
separable from, or merely link (or bind by name) to the interfaces of,
|
||||||
|
the Work and Derivative Works thereof.
|
||||||
|
|
||||||
|
"Contribution" shall mean any work of authorship, including
|
||||||
|
the original version of the Work and any modifications or additions
|
||||||
|
to that Work or Derivative Works thereof, that is intentionally
|
||||||
|
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||||
|
or by an individual or Legal Entity authorized to submit on behalf of
|
||||||
|
the copyright owner. For the purposes of this definition, "submitted"
|
||||||
|
means any form of electronic, verbal, or written communication sent
|
||||||
|
to the Licensor or its representatives, including but not limited to
|
||||||
|
communication on electronic mailing lists, source code control systems,
|
||||||
|
and issue tracking systems that are managed by, or on behalf of, the
|
||||||
|
Licensor for the purpose of discussing and improving the Work, but
|
||||||
|
excluding communication that is conspicuously marked or otherwise
|
||||||
|
designated in writing by the copyright owner as "Not a Contribution."
|
||||||
|
|
||||||
|
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||||
|
on behalf of whom a Contribution has been received by Licensor and
|
||||||
|
subsequently incorporated within the Work.
|
||||||
|
|
||||||
|
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||||
|
this License, each Contributor hereby grants to You a perpetual,
|
||||||
|
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||||
|
copyright license to reproduce, prepare Derivative Works of,
|
||||||
|
publicly display, publicly perform, sublicense, and distribute the
|
||||||
|
Work and such Derivative Works in Source or Object form.
|
||||||
|
|
||||||
|
3. Grant of Patent License. Subject to the terms and conditions of
|
||||||
|
this License, each Contributor hereby grants to You a perpetual,
|
||||||
|
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||||
|
(except as stated in this section) patent license to make, have made,
|
||||||
|
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||||
|
where such license applies only to those patent claims licensable
|
||||||
|
by such Contributor that are necessarily infringed by their
|
||||||
|
Contribution(s) alone or by combination of their Contribution(s)
|
||||||
|
with the Work to which such Contribution(s) was submitted. If You
|
||||||
|
institute patent litigation against any entity (including a
|
||||||
|
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||||
|
or a Contribution incorporated within the Work constitutes direct
|
||||||
|
or contributory patent infringement, then any patent licenses
|
||||||
|
granted to You under this License for that Work shall terminate
|
||||||
|
as of the date such litigation is filed.
|
||||||
|
|
||||||
|
4. Redistribution. You may reproduce and distribute copies of the
|
||||||
|
Work or Derivative Works thereof in any medium, with or without
|
||||||
|
modifications, and in Source or Object form, provided that You
|
||||||
|
meet the following conditions:
|
||||||
|
|
||||||
|
(a) You must give any other recipients of the Work or
|
||||||
|
Derivative Works a copy of this License; and
|
||||||
|
|
||||||
|
(b) You must cause any modified files to carry prominent notices
|
||||||
|
stating that You changed the files; and
|
||||||
|
|
||||||
|
(c) You must retain, in the Source form of any Derivative Works
|
||||||
|
that You distribute, all copyright, patent, trademark, and
|
||||||
|
attribution notices from the Source form of the Work,
|
||||||
|
excluding those notices that do not pertain to any part of
|
||||||
|
the Derivative Works; and
|
||||||
|
|
||||||
|
(d) If the Work includes a "NOTICE" text file as part of its
|
||||||
|
distribution, then any Derivative Works that You distribute must
|
||||||
|
include a readable copy of the attribution notices contained
|
||||||
|
within such NOTICE file, excluding those notices that do not
|
||||||
|
pertain to any part of the Derivative Works, in at least one
|
||||||
|
of the following places: within a NOTICE text file distributed
|
||||||
|
as part of the Derivative Works; within the Source form or
|
||||||
|
documentation, if provided along with the Derivative Works; or,
|
||||||
|
within a display generated by the Derivative Works, if and
|
||||||
|
wherever such third-party notices normally appear. The contents
|
||||||
|
of the NOTICE file are for informational purposes only and
|
||||||
|
do not modify the License. You may add Your own attribution
|
||||||
|
notices within Derivative Works that You distribute, alongside
|
||||||
|
or as an addendum to the NOTICE text from the Work, provided
|
||||||
|
that such additional attribution notices cannot be construed
|
||||||
|
as modifying the License.
|
||||||
|
|
||||||
|
You may add Your own copyright statement to Your modifications and
|
||||||
|
may provide additional or different license terms and conditions
|
||||||
|
for use, reproduction, or distribution of Your modifications, or
|
||||||
|
for any such Derivative Works as a whole, provided Your use,
|
||||||
|
reproduction, and distribution of the Work otherwise complies with
|
||||||
|
the conditions stated in this License.
|
||||||
|
|
||||||
|
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||||
|
any Contribution intentionally submitted for inclusion in the Work
|
||||||
|
by You to the Licensor shall be under the terms and conditions of
|
||||||
|
this License, without any additional terms or conditions.
|
||||||
|
Notwithstanding the above, nothing herein shall supersede or modify
|
||||||
|
the terms of any separate license agreement you may have executed
|
||||||
|
with Licensor regarding such Contributions.
|
||||||
|
|
||||||
|
6. Trademarks. This License does not grant permission to use the trade
|
||||||
|
names, trademarks, service marks, or product names of the Licensor,
|
||||||
|
except as required for reasonable and customary use in describing the
|
||||||
|
origin of the Work and reproducing the content of the NOTICE file.
|
||||||
|
|
||||||
|
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||||
|
agreed to in writing, Licensor provides the Work (and each
|
||||||
|
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||||
|
implied, including, without limitation, any warranties or conditions
|
||||||
|
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||||
|
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||||
|
appropriateness of using or redistributing the Work and assume any
|
||||||
|
risks associated with Your exercise of permissions under this License.
|
||||||
|
|
||||||
|
8. Limitation of Liability. In no event and under no legal theory,
|
||||||
|
whether in tort (including negligence), contract, or otherwise,
|
||||||
|
unless required by applicable law (such as deliberate and grossly
|
||||||
|
negligent acts) or agreed to in writing, shall any Contributor be
|
||||||
|
liable to You for damages, including any direct, indirect, special,
|
||||||
|
incidental, or consequential damages of any character arising as a
|
||||||
|
result of this License or out of the use or inability to use the
|
||||||
|
Work (including but not limited to damages for loss of goodwill,
|
||||||
|
work stoppage, computer failure or malfunction, or any and all
|
||||||
|
other commercial damages or losses), even if such Contributor
|
||||||
|
has been advised of the possibility of such damages.
|
||||||
|
|
||||||
|
9. Accepting Warranty or Additional Liability. While redistributing
|
||||||
|
the Work or Derivative Works thereof, You may choose to offer,
|
||||||
|
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||||
|
or other liability obligations and/or rights consistent with this
|
||||||
|
License. However, in accepting such obligations, You may act only
|
||||||
|
on Your own behalf and on Your sole responsibility, not on behalf
|
||||||
|
of any other Contributor, and only if You agree to indemnify,
|
||||||
|
defend, and hold each Contributor harmless for any liability
|
||||||
|
incurred by, or claims asserted against, such Contributor by reason
|
||||||
|
of your accepting any such warranty or additional liability.
|
||||||
|
|
||||||
|
END OF TERMS AND CONDITIONS
|
||||||
|
|
||||||
|
APPENDIX: How to apply the Apache License to your work.
|
||||||
|
|
||||||
|
To apply the Apache License to your work, attach the following
|
||||||
|
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||||
|
replaced with your own identifying information. (Don't include
|
||||||
|
the brackets!) The text should be enclosed in the appropriate
|
||||||
|
comment syntax for the file format. We also recommend that a
|
||||||
|
file or class name and description of purpose be included on the
|
||||||
|
same "printed page" as the copyright notice for easier
|
||||||
|
identification within third-party archives.
|
||||||
|
|
||||||
|
Copyright [yyyy] [name of copyright owner]
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
|
@ -0,0 +1,25 @@
|
||||||
|
Copyright (c) 2015 The Rust Project Developers
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any
|
||||||
|
person obtaining a copy of this software and associated
|
||||||
|
documentation files (the "Software"), to deal in the
|
||||||
|
Software without restriction, including without
|
||||||
|
limitation the rights to use, copy, modify, merge,
|
||||||
|
publish, distribute, sublicense, and/or sell copies of
|
||||||
|
the Software, and to permit persons to whom the Software
|
||||||
|
is furnished to do so, subject to the following
|
||||||
|
conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice
|
||||||
|
shall be included in all copies or substantial portions
|
||||||
|
of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
|
||||||
|
ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
|
||||||
|
TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
|
||||||
|
PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
|
||||||
|
SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||||
|
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||||
|
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
|
||||||
|
IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||||
|
DEALINGS IN THE SOFTWARE.
|
||||||
|
|
@ -0,0 +1,53 @@
|
||||||
|
# **heck** is a case conversion library
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
This library exists to provide case conversion between common cases like
|
||||||
|
CamelCase and snake_case. It is intended to be unicode aware, internally
|
||||||
|
consistent, and reasonably well performing.
|
||||||
|
|
||||||
|
## Definition of a word boundary
|
||||||
|
|
||||||
|
Word boundaries are defined by non-alphanumeric characters, as well as
|
||||||
|
within those words in this manner:
|
||||||
|
|
||||||
|
1. If an uppercase character is followed by lowercase letters, a word
|
||||||
|
boundary is considered to be just prior to that uppercase character.
|
||||||
|
2. If multiple uppercase characters are consecutive, they are considered to
|
||||||
|
be within a single word, except that the last will be part of the next word
|
||||||
|
if it is followed by lowercase characters (see rule 1).
|
||||||
|
|
||||||
|
That is, "HelloWorld" is segmented `Hello|World` whereas "XMLHttpRequest" is
|
||||||
|
segmented `XML|Http|Request`.
|
||||||
|
|
||||||
|
Characters not within words (such as spaces, punctuations, and underscores)
|
||||||
|
are not included in the output string except as they are a part of the case
|
||||||
|
being converted to. Multiple adjacent word boundaries (such as a series of
|
||||||
|
underscores) are folded into one. ("hello__world" in snake case is therefore
|
||||||
|
"hello_world", not the exact same string). Leading or trailing word boundary
|
||||||
|
indicators are dropped, except insofar as CamelCase capitalizes the first word.
|
||||||
|
|
||||||
|
## Cases contained in this library:
|
||||||
|
|
||||||
|
1. UpperCamelCase
|
||||||
|
2. lowerCamelCase
|
||||||
|
3. snake_case
|
||||||
|
4. kebab-case
|
||||||
|
5. SHOUTY_SNAKE_CASE
|
||||||
|
6. Title Case
|
||||||
|
7. SHOUTY-KEBAB-CASE
|
||||||
|
8. Train-Case
|
||||||
|
|
||||||
|
## MSRV
|
||||||
|
|
||||||
|
The minimum supported Rust version for this crate is 1.56.0. This may change in
|
||||||
|
minor or patch releases, but we probably won't ever require a very recent
|
||||||
|
version. If you would like to have a stronger guarantee than that, please open
|
||||||
|
an issue.
|
||||||
|
|
||||||
|
## License
|
||||||
|
|
||||||
|
heck is distributed under the terms of both the MIT license and the
|
||||||
|
Apache License (Version 2.0).
|
||||||
|
|
||||||
|
See LICENSE-APACHE and LICENSE-MIT for details.
|
||||||
|
|
@ -0,0 +1,75 @@
|
||||||
|
use core::fmt;
|
||||||
|
|
||||||
|
use alloc::{borrow::ToOwned, string::ToString};
|
||||||
|
|
||||||
|
use crate::{lowercase, transform};
|
||||||
|
|
||||||
|
/// This trait defines a kebab case conversion.
|
||||||
|
///
|
||||||
|
/// In kebab-case, word boundaries are indicated by hyphens.
|
||||||
|
///
|
||||||
|
/// ## Example:
|
||||||
|
///
|
||||||
|
/// ```rust
|
||||||
|
/// use heck::ToKebabCase;
|
||||||
|
///
|
||||||
|
/// let sentence = "We are going to inherit the earth.";
|
||||||
|
/// assert_eq!(sentence.to_kebab_case(), "we-are-going-to-inherit-the-earth");
|
||||||
|
/// ```
|
||||||
|
pub trait ToKebabCase: ToOwned {
|
||||||
|
/// Convert this type to kebab case.
|
||||||
|
fn to_kebab_case(&self) -> Self::Owned;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ToKebabCase for str {
|
||||||
|
fn to_kebab_case(&self) -> Self::Owned {
|
||||||
|
AsKebabCase(self).to_string()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// This wrapper performs a kebab case conversion in [`fmt::Display`].
|
||||||
|
///
|
||||||
|
/// ## Example:
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// use heck::AsKebabCase;
|
||||||
|
///
|
||||||
|
/// let sentence = "We are going to inherit the earth.";
|
||||||
|
/// assert_eq!(format!("{}", AsKebabCase(sentence)), "we-are-going-to-inherit-the-earth");
|
||||||
|
/// ```
|
||||||
|
pub struct AsKebabCase<T: AsRef<str>>(pub T);
|
||||||
|
|
||||||
|
impl<T: AsRef<str>> fmt::Display for AsKebabCase<T> {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
transform(self.0.as_ref(), lowercase, |f| write!(f, "-"), f)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::ToKebabCase;
|
||||||
|
|
||||||
|
macro_rules! t {
|
||||||
|
($t:ident : $s1:expr => $s2:expr) => {
|
||||||
|
#[test]
|
||||||
|
fn $t() {
|
||||||
|
assert_eq!($s1.to_kebab_case(), $s2)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
t!(test1: "CamelCase" => "camel-case");
|
||||||
|
t!(test2: "This is Human case." => "this-is-human-case");
|
||||||
|
t!(test3: "MixedUP CamelCase, with some Spaces" => "mixed-up-camel-case-with-some-spaces");
|
||||||
|
t!(test4: "mixed_up_ snake_case with some _spaces" => "mixed-up-snake-case-with-some-spaces");
|
||||||
|
t!(test5: "kebab-case" => "kebab-case");
|
||||||
|
t!(test6: "SHOUTY_SNAKE_CASE" => "shouty-snake-case");
|
||||||
|
t!(test7: "snake_case" => "snake-case");
|
||||||
|
t!(test8: "this-contains_ ALLKinds OfWord_Boundaries" => "this-contains-all-kinds-of-word-boundaries");
|
||||||
|
t!(test9: "XΣXΣ baffle" => "xσxς-baffle");
|
||||||
|
t!(test10: "XMLHttpRequest" => "xml-http-request");
|
||||||
|
t!(test11: "لِنَذْهَبْ إِلَى السِّيْنَمَا" => "لِنَذْهَبْ-إِلَى-السِّيْنَمَا");
|
||||||
|
// Japanese and Chinese do not have word separation.
|
||||||
|
t!(test12: "ファイルを読み込み" => "ファイルを読み込み");
|
||||||
|
t!(test13: "祝你一天过得愉快" => "祝你一天过得愉快");
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,192 @@
|
||||||
|
//! **heck** is a case conversion library.
|
||||||
|
//!
|
||||||
|
//! This library exists to provide case conversion between common cases like
|
||||||
|
//! CamelCase and snake_case. It is intended to be unicode aware, internally
|
||||||
|
//! consistent, and reasonably well performing.
|
||||||
|
//!
|
||||||
|
//! ## Definition of a word boundary
|
||||||
|
//!
|
||||||
|
//! Word boundaries are defined by non-alphanumeric characters, as well as
|
||||||
|
//! within those words in this manner:
|
||||||
|
//!
|
||||||
|
//! 1. If an uppercase character is followed by lowercase letters, a word
|
||||||
|
//! boundary is considered to be just prior to that uppercase character.
|
||||||
|
//! 2. If multiple uppercase characters are consecutive, they are considered to
|
||||||
|
//! be within a single word, except that the last will be part of the next word
|
||||||
|
//! if it is followed by lowercase characters (see rule 1).
|
||||||
|
//!
|
||||||
|
//! That is, "HelloWorld" is segmented `Hello|World` whereas "XMLHttpRequest" is
|
||||||
|
//! segmented `XML|Http|Request`.
|
||||||
|
//!
|
||||||
|
//! Characters not within words (such as spaces, punctuations, and underscores)
|
||||||
|
//! are not included in the output string except as they are a part of the case
|
||||||
|
//! being converted to. Multiple adjacent word boundaries (such as a series of
|
||||||
|
//! underscores) are folded into one. ("hello__world" in snake case is therefore
|
||||||
|
//! "hello_world", not the exact same string). Leading or trailing word boundary
|
||||||
|
//! indicators are dropped, except insofar as CamelCase capitalizes the first
|
||||||
|
//! word.
|
||||||
|
//!
|
||||||
|
//! ### Cases contained in this library:
|
||||||
|
//!
|
||||||
|
//! 1. UpperCamelCase
|
||||||
|
//! 2. lowerCamelCase
|
||||||
|
//! 3. snake_case
|
||||||
|
//! 4. kebab-case
|
||||||
|
//! 5. SHOUTY_SNAKE_CASE
|
||||||
|
//! 6. Title Case
|
||||||
|
//! 7. SHOUTY-KEBAB-CASE
|
||||||
|
//! 8. Train-Case
|
||||||
|
#![deny(missing_docs)]
|
||||||
|
#![forbid(unsafe_code)]
|
||||||
|
#![no_std]
|
||||||
|
|
||||||
|
extern crate alloc;
|
||||||
|
|
||||||
|
mod kebab;
|
||||||
|
mod lower_camel;
|
||||||
|
mod shouty_kebab;
|
||||||
|
mod shouty_snake;
|
||||||
|
mod snake;
|
||||||
|
mod title;
|
||||||
|
mod train;
|
||||||
|
mod upper_camel;
|
||||||
|
|
||||||
|
pub use kebab::{AsKebabCase, ToKebabCase};
|
||||||
|
pub use lower_camel::{AsLowerCamelCase, ToLowerCamelCase};
|
||||||
|
pub use shouty_kebab::{AsShoutyKebabCase, ToShoutyKebabCase};
|
||||||
|
pub use shouty_snake::{
|
||||||
|
AsShoutySnakeCase, AsShoutySnakeCase as AsShoutySnekCase, ToShoutySnakeCase, ToShoutySnekCase,
|
||||||
|
};
|
||||||
|
pub use snake::{AsSnakeCase, AsSnakeCase as AsSnekCase, ToSnakeCase, ToSnekCase};
|
||||||
|
pub use title::{AsTitleCase, ToTitleCase};
|
||||||
|
pub use train::{AsTrainCase, ToTrainCase};
|
||||||
|
pub use upper_camel::{
|
||||||
|
AsUpperCamelCase, AsUpperCamelCase as AsPascalCase, ToPascalCase, ToUpperCamelCase,
|
||||||
|
};
|
||||||
|
|
||||||
|
use core::fmt;
|
||||||
|
|
||||||
|
fn transform<F, G>(
|
||||||
|
s: &str,
|
||||||
|
mut with_word: F,
|
||||||
|
mut boundary: G,
|
||||||
|
f: &mut fmt::Formatter,
|
||||||
|
) -> fmt::Result
|
||||||
|
where
|
||||||
|
F: FnMut(&str, &mut fmt::Formatter) -> fmt::Result,
|
||||||
|
G: FnMut(&mut fmt::Formatter) -> fmt::Result,
|
||||||
|
{
|
||||||
|
/// Tracks the current 'mode' of the transformation algorithm as it scans
|
||||||
|
/// the input string.
|
||||||
|
///
|
||||||
|
/// The mode is a tri-state which tracks the case of the last cased
|
||||||
|
/// character of the current word. If there is no cased character
|
||||||
|
/// (either lowercase or uppercase) since the previous word boundary,
|
||||||
|
/// than the mode is `Boundary`. If the last cased character is lowercase,
|
||||||
|
/// then the mode is `Lowercase`. Othertherwise, the mode is
|
||||||
|
/// `Uppercase`.
|
||||||
|
#[derive(Clone, Copy, PartialEq)]
|
||||||
|
enum WordMode {
|
||||||
|
/// There have been no lowercase or uppercase characters in the current
|
||||||
|
/// word.
|
||||||
|
Boundary,
|
||||||
|
/// The previous cased character in the current word is lowercase.
|
||||||
|
Lowercase,
|
||||||
|
/// The previous cased character in the current word is uppercase.
|
||||||
|
Uppercase,
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut first_word = true;
|
||||||
|
|
||||||
|
for word in s.split(|c: char| !c.is_alphanumeric()) {
|
||||||
|
let mut char_indices = word.char_indices().peekable();
|
||||||
|
let mut init = 0;
|
||||||
|
let mut mode = WordMode::Boundary;
|
||||||
|
|
||||||
|
while let Some((i, c)) = char_indices.next() {
|
||||||
|
if let Some(&(next_i, next)) = char_indices.peek() {
|
||||||
|
// The mode including the current character, assuming the
|
||||||
|
// current character does not result in a word boundary.
|
||||||
|
let next_mode = if c.is_lowercase() {
|
||||||
|
WordMode::Lowercase
|
||||||
|
} else if c.is_uppercase() {
|
||||||
|
WordMode::Uppercase
|
||||||
|
} else {
|
||||||
|
mode
|
||||||
|
};
|
||||||
|
|
||||||
|
// Word boundary after if current is not uppercase and next
|
||||||
|
// is uppercase
|
||||||
|
if next_mode == WordMode::Lowercase && next.is_uppercase() {
|
||||||
|
if !first_word {
|
||||||
|
boundary(f)?;
|
||||||
|
}
|
||||||
|
with_word(&word[init..next_i], f)?;
|
||||||
|
first_word = false;
|
||||||
|
init = next_i;
|
||||||
|
mode = WordMode::Boundary;
|
||||||
|
|
||||||
|
// Otherwise if current and previous are uppercase and next
|
||||||
|
// is lowercase, word boundary before
|
||||||
|
} else if mode == WordMode::Uppercase && c.is_uppercase() && next.is_lowercase() {
|
||||||
|
if !first_word {
|
||||||
|
boundary(f)?;
|
||||||
|
} else {
|
||||||
|
first_word = false;
|
||||||
|
}
|
||||||
|
with_word(&word[init..i], f)?;
|
||||||
|
init = i;
|
||||||
|
mode = WordMode::Boundary;
|
||||||
|
|
||||||
|
// Otherwise no word boundary, just update the mode
|
||||||
|
} else {
|
||||||
|
mode = next_mode;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Collect trailing characters as a word
|
||||||
|
if !first_word {
|
||||||
|
boundary(f)?;
|
||||||
|
} else {
|
||||||
|
first_word = false;
|
||||||
|
}
|
||||||
|
with_word(&word[init..], f)?;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn lowercase(s: &str, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
let mut chars = s.chars().peekable();
|
||||||
|
while let Some(c) = chars.next() {
|
||||||
|
if c == 'Σ' && chars.peek().is_none() {
|
||||||
|
write!(f, "ς")?;
|
||||||
|
} else {
|
||||||
|
write!(f, "{}", c.to_lowercase())?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn uppercase(s: &str, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
for c in s.chars() {
|
||||||
|
write!(f, "{}", c.to_uppercase())?;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn capitalize(s: &str, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
let mut char_indices = s.char_indices();
|
||||||
|
if let Some((_, c)) = char_indices.next() {
|
||||||
|
write!(f, "{}", c.to_uppercase())?;
|
||||||
|
if let Some((i, _)) = char_indices.next() {
|
||||||
|
lowercase(&s[i..], f)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,88 @@
|
||||||
|
use core::fmt;
|
||||||
|
|
||||||
|
use alloc::{
|
||||||
|
borrow::ToOwned,
|
||||||
|
string::{String, ToString},
|
||||||
|
};
|
||||||
|
|
||||||
|
use crate::{capitalize, lowercase, transform};
|
||||||
|
|
||||||
|
/// This trait defines a lower camel case conversion.
|
||||||
|
///
|
||||||
|
/// In lowerCamelCase, word boundaries are indicated by capital letters,
|
||||||
|
/// excepting the first word.
|
||||||
|
///
|
||||||
|
/// ## Example:
|
||||||
|
///
|
||||||
|
/// ```rust
|
||||||
|
/// use heck::ToLowerCamelCase;
|
||||||
|
///
|
||||||
|
/// let sentence = "It is we who built these palaces and cities.";
|
||||||
|
/// assert_eq!(sentence.to_lower_camel_case(), "itIsWeWhoBuiltThesePalacesAndCities");
|
||||||
|
/// ```
|
||||||
|
pub trait ToLowerCamelCase: ToOwned {
|
||||||
|
/// Convert this type to lower camel case.
|
||||||
|
fn to_lower_camel_case(&self) -> Self::Owned;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ToLowerCamelCase for str {
|
||||||
|
fn to_lower_camel_case(&self) -> String {
|
||||||
|
AsLowerCamelCase(self).to_string()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// This wrapper performs a lower camel case conversion in [`fmt::Display`].
|
||||||
|
///
|
||||||
|
/// ## Example:
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// use heck::AsLowerCamelCase;
|
||||||
|
///
|
||||||
|
/// let sentence = "It is we who built these palaces and cities.";
|
||||||
|
/// assert_eq!(format!("{}", AsLowerCamelCase(sentence)), "itIsWeWhoBuiltThesePalacesAndCities");
|
||||||
|
/// ```
|
||||||
|
pub struct AsLowerCamelCase<T: AsRef<str>>(pub T);
|
||||||
|
|
||||||
|
impl<T: AsRef<str>> fmt::Display for AsLowerCamelCase<T> {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
let mut first = true;
|
||||||
|
transform(
|
||||||
|
self.0.as_ref(),
|
||||||
|
|s, f| {
|
||||||
|
if first {
|
||||||
|
first = false;
|
||||||
|
lowercase(s, f)
|
||||||
|
} else {
|
||||||
|
capitalize(s, f)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|_| Ok(()),
|
||||||
|
f,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::ToLowerCamelCase;
|
||||||
|
|
||||||
|
macro_rules! t {
|
||||||
|
($t:ident : $s1:expr => $s2:expr) => {
|
||||||
|
#[test]
|
||||||
|
fn $t() {
|
||||||
|
assert_eq!($s1.to_lower_camel_case(), $s2)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
t!(test1: "CamelCase" => "camelCase");
|
||||||
|
t!(test2: "This is Human case." => "thisIsHumanCase");
|
||||||
|
t!(test3: "MixedUP CamelCase, with some Spaces" => "mixedUpCamelCaseWithSomeSpaces");
|
||||||
|
t!(test4: "mixed_up_ snake_case, with some _spaces" => "mixedUpSnakeCaseWithSomeSpaces");
|
||||||
|
t!(test5: "kebab-case" => "kebabCase");
|
||||||
|
t!(test6: "SHOUTY_SNAKE_CASE" => "shoutySnakeCase");
|
||||||
|
t!(test7: "snake_case" => "snakeCase");
|
||||||
|
t!(test8: "this-contains_ ALLKinds OfWord_Boundaries" => "thisContainsAllKindsOfWordBoundaries");
|
||||||
|
t!(test9: "XΣXΣ baffle" => "xσxςBaffle");
|
||||||
|
t!(test10: "XMLHttpRequest" => "xmlHttpRequest");
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,73 @@
|
||||||
|
use core::fmt;
|
||||||
|
|
||||||
|
use alloc::{borrow::ToOwned, string::ToString};
|
||||||
|
|
||||||
|
use crate::{transform, uppercase};
|
||||||
|
|
||||||
|
/// This trait defines a shouty kebab case conversion.
|
||||||
|
///
|
||||||
|
/// In SHOUTY-KEBAB-CASE, word boundaries are indicated by hyphens and all
|
||||||
|
/// words are in uppercase.
|
||||||
|
///
|
||||||
|
/// ## Example:
|
||||||
|
///
|
||||||
|
/// ```rust
|
||||||
|
/// use heck::ToShoutyKebabCase;
|
||||||
|
///
|
||||||
|
/// let sentence = "We are going to inherit the earth.";
|
||||||
|
/// assert_eq!(sentence.to_shouty_kebab_case(), "WE-ARE-GOING-TO-INHERIT-THE-EARTH");
|
||||||
|
/// ```
|
||||||
|
pub trait ToShoutyKebabCase: ToOwned {
|
||||||
|
/// Convert this type to shouty kebab case.
|
||||||
|
fn to_shouty_kebab_case(&self) -> Self::Owned;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ToShoutyKebabCase for str {
|
||||||
|
fn to_shouty_kebab_case(&self) -> Self::Owned {
|
||||||
|
AsShoutyKebabCase(self).to_string()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// This wrapper performs a kebab case conversion in [`fmt::Display`].
|
||||||
|
///
|
||||||
|
/// ## Example:
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// use heck::AsShoutyKebabCase;
|
||||||
|
///
|
||||||
|
/// let sentence = "We are going to inherit the earth.";
|
||||||
|
/// assert_eq!(format!("{}", AsShoutyKebabCase(sentence)), "WE-ARE-GOING-TO-INHERIT-THE-EARTH");
|
||||||
|
/// ```
|
||||||
|
pub struct AsShoutyKebabCase<T: AsRef<str>>(pub T);
|
||||||
|
|
||||||
|
impl<T: AsRef<str>> fmt::Display for AsShoutyKebabCase<T> {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
transform(self.0.as_ref(), uppercase, |f| write!(f, "-"), f)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::ToShoutyKebabCase;
|
||||||
|
|
||||||
|
macro_rules! t {
|
||||||
|
($t:ident : $s1:expr => $s2:expr) => {
|
||||||
|
#[test]
|
||||||
|
fn $t() {
|
||||||
|
assert_eq!($s1.to_shouty_kebab_case(), $s2)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
t!(test1: "CamelCase" => "CAMEL-CASE");
|
||||||
|
t!(test2: "This is Human case." => "THIS-IS-HUMAN-CASE");
|
||||||
|
t!(test3: "MixedUP CamelCase, with some Spaces" => "MIXED-UP-CAMEL-CASE-WITH-SOME-SPACES");
|
||||||
|
t!(test4: "mixed_up_ snake_case with some _spaces" => "MIXED-UP-SNAKE-CASE-WITH-SOME-SPACES");
|
||||||
|
t!(test5: "kebab-case" => "KEBAB-CASE");
|
||||||
|
t!(test6: "SHOUTY_SNAKE_CASE" => "SHOUTY-SNAKE-CASE");
|
||||||
|
t!(test7: "snake_case" => "SNAKE-CASE");
|
||||||
|
t!(test8: "this-contains_ ALLKinds OfWord_Boundaries" => "THIS-CONTAINS-ALL-KINDS-OF-WORD-BOUNDARIES");
|
||||||
|
t!(test9: "XΣXΣ baffle" => "XΣXΣ-BAFFLE");
|
||||||
|
t!(test10: "XMLHttpRequest" => "XML-HTTP-REQUEST");
|
||||||
|
t!(test11: "SHOUTY-KEBAB-CASE" => "SHOUTY-KEBAB-CASE");
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,86 @@
|
||||||
|
use core::fmt;
|
||||||
|
|
||||||
|
use alloc::{borrow::ToOwned, string::ToString};
|
||||||
|
|
||||||
|
use crate::{transform, uppercase};
|
||||||
|
|
||||||
|
/// This trait defines a shouty snake case conversion.
|
||||||
|
///
|
||||||
|
/// In SHOUTY_SNAKE_CASE, word boundaries are indicated by underscores and all
|
||||||
|
/// words are in uppercase.
|
||||||
|
///
|
||||||
|
/// ## Example:
|
||||||
|
///
|
||||||
|
/// ```rust
|
||||||
|
/// use heck::ToShoutySnakeCase;
|
||||||
|
///
|
||||||
|
/// let sentence = "That world is growing in this minute.";
|
||||||
|
/// assert_eq!(sentence.to_shouty_snake_case(), "THAT_WORLD_IS_GROWING_IN_THIS_MINUTE");
|
||||||
|
/// ```
|
||||||
|
pub trait ToShoutySnakeCase: ToOwned {
|
||||||
|
/// Convert this type to shouty snake case.
|
||||||
|
fn to_shouty_snake_case(&self) -> Self::Owned;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Oh heck, `ToShoutySnekCase` is an alias for [`ToShoutySnakeCase`]. See
|
||||||
|
/// ToShoutySnakeCase for more documentation.
|
||||||
|
pub trait ToShoutySnekCase: ToOwned {
|
||||||
|
/// CONVERT THIS TYPE TO SNEK CASE.
|
||||||
|
#[allow(non_snake_case)]
|
||||||
|
fn TO_SHOUTY_SNEK_CASE(&self) -> Self::Owned;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: ?Sized + ToShoutySnakeCase> ToShoutySnekCase for T {
|
||||||
|
fn TO_SHOUTY_SNEK_CASE(&self) -> Self::Owned {
|
||||||
|
self.to_shouty_snake_case()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ToShoutySnakeCase for str {
|
||||||
|
fn to_shouty_snake_case(&self) -> Self::Owned {
|
||||||
|
AsShoutySnakeCase(self).to_string()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// This wrapper performs a shouty snake case conversion in [`fmt::Display`].
|
||||||
|
///
|
||||||
|
/// ## Example:
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// use heck::AsShoutySnakeCase;
|
||||||
|
///
|
||||||
|
/// let sentence = "That world is growing in this minute.";
|
||||||
|
/// assert_eq!(format!("{}", AsShoutySnakeCase(sentence)), "THAT_WORLD_IS_GROWING_IN_THIS_MINUTE");
|
||||||
|
/// ```
|
||||||
|
pub struct AsShoutySnakeCase<T: AsRef<str>>(pub T);
|
||||||
|
|
||||||
|
impl<T: AsRef<str>> fmt::Display for AsShoutySnakeCase<T> {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
transform(self.0.as_ref(), uppercase, |f| write!(f, "_"), f)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::ToShoutySnakeCase;
|
||||||
|
|
||||||
|
macro_rules! t {
|
||||||
|
($t:ident : $s1:expr => $s2:expr) => {
|
||||||
|
#[test]
|
||||||
|
fn $t() {
|
||||||
|
assert_eq!($s1.to_shouty_snake_case(), $s2)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
t!(test1: "CamelCase" => "CAMEL_CASE");
|
||||||
|
t!(test2: "This is Human case." => "THIS_IS_HUMAN_CASE");
|
||||||
|
t!(test3: "MixedUP CamelCase, with some Spaces" => "MIXED_UP_CAMEL_CASE_WITH_SOME_SPACES");
|
||||||
|
t!(test4: "mixed_up_snake_case with some _spaces" => "MIXED_UP_SNAKE_CASE_WITH_SOME_SPACES");
|
||||||
|
t!(test5: "kebab-case" => "KEBAB_CASE");
|
||||||
|
t!(test6: "SHOUTY_SNAKE_CASE" => "SHOUTY_SNAKE_CASE");
|
||||||
|
t!(test7: "snake_case" => "SNAKE_CASE");
|
||||||
|
t!(test8: "this-contains_ ALLKinds OfWord_Boundaries" => "THIS_CONTAINS_ALL_KINDS_OF_WORD_BOUNDARIES");
|
||||||
|
t!(test9: "XΣXΣ baffle" => "XΣXΣ_BAFFLE");
|
||||||
|
t!(test10: "XMLHttpRequest" => "XML_HTTP_REQUEST");
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,100 @@
|
||||||
|
use alloc::{
|
||||||
|
borrow::ToOwned,
|
||||||
|
fmt,
|
||||||
|
string::{String, ToString},
|
||||||
|
};
|
||||||
|
|
||||||
|
use crate::{lowercase, transform};
|
||||||
|
|
||||||
|
/// This trait defines a snake case conversion.
|
||||||
|
///
|
||||||
|
/// In snake_case, word boundaries are indicated by underscores.
|
||||||
|
///
|
||||||
|
/// ## Example:
|
||||||
|
///
|
||||||
|
/// ```rust
|
||||||
|
/// use heck::ToSnakeCase;
|
||||||
|
///
|
||||||
|
/// let sentence = "We carry a new world here, in our hearts.";
|
||||||
|
/// assert_eq!(sentence.to_snake_case(), "we_carry_a_new_world_here_in_our_hearts");
|
||||||
|
/// ```
|
||||||
|
pub trait ToSnakeCase: ToOwned {
|
||||||
|
/// Convert this type to snake case.
|
||||||
|
fn to_snake_case(&self) -> Self::Owned;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Oh heck, `SnekCase` is an alias for [`ToSnakeCase`]. See ToSnakeCase for
|
||||||
|
/// more documentation.
|
||||||
|
pub trait ToSnekCase: ToOwned {
|
||||||
|
/// Convert this type to snek case.
|
||||||
|
fn to_snek_case(&self) -> Self::Owned;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: ?Sized + ToSnakeCase> ToSnekCase for T {
|
||||||
|
fn to_snek_case(&self) -> Self::Owned {
|
||||||
|
self.to_snake_case()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ToSnakeCase for str {
|
||||||
|
fn to_snake_case(&self) -> String {
|
||||||
|
AsSnakeCase(self).to_string()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// This wrapper performs a snake case conversion in [`fmt::Display`].
|
||||||
|
///
|
||||||
|
/// ## Example:
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// use heck::AsSnakeCase;
|
||||||
|
///
|
||||||
|
/// let sentence = "We carry a new world here, in our hearts.";
|
||||||
|
/// assert_eq!(format!("{}", AsSnakeCase(sentence)), "we_carry_a_new_world_here_in_our_hearts");
|
||||||
|
/// ```
|
||||||
|
pub struct AsSnakeCase<T: AsRef<str>>(pub T);
|
||||||
|
|
||||||
|
impl<T: AsRef<str>> fmt::Display for AsSnakeCase<T> {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
transform(self.0.as_ref(), lowercase, |f| write!(f, "_"), f)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::ToSnakeCase;
|
||||||
|
|
||||||
|
macro_rules! t {
|
||||||
|
($t:ident : $s1:expr => $s2:expr) => {
|
||||||
|
#[test]
|
||||||
|
fn $t() {
|
||||||
|
assert_eq!($s1.to_snake_case(), $s2)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
t!(test1: "CamelCase" => "camel_case");
|
||||||
|
t!(test2: "This is Human case." => "this_is_human_case");
|
||||||
|
t!(test3: "MixedUP CamelCase, with some Spaces" => "mixed_up_camel_case_with_some_spaces");
|
||||||
|
t!(test4: "mixed_up_ snake_case with some _spaces" => "mixed_up_snake_case_with_some_spaces");
|
||||||
|
t!(test5: "kebab-case" => "kebab_case");
|
||||||
|
t!(test6: "SHOUTY_SNAKE_CASE" => "shouty_snake_case");
|
||||||
|
t!(test7: "snake_case" => "snake_case");
|
||||||
|
t!(test8: "this-contains_ ALLKinds OfWord_Boundaries" => "this_contains_all_kinds_of_word_boundaries");
|
||||||
|
t!(test9: "XΣXΣ baffle" => "xσxς_baffle");
|
||||||
|
t!(test10: "XMLHttpRequest" => "xml_http_request");
|
||||||
|
t!(test11: "FIELD_NAME11" => "field_name11");
|
||||||
|
t!(test12: "99BOTTLES" => "99bottles");
|
||||||
|
t!(test13: "FieldNamE11" => "field_nam_e11");
|
||||||
|
t!(test14: "abc123def456" => "abc123def456");
|
||||||
|
t!(test16: "abc123DEF456" => "abc123_def456");
|
||||||
|
t!(test17: "abc123Def456" => "abc123_def456");
|
||||||
|
t!(test18: "abc123DEf456" => "abc123_d_ef456");
|
||||||
|
t!(test19: "ABC123def456" => "abc123def456");
|
||||||
|
t!(test20: "ABC123DEF456" => "abc123def456");
|
||||||
|
t!(test21: "ABC123Def456" => "abc123_def456");
|
||||||
|
t!(test22: "ABC123DEf456" => "abc123d_ef456");
|
||||||
|
t!(test23: "ABC123dEEf456FOO" => "abc123d_e_ef456_foo");
|
||||||
|
t!(test24: "abcDEF" => "abc_def");
|
||||||
|
t!(test25: "ABcDE" => "a_bc_de");
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,75 @@
|
||||||
|
use core::fmt;
|
||||||
|
|
||||||
|
use alloc::{
|
||||||
|
borrow::ToOwned,
|
||||||
|
string::{String, ToString},
|
||||||
|
};
|
||||||
|
|
||||||
|
use crate::{capitalize, transform};
|
||||||
|
|
||||||
|
/// This trait defines a title case conversion.
|
||||||
|
///
|
||||||
|
/// In Title Case, word boundaries are indicated by spaces, and every word is
|
||||||
|
/// capitalized.
|
||||||
|
///
|
||||||
|
/// ## Example:
|
||||||
|
///
|
||||||
|
/// ```rust
|
||||||
|
/// use heck::ToTitleCase;
|
||||||
|
///
|
||||||
|
/// let sentence = "We have always lived in slums and holes in the wall.";
|
||||||
|
/// assert_eq!(sentence.to_title_case(), "We Have Always Lived In Slums And Holes In The Wall");
|
||||||
|
/// ```
|
||||||
|
pub trait ToTitleCase: ToOwned {
|
||||||
|
/// Convert this type to title case.
|
||||||
|
fn to_title_case(&self) -> Self::Owned;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ToTitleCase for str {
|
||||||
|
fn to_title_case(&self) -> String {
|
||||||
|
AsTitleCase(self).to_string()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// This wrapper performs a title case conversion in [`fmt::Display`].
|
||||||
|
///
|
||||||
|
/// ## Example:
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// use heck::AsTitleCase;
|
||||||
|
///
|
||||||
|
/// let sentence = "We have always lived in slums and holes in the wall.";
|
||||||
|
/// assert_eq!(format!("{}", AsTitleCase(sentence)), "We Have Always Lived In Slums And Holes In The Wall");
|
||||||
|
/// ```
|
||||||
|
pub struct AsTitleCase<T: AsRef<str>>(pub T);
|
||||||
|
|
||||||
|
impl<T: AsRef<str>> fmt::Display for AsTitleCase<T> {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
transform(self.0.as_ref(), capitalize, |f| write!(f, " "), f)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::ToTitleCase;
|
||||||
|
|
||||||
|
macro_rules! t {
|
||||||
|
($t:ident : $s1:expr => $s2:expr) => {
|
||||||
|
#[test]
|
||||||
|
fn $t() {
|
||||||
|
assert_eq!($s1.to_title_case(), $s2)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
t!(test1: "CamelCase" => "Camel Case");
|
||||||
|
t!(test2: "This is Human case." => "This Is Human Case");
|
||||||
|
t!(test3: "MixedUP CamelCase, with some Spaces" => "Mixed Up Camel Case With Some Spaces");
|
||||||
|
t!(test4: "mixed_up_ snake_case, with some _spaces" => "Mixed Up Snake Case With Some Spaces");
|
||||||
|
t!(test5: "kebab-case" => "Kebab Case");
|
||||||
|
t!(test6: "SHOUTY_SNAKE_CASE" => "Shouty Snake Case");
|
||||||
|
t!(test7: "snake_case" => "Snake Case");
|
||||||
|
t!(test8: "this-contains_ ALLKinds OfWord_Boundaries" => "This Contains All Kinds Of Word Boundaries");
|
||||||
|
t!(test9: "XΣXΣ baffle" => "Xσxς Baffle");
|
||||||
|
t!(test10: "XMLHttpRequest" => "Xml Http Request");
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,87 @@
|
||||||
|
use core::fmt;
|
||||||
|
|
||||||
|
use alloc::{borrow::ToOwned, string::ToString};
|
||||||
|
|
||||||
|
use crate::{capitalize, transform};
|
||||||
|
|
||||||
|
/// This trait defines a train case conversion.
|
||||||
|
///
|
||||||
|
/// In Train-Case, word boundaries are indicated by hyphens and words start
|
||||||
|
/// with Capital Letters.
|
||||||
|
///
|
||||||
|
/// ## Example:
|
||||||
|
///
|
||||||
|
/// ```rust
|
||||||
|
/// use heck::ToTrainCase;
|
||||||
|
///
|
||||||
|
/// let sentence = "We are going to inherit the earth.";
|
||||||
|
/// assert_eq!(sentence.to_train_case(), "We-Are-Going-To-Inherit-The-Earth");
|
||||||
|
/// ```
|
||||||
|
pub trait ToTrainCase: ToOwned {
|
||||||
|
/// Convert this type to Train-Case.
|
||||||
|
fn to_train_case(&self) -> Self::Owned;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ToTrainCase for str {
|
||||||
|
fn to_train_case(&self) -> Self::Owned {
|
||||||
|
AsTrainCase(self).to_string()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// This wrapper performs a train case conversion in [`fmt::Display`].
|
||||||
|
///
|
||||||
|
/// ## Example:
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// use heck::AsTrainCase;
|
||||||
|
///
|
||||||
|
/// let sentence = "We are going to inherit the earth.";
|
||||||
|
/// assert_eq!(format!("{}", AsTrainCase(sentence)), "We-Are-Going-To-Inherit-The-Earth");
|
||||||
|
/// ```
|
||||||
|
pub struct AsTrainCase<T: AsRef<str>>(pub T);
|
||||||
|
|
||||||
|
impl<T: AsRef<str>> fmt::Display for AsTrainCase<T> {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
transform(self.0.as_ref(), capitalize, |f| write!(f, "-"), f)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::ToTrainCase;
|
||||||
|
|
||||||
|
macro_rules! t {
|
||||||
|
($t:ident : $s1:expr => $s2:expr) => {
|
||||||
|
#[test]
|
||||||
|
fn $t() {
|
||||||
|
assert_eq!($s1.to_train_case(), $s2)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
t!(test1: "CamelCase" => "Camel-Case");
|
||||||
|
t!(test2: "This is Human case." => "This-Is-Human-Case");
|
||||||
|
t!(test3: "MixedUP CamelCase, with some Spaces" => "Mixed-Up-Camel-Case-With-Some-Spaces");
|
||||||
|
t!(test4: "mixed_up_ snake_case with some _spaces" => "Mixed-Up-Snake-Case-With-Some-Spaces");
|
||||||
|
t!(test5: "kebab-case" => "Kebab-Case");
|
||||||
|
t!(test6: "SHOUTY_SNAKE_CASE" => "Shouty-Snake-Case");
|
||||||
|
t!(test7: "snake_case" => "Snake-Case");
|
||||||
|
t!(test8: "this-contains_ ALLKinds OfWord_Boundaries" => "This-Contains-All-Kinds-Of-Word-Boundaries");
|
||||||
|
#[cfg(feature = "unicode")]
|
||||||
|
t!(test9: "XΣXΣ baffle" => "Xσxς-Baffle");
|
||||||
|
t!(test10: "XMLHttpRequest" => "Xml-Http-Request");
|
||||||
|
t!(test11: "FIELD_NAME11" => "Field-Name11");
|
||||||
|
t!(test12: "99BOTTLES" => "99bottles");
|
||||||
|
t!(test13: "FieldNamE11" => "Field-Nam-E11");
|
||||||
|
t!(test14: "abc123def456" => "Abc123def456");
|
||||||
|
t!(test16: "abc123DEF456" => "Abc123-Def456");
|
||||||
|
t!(test17: "abc123Def456" => "Abc123-Def456");
|
||||||
|
t!(test18: "abc123DEf456" => "Abc123-D-Ef456");
|
||||||
|
t!(test19: "ABC123def456" => "Abc123def456");
|
||||||
|
t!(test20: "ABC123DEF456" => "Abc123def456");
|
||||||
|
t!(test21: "ABC123Def456" => "Abc123-Def456");
|
||||||
|
t!(test22: "ABC123DEf456" => "Abc123d-Ef456");
|
||||||
|
t!(test23: "ABC123dEEf456FOO" => "Abc123d-E-Ef456-Foo");
|
||||||
|
t!(test24: "abcDEF" => "Abc-Def");
|
||||||
|
t!(test25: "ABcDE" => "A-Bc-De");
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,88 @@
|
||||||
|
use core::fmt;
|
||||||
|
|
||||||
|
use alloc::{
|
||||||
|
borrow::ToOwned,
|
||||||
|
string::{String, ToString},
|
||||||
|
};
|
||||||
|
|
||||||
|
use crate::{capitalize, transform};
|
||||||
|
|
||||||
|
/// This trait defines an upper camel case conversion.
|
||||||
|
///
|
||||||
|
/// In UpperCamelCase, word boundaries are indicated by capital letters,
|
||||||
|
/// including the first word.
|
||||||
|
///
|
||||||
|
/// ## Example:
|
||||||
|
///
|
||||||
|
/// ```rust
|
||||||
|
/// use heck::ToUpperCamelCase;
|
||||||
|
///
|
||||||
|
/// let sentence = "We are not in the least afraid of ruins.";
|
||||||
|
/// assert_eq!(sentence.to_upper_camel_case(), "WeAreNotInTheLeastAfraidOfRuins");
|
||||||
|
/// ```
|
||||||
|
pub trait ToUpperCamelCase: ToOwned {
|
||||||
|
/// Convert this type to upper camel case.
|
||||||
|
fn to_upper_camel_case(&self) -> Self::Owned;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ToUpperCamelCase for str {
|
||||||
|
fn to_upper_camel_case(&self) -> String {
|
||||||
|
AsUpperCamelCase(self).to_string()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// `ToPascalCase` is an alias for [`ToUpperCamelCase`]. See ToUpperCamelCase for more
|
||||||
|
/// documentation.
|
||||||
|
pub trait ToPascalCase: ToOwned {
|
||||||
|
/// Convert this type to upper camel case.
|
||||||
|
fn to_pascal_case(&self) -> Self::Owned;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: ?Sized + ToUpperCamelCase> ToPascalCase for T {
|
||||||
|
fn to_pascal_case(&self) -> Self::Owned {
|
||||||
|
self.to_upper_camel_case()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// This wrapper performs a upper camel case conversion in [`fmt::Display`].
|
||||||
|
///
|
||||||
|
/// ## Example:
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// use heck::AsUpperCamelCase;
|
||||||
|
///
|
||||||
|
/// let sentence = "We are not in the least afraid of ruins.";
|
||||||
|
/// assert_eq!(format!("{}", AsUpperCamelCase(sentence)), "WeAreNotInTheLeastAfraidOfRuins");
|
||||||
|
/// ```
|
||||||
|
pub struct AsUpperCamelCase<T: AsRef<str>>(pub T);
|
||||||
|
|
||||||
|
impl<T: AsRef<str>> fmt::Display for AsUpperCamelCase<T> {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
transform(self.0.as_ref(), capitalize, |_| Ok(()), f)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::ToUpperCamelCase;
|
||||||
|
|
||||||
|
macro_rules! t {
|
||||||
|
($t:ident : $s1:expr => $s2:expr) => {
|
||||||
|
#[test]
|
||||||
|
fn $t() {
|
||||||
|
assert_eq!($s1.to_upper_camel_case(), $s2)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
t!(test1: "CamelCase" => "CamelCase");
|
||||||
|
t!(test2: "This is Human case." => "ThisIsHumanCase");
|
||||||
|
t!(test3: "MixedUP_CamelCase, with some Spaces" => "MixedUpCamelCaseWithSomeSpaces");
|
||||||
|
t!(test4: "mixed_up_ snake_case, with some _spaces" => "MixedUpSnakeCaseWithSomeSpaces");
|
||||||
|
t!(test5: "kebab-case" => "KebabCase");
|
||||||
|
t!(test6: "SHOUTY_SNAKE_CASE" => "ShoutySnakeCase");
|
||||||
|
t!(test7: "snake_case" => "SnakeCase");
|
||||||
|
t!(test8: "this-contains_ ALLKinds OfWord_Boundaries" => "ThisContainsAllKindsOfWordBoundaries");
|
||||||
|
t!(test9: "XΣXΣ baffle" => "XσxςBaffle");
|
||||||
|
t!(test10: "XMLHttpRequest" => "XmlHttpRequest");
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
{"files":{".cargo_vcs_info.json":"e0165305f3b22a9ab4217a121f85379aa56c2675caa7afedc0a7468fc187600b",".github/FUNDING.yml":"b017158736b3c9751a2d21edfce7fe61c8954e2fced8da8dd3013c2f3e295bd9",".github/workflows/ci.yml":"89c4f60223daf03217ea7c1e8879135b11d2554bd1e57dd9eff5c02f1adc7909","Cargo.lock":"1cd64090b8e883963bb08d91e6968cc1e83ffdba4f4b2f47651ce9d351a8a947","Cargo.toml":"894c215e4e7e973b556b0e9627bf9b6a719a043fac9b5af9838660816392a09f","Cargo.toml.orig":"44ca1ae5d9b48743305b57f3367051289512037e7836b8b3693b68d48dec0483","LICENSE-APACHE":"62c7a1e35f56406896d7aa7ca52d0cc0d272ac022b5d2796e7d6905db8a3636a","LICENSE-MIT":"23f18e03dc49df91622fe2a76176497404e46ced8a715d9d2b67a7446571cca3","README.md":"1305bd79675db0194915d9bc91bd0b3cf9487bc1126e05bf46b48ab43edce44b","benches/bench.rs":"29a0bdb973848007d681e571c57487e21e1bfb7aed5980c2190dba354498b154","src/lib.rs":"e962338e1886873aa7c3399ec89aa5378ccbfed712b9690f043628079390a34f","src/u128_ext.rs":"498cc94f13805e551248fd82f47cc318f51d953a5002a9f8698858cd12fbae3c","tests/test.rs":"b22f8a8ed89edcbb4140b74f5edd7f2adf3cb0e363990dd6010cd6ebe0dc36b7"},"package":"8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682"}
|
||||||
|
|
@ -0,0 +1,6 @@
|
||||||
|
{
|
||||||
|
"git": {
|
||||||
|
"sha1": "af77385d0daf4d0e949e81f2588be2e44f69f086"
|
||||||
|
},
|
||||||
|
"path_in_vcs": ""
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
github: dtolnay
|
||||||
|
|
@ -0,0 +1,126 @@
|
||||||
|
name: CI
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
pull_request:
|
||||||
|
workflow_dispatch:
|
||||||
|
schedule: [cron: "40 1 * * *"]
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
|
|
||||||
|
env:
|
||||||
|
RUSTFLAGS: -Dwarnings
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
pre_ci:
|
||||||
|
uses: dtolnay/.github/.github/workflows/pre_ci.yml@master
|
||||||
|
|
||||||
|
test:
|
||||||
|
name: Rust ${{matrix.rust}}
|
||||||
|
needs: pre_ci
|
||||||
|
if: needs.pre_ci.outputs.continue
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
strategy:
|
||||||
|
fail-fast: false
|
||||||
|
matrix:
|
||||||
|
rust: [nightly, beta, stable, 1.86.0]
|
||||||
|
timeout-minutes: 45
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v6
|
||||||
|
- uses: dtolnay/rust-toolchain@master
|
||||||
|
with:
|
||||||
|
toolchain: ${{matrix.rust}}
|
||||||
|
- name: Enable type layout randomization
|
||||||
|
run: echo RUSTFLAGS=${RUSTFLAGS}\ -Zrandomize-layout >> $GITHUB_ENV
|
||||||
|
if: matrix.rust == 'nightly'
|
||||||
|
- run: cargo build
|
||||||
|
- run: cargo test
|
||||||
|
- run: cargo test --release
|
||||||
|
- run: cargo build --no-default-features
|
||||||
|
- run: cargo test --tests --no-default-features
|
||||||
|
- run: cargo test --tests --no-default-features --release
|
||||||
|
- run: cargo build --tests --features no-panic --release
|
||||||
|
if: matrix.rust == 'nightly'
|
||||||
|
- run: cargo bench --no-run
|
||||||
|
if: matrix.rust == 'nightly'
|
||||||
|
- uses: actions/upload-artifact@v6
|
||||||
|
if: matrix.rust == 'nightly' && always()
|
||||||
|
with:
|
||||||
|
name: Cargo.lock
|
||||||
|
path: Cargo.lock
|
||||||
|
continue-on-error: true
|
||||||
|
|
||||||
|
msrv:
|
||||||
|
name: Rust 1.68.0
|
||||||
|
needs: pre_ci
|
||||||
|
if: needs.pre_ci.outputs.continue
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
timeout-minutes: 45
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v6
|
||||||
|
- uses: dtolnay/rust-toolchain@1.68
|
||||||
|
- run: cargo build
|
||||||
|
- run: cargo build --no-default-features
|
||||||
|
|
||||||
|
doc:
|
||||||
|
name: Documentation
|
||||||
|
needs: pre_ci
|
||||||
|
if: needs.pre_ci.outputs.continue
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
timeout-minutes: 45
|
||||||
|
env:
|
||||||
|
RUSTDOCFLAGS: -Dwarnings
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v6
|
||||||
|
- uses: dtolnay/rust-toolchain@nightly
|
||||||
|
- uses: dtolnay/install@cargo-docs-rs
|
||||||
|
- run: cargo docs-rs
|
||||||
|
|
||||||
|
miri:
|
||||||
|
name: Miri
|
||||||
|
needs: pre_ci
|
||||||
|
if: needs.pre_ci.outputs.continue
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
timeout-minutes: 45
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v6
|
||||||
|
- uses: dtolnay/rust-toolchain@miri
|
||||||
|
- run: cargo miri setup
|
||||||
|
- run: cargo miri test
|
||||||
|
env:
|
||||||
|
MIRIFLAGS: -Zmiri-strict-provenance
|
||||||
|
|
||||||
|
clippy:
|
||||||
|
name: Clippy
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
if: github.event_name != 'pull_request'
|
||||||
|
timeout-minutes: 45
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v6
|
||||||
|
- uses: dtolnay/rust-toolchain@clippy
|
||||||
|
- run: cargo clippy --tests --benches -- -Dclippy::all -Dclippy::pedantic
|
||||||
|
|
||||||
|
fuzz:
|
||||||
|
name: Fuzz
|
||||||
|
needs: pre_ci
|
||||||
|
if: needs.pre_ci.outputs.continue
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
timeout-minutes: 45
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v6
|
||||||
|
- uses: dtolnay/rust-toolchain@nightly
|
||||||
|
- uses: dtolnay/install@cargo-fuzz
|
||||||
|
- run: cargo fuzz check
|
||||||
|
|
||||||
|
outdated:
|
||||||
|
name: Outdated
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
if: github.event_name != 'pull_request'
|
||||||
|
timeout-minutes: 45
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v6
|
||||||
|
- uses: dtolnay/rust-toolchain@stable
|
||||||
|
- uses: dtolnay/install@cargo-outdated
|
||||||
|
- run: cargo outdated --workspace --exit-code 1
|
||||||
|
- run: cargo outdated --manifest-path fuzz/Cargo.toml --exit-code 1
|
||||||
|
|
@ -0,0 +1,460 @@
|
||||||
|
# This file is automatically @generated by Cargo.
|
||||||
|
# It is not intended for manual editing.
|
||||||
|
version = 3
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "aho-corasick"
|
||||||
|
version = "1.1.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ddd31a130427c27518df266943a5308ed92d4b226cc639f5a8f1002816174301"
|
||||||
|
dependencies = [
|
||||||
|
"memchr",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "alloca"
|
||||||
|
version = "0.4.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e5a7d05ea6aea7e9e64d25b9156ba2fee3fdd659e34e41063cd2fc7cd020d7f4"
|
||||||
|
dependencies = [
|
||||||
|
"cc",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "anes"
|
||||||
|
version = "0.1.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "4b46cbb362ab8752921c97e041f5e366ee6297bd428a31275b9fcf1e380f7299"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "anstyle"
|
||||||
|
version = "1.0.14"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "940b3a0ca603d1eade50a4846a2afffd5ef57a9feac2c0e2ec2e14f9ead76000"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "autocfg"
|
||||||
|
version = "1.5.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "cast"
|
||||||
|
version = "0.3.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "cc"
|
||||||
|
version = "1.2.57"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "7a0dd1ca384932ff3641c8718a02769f1698e7563dc6974ffd03346116310423"
|
||||||
|
dependencies = [
|
||||||
|
"find-msvc-tools",
|
||||||
|
"shlex",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "cfg-if"
|
||||||
|
version = "1.0.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ciborium"
|
||||||
|
version = "0.2.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "42e69ffd6f0917f5c029256a24d0161db17cea3997d185db0d35926308770f0e"
|
||||||
|
dependencies = [
|
||||||
|
"ciborium-io",
|
||||||
|
"ciborium-ll",
|
||||||
|
"serde",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ciborium-io"
|
||||||
|
version = "0.2.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "05afea1e0a06c9be33d539b876f1ce3692f4afea2cb41f740e7743225ed1c757"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ciborium-ll"
|
||||||
|
version = "0.2.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "57663b653d948a338bfb3eeba9bb2fd5fcfaecb9e199e87e1eda4d9e8b240fd9"
|
||||||
|
dependencies = [
|
||||||
|
"ciborium-io",
|
||||||
|
"half",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "clap"
|
||||||
|
version = "4.6.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b193af5b67834b676abd72466a96c1024e6a6ad978a1f484bd90b85c94041351"
|
||||||
|
dependencies = [
|
||||||
|
"clap_builder",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "clap_builder"
|
||||||
|
version = "4.6.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "714a53001bf66416adb0e2ef5ac857140e7dc3a0c48fb28b2f10762fc4b5069f"
|
||||||
|
dependencies = [
|
||||||
|
"anstyle",
|
||||||
|
"clap_lex",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "clap_lex"
|
||||||
|
version = "1.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "c8d4a3bb8b1e0c1050499d1815f5ab16d04f0959b233085fb31653fbfc9d98f9"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "criterion"
|
||||||
|
version = "0.8.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "950046b2aa2492f9a536f5f4f9a3de7b9e2476e575e05bd6c333371add4d98f3"
|
||||||
|
dependencies = [
|
||||||
|
"alloca",
|
||||||
|
"anes",
|
||||||
|
"cast",
|
||||||
|
"ciborium",
|
||||||
|
"clap",
|
||||||
|
"criterion-plot",
|
||||||
|
"itertools",
|
||||||
|
"num-traits",
|
||||||
|
"oorandom",
|
||||||
|
"page_size",
|
||||||
|
"regex",
|
||||||
|
"serde",
|
||||||
|
"serde_json",
|
||||||
|
"tinytemplate",
|
||||||
|
"walkdir",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "criterion-plot"
|
||||||
|
version = "0.8.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d8d80a2f4f5b554395e47b5d8305bc3d27813bacb73493eb1001e8f76dae29ea"
|
||||||
|
dependencies = [
|
||||||
|
"cast",
|
||||||
|
"itertools",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "crunchy"
|
||||||
|
version = "0.2.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "460fbee9c2c2f33933d720630a6a0bac33ba7053db5344fac858d4b8952d77d5"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "either"
|
||||||
|
version = "1.15.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "find-msvc-tools"
|
||||||
|
version = "0.1.9"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "5baebc0774151f905a1a2cc41989300b1e6fbb29aff0ceffa1064fdd3088d582"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "half"
|
||||||
|
version = "2.7.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "6ea2d84b969582b4b1864a92dc5d27cd2b77b622a8d79306834f1be5ba20d84b"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if",
|
||||||
|
"crunchy",
|
||||||
|
"zerocopy",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "itertools"
|
||||||
|
version = "0.13.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186"
|
||||||
|
dependencies = [
|
||||||
|
"either",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "itoa"
|
||||||
|
version = "1.0.17"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "92ecc6618181def0457392ccd0ee51198e065e016d1d527a7ac1b6dc7c1f09d2"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "itoa"
|
||||||
|
version = "1.0.18"
|
||||||
|
dependencies = [
|
||||||
|
"criterion",
|
||||||
|
"no-panic",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "libc"
|
||||||
|
version = "0.2.183"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b5b646652bf6661599e1da8901b3b9522896f01e736bad5f723fe7a3a27f899d"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "memchr"
|
||||||
|
version = "2.8.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f8ca58f447f06ed17d5fc4043ce1b10dd205e060fb3ce5b979b8ed8e59ff3f79"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "no-panic"
|
||||||
|
version = "0.1.36"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f967505aabc8af5752d098c34146544a43684817cdba8f9725b292530cabbf53"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "num-traits"
|
||||||
|
version = "0.2.19"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841"
|
||||||
|
dependencies = [
|
||||||
|
"autocfg",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "oorandom"
|
||||||
|
version = "11.1.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d6790f58c7ff633d8771f42965289203411a5e5c68388703c06e14f24770b41e"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "page_size"
|
||||||
|
version = "0.6.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "30d5b2194ed13191c1999ae0704b7839fb18384fa22e49b57eeaa97d79ce40da"
|
||||||
|
dependencies = [
|
||||||
|
"libc",
|
||||||
|
"winapi",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "proc-macro2"
|
||||||
|
version = "1.0.106"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934"
|
||||||
|
dependencies = [
|
||||||
|
"unicode-ident",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "quote"
|
||||||
|
version = "1.0.45"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "41f2619966050689382d2b44f664f4bc593e129785a36d6ee376ddf37259b924"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "regex"
|
||||||
|
version = "1.12.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e10754a14b9137dd7b1e3e5b0493cc9171fdd105e0ab477f51b72e7f3ac0e276"
|
||||||
|
dependencies = [
|
||||||
|
"aho-corasick",
|
||||||
|
"memchr",
|
||||||
|
"regex-automata",
|
||||||
|
"regex-syntax",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "regex-automata"
|
||||||
|
version = "0.4.14"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "6e1dd4122fc1595e8162618945476892eefca7b88c52820e74af6262213cae8f"
|
||||||
|
dependencies = [
|
||||||
|
"aho-corasick",
|
||||||
|
"memchr",
|
||||||
|
"regex-syntax",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "regex-syntax"
|
||||||
|
version = "0.8.10"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "dc897dd8d9e8bd1ed8cdad82b5966c3e0ecae09fb1907d58efaa013543185d0a"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "same-file"
|
||||||
|
version = "1.0.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502"
|
||||||
|
dependencies = [
|
||||||
|
"winapi-util",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "serde"
|
||||||
|
version = "1.0.228"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e"
|
||||||
|
dependencies = [
|
||||||
|
"serde_core",
|
||||||
|
"serde_derive",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "serde_core"
|
||||||
|
version = "1.0.228"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad"
|
||||||
|
dependencies = [
|
||||||
|
"serde_derive",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "serde_derive"
|
||||||
|
version = "1.0.228"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "serde_json"
|
||||||
|
version = "1.0.149"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "83fc039473c5595ace860d8c4fafa220ff474b3fc6bfdb4293327f1a37e94d86"
|
||||||
|
dependencies = [
|
||||||
|
"itoa 1.0.17",
|
||||||
|
"memchr",
|
||||||
|
"serde",
|
||||||
|
"serde_core",
|
||||||
|
"zmij",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "shlex"
|
||||||
|
version = "1.3.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "syn"
|
||||||
|
version = "2.0.117"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e665b8803e7b1d2a727f4023456bbbbe74da67099c585258af0ad9c5013b9b99"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"unicode-ident",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tinytemplate"
|
||||||
|
version = "1.2.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "be4d6b5f19ff7664e8c98d03e2139cb510db9b0a60b55f8e8709b689d939b6bc"
|
||||||
|
dependencies = [
|
||||||
|
"serde",
|
||||||
|
"serde_json",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "unicode-ident"
|
||||||
|
version = "1.0.24"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "walkdir"
|
||||||
|
version = "2.5.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b"
|
||||||
|
dependencies = [
|
||||||
|
"same-file",
|
||||||
|
"winapi-util",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "winapi"
|
||||||
|
version = "0.3.9"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
|
||||||
|
dependencies = [
|
||||||
|
"winapi-i686-pc-windows-gnu",
|
||||||
|
"winapi-x86_64-pc-windows-gnu",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "winapi-i686-pc-windows-gnu"
|
||||||
|
version = "0.4.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "winapi-util"
|
||||||
|
version = "0.1.11"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22"
|
||||||
|
dependencies = [
|
||||||
|
"windows-sys",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "winapi-x86_64-pc-windows-gnu"
|
||||||
|
version = "0.4.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows-link"
|
||||||
|
version = "0.2.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows-sys"
|
||||||
|
version = "0.61.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc"
|
||||||
|
dependencies = [
|
||||||
|
"windows-link",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "zerocopy"
|
||||||
|
version = "0.8.47"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "efbb2a062be311f2ba113ce66f697a4dc589f85e78a4aea276200804cea0ed87"
|
||||||
|
dependencies = [
|
||||||
|
"zerocopy-derive",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "zerocopy-derive"
|
||||||
|
version = "0.8.47"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "0e8bc7269b54418e7aeeef514aa68f8690b8c0489a06b0136e5f57c4c5ccab89"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "zmij"
|
||||||
|
version = "1.0.21"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b8848ee67ecc8aedbaf3e4122217aff892639231befc6a1b58d29fff4c2cabaa"
|
||||||
|
|
@ -0,0 +1,66 @@
|
||||||
|
# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO
|
||||||
|
#
|
||||||
|
# When uploading crates to the registry Cargo will automatically
|
||||||
|
# "normalize" Cargo.toml files for maximal compatibility
|
||||||
|
# with all versions of Cargo and also rewrite `path` dependencies
|
||||||
|
# to registry (e.g., crates.io) dependencies.
|
||||||
|
#
|
||||||
|
# If you are reading this file be aware that the original Cargo.toml
|
||||||
|
# will likely look very different (and much more reasonable).
|
||||||
|
# See Cargo.toml.orig for the original contents.
|
||||||
|
|
||||||
|
[package]
|
||||||
|
edition = "2021"
|
||||||
|
rust-version = "1.68"
|
||||||
|
name = "itoa"
|
||||||
|
version = "1.0.18"
|
||||||
|
authors = ["David Tolnay <dtolnay@gmail.com>"]
|
||||||
|
build = false
|
||||||
|
exclude = ["*.png"]
|
||||||
|
autolib = false
|
||||||
|
autobins = false
|
||||||
|
autoexamples = false
|
||||||
|
autotests = false
|
||||||
|
autobenches = false
|
||||||
|
description = "Fast integer primitive to string conversion"
|
||||||
|
documentation = "https://docs.rs/itoa"
|
||||||
|
readme = "README.md"
|
||||||
|
keywords = ["integer"]
|
||||||
|
categories = [
|
||||||
|
"value-formatting",
|
||||||
|
"no-std",
|
||||||
|
"no-std::no-alloc",
|
||||||
|
]
|
||||||
|
license = "MIT OR Apache-2.0"
|
||||||
|
repository = "https://github.com/dtolnay/itoa"
|
||||||
|
|
||||||
|
[package.metadata.docs.rs]
|
||||||
|
targets = ["x86_64-unknown-linux-gnu"]
|
||||||
|
rustdoc-args = [
|
||||||
|
"--generate-link-to-definition",
|
||||||
|
"--generate-macro-expansion",
|
||||||
|
"--extern-html-root-url=core=https://doc.rust-lang.org",
|
||||||
|
"--extern-html-root-url=alloc=https://doc.rust-lang.org",
|
||||||
|
"--extern-html-root-url=std=https://doc.rust-lang.org",
|
||||||
|
]
|
||||||
|
|
||||||
|
[lib]
|
||||||
|
name = "itoa"
|
||||||
|
path = "src/lib.rs"
|
||||||
|
|
||||||
|
[[test]]
|
||||||
|
name = "test"
|
||||||
|
path = "tests/test.rs"
|
||||||
|
|
||||||
|
[[bench]]
|
||||||
|
name = "bench"
|
||||||
|
path = "benches/bench.rs"
|
||||||
|
harness = false
|
||||||
|
|
||||||
|
[dependencies.no-panic]
|
||||||
|
version = "0.1"
|
||||||
|
optional = true
|
||||||
|
|
||||||
|
[target."cfg(not(miri))".dev-dependencies.criterion]
|
||||||
|
version = "0.8"
|
||||||
|
default-features = false
|
||||||
|
|
@ -0,0 +1,33 @@
|
||||||
|
[package]
|
||||||
|
name = "itoa"
|
||||||
|
version = "1.0.18"
|
||||||
|
authors = ["David Tolnay <dtolnay@gmail.com>"]
|
||||||
|
categories = ["value-formatting", "no-std", "no-std::no-alloc"]
|
||||||
|
description = "Fast integer primitive to string conversion"
|
||||||
|
documentation = "https://docs.rs/itoa"
|
||||||
|
edition = "2021"
|
||||||
|
exclude = ["*.png"]
|
||||||
|
keywords = ["integer"]
|
||||||
|
license = "MIT OR Apache-2.0"
|
||||||
|
repository = "https://github.com/dtolnay/itoa"
|
||||||
|
rust-version = "1.68"
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
no-panic = { version = "0.1", optional = true }
|
||||||
|
|
||||||
|
[target.'cfg(not(miri))'.dev-dependencies]
|
||||||
|
criterion = { version = "0.8", default-features = false }
|
||||||
|
|
||||||
|
[[bench]]
|
||||||
|
name = "bench"
|
||||||
|
harness = false
|
||||||
|
|
||||||
|
[package.metadata.docs.rs]
|
||||||
|
targets = ["x86_64-unknown-linux-gnu"]
|
||||||
|
rustdoc-args = [
|
||||||
|
"--generate-link-to-definition",
|
||||||
|
"--generate-macro-expansion",
|
||||||
|
"--extern-html-root-url=core=https://doc.rust-lang.org",
|
||||||
|
"--extern-html-root-url=alloc=https://doc.rust-lang.org",
|
||||||
|
"--extern-html-root-url=std=https://doc.rust-lang.org",
|
||||||
|
]
|
||||||
|
|
@ -0,0 +1,176 @@
|
||||||
|
Apache License
|
||||||
|
Version 2.0, January 2004
|
||||||
|
http://www.apache.org/licenses/
|
||||||
|
|
||||||
|
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||||
|
|
||||||
|
1. Definitions.
|
||||||
|
|
||||||
|
"License" shall mean the terms and conditions for use, reproduction,
|
||||||
|
and distribution as defined by Sections 1 through 9 of this document.
|
||||||
|
|
||||||
|
"Licensor" shall mean the copyright owner or entity authorized by
|
||||||
|
the copyright owner that is granting the License.
|
||||||
|
|
||||||
|
"Legal Entity" shall mean the union of the acting entity and all
|
||||||
|
other entities that control, are controlled by, or are under common
|
||||||
|
control with that entity. For the purposes of this definition,
|
||||||
|
"control" means (i) the power, direct or indirect, to cause the
|
||||||
|
direction or management of such entity, whether by contract or
|
||||||
|
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||||
|
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||||
|
|
||||||
|
"You" (or "Your") shall mean an individual or Legal Entity
|
||||||
|
exercising permissions granted by this License.
|
||||||
|
|
||||||
|
"Source" form shall mean the preferred form for making modifications,
|
||||||
|
including but not limited to software source code, documentation
|
||||||
|
source, and configuration files.
|
||||||
|
|
||||||
|
"Object" form shall mean any form resulting from mechanical
|
||||||
|
transformation or translation of a Source form, including but
|
||||||
|
not limited to compiled object code, generated documentation,
|
||||||
|
and conversions to other media types.
|
||||||
|
|
||||||
|
"Work" shall mean the work of authorship, whether in Source or
|
||||||
|
Object form, made available under the License, as indicated by a
|
||||||
|
copyright notice that is included in or attached to the work
|
||||||
|
(an example is provided in the Appendix below).
|
||||||
|
|
||||||
|
"Derivative Works" shall mean any work, whether in Source or Object
|
||||||
|
form, that is based on (or derived from) the Work and for which the
|
||||||
|
editorial revisions, annotations, elaborations, or other modifications
|
||||||
|
represent, as a whole, an original work of authorship. For the purposes
|
||||||
|
of this License, Derivative Works shall not include works that remain
|
||||||
|
separable from, or merely link (or bind by name) to the interfaces of,
|
||||||
|
the Work and Derivative Works thereof.
|
||||||
|
|
||||||
|
"Contribution" shall mean any work of authorship, including
|
||||||
|
the original version of the Work and any modifications or additions
|
||||||
|
to that Work or Derivative Works thereof, that is intentionally
|
||||||
|
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||||
|
or by an individual or Legal Entity authorized to submit on behalf of
|
||||||
|
the copyright owner. For the purposes of this definition, "submitted"
|
||||||
|
means any form of electronic, verbal, or written communication sent
|
||||||
|
to the Licensor or its representatives, including but not limited to
|
||||||
|
communication on electronic mailing lists, source code control systems,
|
||||||
|
and issue tracking systems that are managed by, or on behalf of, the
|
||||||
|
Licensor for the purpose of discussing and improving the Work, but
|
||||||
|
excluding communication that is conspicuously marked or otherwise
|
||||||
|
designated in writing by the copyright owner as "Not a Contribution."
|
||||||
|
|
||||||
|
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||||
|
on behalf of whom a Contribution has been received by Licensor and
|
||||||
|
subsequently incorporated within the Work.
|
||||||
|
|
||||||
|
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||||
|
this License, each Contributor hereby grants to You a perpetual,
|
||||||
|
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||||
|
copyright license to reproduce, prepare Derivative Works of,
|
||||||
|
publicly display, publicly perform, sublicense, and distribute the
|
||||||
|
Work and such Derivative Works in Source or Object form.
|
||||||
|
|
||||||
|
3. Grant of Patent License. Subject to the terms and conditions of
|
||||||
|
this License, each Contributor hereby grants to You a perpetual,
|
||||||
|
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||||
|
(except as stated in this section) patent license to make, have made,
|
||||||
|
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||||
|
where such license applies only to those patent claims licensable
|
||||||
|
by such Contributor that are necessarily infringed by their
|
||||||
|
Contribution(s) alone or by combination of their Contribution(s)
|
||||||
|
with the Work to which such Contribution(s) was submitted. If You
|
||||||
|
institute patent litigation against any entity (including a
|
||||||
|
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||||
|
or a Contribution incorporated within the Work constitutes direct
|
||||||
|
or contributory patent infringement, then any patent licenses
|
||||||
|
granted to You under this License for that Work shall terminate
|
||||||
|
as of the date such litigation is filed.
|
||||||
|
|
||||||
|
4. Redistribution. You may reproduce and distribute copies of the
|
||||||
|
Work or Derivative Works thereof in any medium, with or without
|
||||||
|
modifications, and in Source or Object form, provided that You
|
||||||
|
meet the following conditions:
|
||||||
|
|
||||||
|
(a) You must give any other recipients of the Work or
|
||||||
|
Derivative Works a copy of this License; and
|
||||||
|
|
||||||
|
(b) You must cause any modified files to carry prominent notices
|
||||||
|
stating that You changed the files; and
|
||||||
|
|
||||||
|
(c) You must retain, in the Source form of any Derivative Works
|
||||||
|
that You distribute, all copyright, patent, trademark, and
|
||||||
|
attribution notices from the Source form of the Work,
|
||||||
|
excluding those notices that do not pertain to any part of
|
||||||
|
the Derivative Works; and
|
||||||
|
|
||||||
|
(d) If the Work includes a "NOTICE" text file as part of its
|
||||||
|
distribution, then any Derivative Works that You distribute must
|
||||||
|
include a readable copy of the attribution notices contained
|
||||||
|
within such NOTICE file, excluding those notices that do not
|
||||||
|
pertain to any part of the Derivative Works, in at least one
|
||||||
|
of the following places: within a NOTICE text file distributed
|
||||||
|
as part of the Derivative Works; within the Source form or
|
||||||
|
documentation, if provided along with the Derivative Works; or,
|
||||||
|
within a display generated by the Derivative Works, if and
|
||||||
|
wherever such third-party notices normally appear. The contents
|
||||||
|
of the NOTICE file are for informational purposes only and
|
||||||
|
do not modify the License. You may add Your own attribution
|
||||||
|
notices within Derivative Works that You distribute, alongside
|
||||||
|
or as an addendum to the NOTICE text from the Work, provided
|
||||||
|
that such additional attribution notices cannot be construed
|
||||||
|
as modifying the License.
|
||||||
|
|
||||||
|
You may add Your own copyright statement to Your modifications and
|
||||||
|
may provide additional or different license terms and conditions
|
||||||
|
for use, reproduction, or distribution of Your modifications, or
|
||||||
|
for any such Derivative Works as a whole, provided Your use,
|
||||||
|
reproduction, and distribution of the Work otherwise complies with
|
||||||
|
the conditions stated in this License.
|
||||||
|
|
||||||
|
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||||
|
any Contribution intentionally submitted for inclusion in the Work
|
||||||
|
by You to the Licensor shall be under the terms and conditions of
|
||||||
|
this License, without any additional terms or conditions.
|
||||||
|
Notwithstanding the above, nothing herein shall supersede or modify
|
||||||
|
the terms of any separate license agreement you may have executed
|
||||||
|
with Licensor regarding such Contributions.
|
||||||
|
|
||||||
|
6. Trademarks. This License does not grant permission to use the trade
|
||||||
|
names, trademarks, service marks, or product names of the Licensor,
|
||||||
|
except as required for reasonable and customary use in describing the
|
||||||
|
origin of the Work and reproducing the content of the NOTICE file.
|
||||||
|
|
||||||
|
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||||
|
agreed to in writing, Licensor provides the Work (and each
|
||||||
|
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||||
|
implied, including, without limitation, any warranties or conditions
|
||||||
|
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||||
|
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||||
|
appropriateness of using or redistributing the Work and assume any
|
||||||
|
risks associated with Your exercise of permissions under this License.
|
||||||
|
|
||||||
|
8. Limitation of Liability. In no event and under no legal theory,
|
||||||
|
whether in tort (including negligence), contract, or otherwise,
|
||||||
|
unless required by applicable law (such as deliberate and grossly
|
||||||
|
negligent acts) or agreed to in writing, shall any Contributor be
|
||||||
|
liable to You for damages, including any direct, indirect, special,
|
||||||
|
incidental, or consequential damages of any character arising as a
|
||||||
|
result of this License or out of the use or inability to use the
|
||||||
|
Work (including but not limited to damages for loss of goodwill,
|
||||||
|
work stoppage, computer failure or malfunction, or any and all
|
||||||
|
other commercial damages or losses), even if such Contributor
|
||||||
|
has been advised of the possibility of such damages.
|
||||||
|
|
||||||
|
9. Accepting Warranty or Additional Liability. While redistributing
|
||||||
|
the Work or Derivative Works thereof, You may choose to offer,
|
||||||
|
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||||
|
or other liability obligations and/or rights consistent with this
|
||||||
|
License. However, in accepting such obligations, You may act only
|
||||||
|
on Your own behalf and on Your sole responsibility, not on behalf
|
||||||
|
of any other Contributor, and only if You agree to indemnify,
|
||||||
|
defend, and hold each Contributor harmless for any liability
|
||||||
|
incurred by, or claims asserted against, such Contributor by reason
|
||||||
|
of your accepting any such warranty or additional liability.
|
||||||
|
|
||||||
|
END OF TERMS AND CONDITIONS
|
||||||
|
|
@ -0,0 +1,23 @@
|
||||||
|
Permission is hereby granted, free of charge, to any
|
||||||
|
person obtaining a copy of this software and associated
|
||||||
|
documentation files (the "Software"), to deal in the
|
||||||
|
Software without restriction, including without
|
||||||
|
limitation the rights to use, copy, modify, merge,
|
||||||
|
publish, distribute, sublicense, and/or sell copies of
|
||||||
|
the Software, and to permit persons to whom the Software
|
||||||
|
is furnished to do so, subject to the following
|
||||||
|
conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice
|
||||||
|
shall be included in all copies or substantial portions
|
||||||
|
of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
|
||||||
|
ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
|
||||||
|
TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
|
||||||
|
PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
|
||||||
|
SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||||
|
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||||
|
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
|
||||||
|
IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||||
|
DEALINGS IN THE SOFTWARE.
|
||||||
|
|
@ -0,0 +1,65 @@
|
||||||
|
itoa
|
||||||
|
====
|
||||||
|
|
||||||
|
[<img alt="github" src="https://img.shields.io/badge/github-dtolnay/itoa-8da0cb?style=for-the-badge&labelColor=555555&logo=github" height="20">](https://github.com/dtolnay/itoa)
|
||||||
|
[<img alt="crates.io" src="https://img.shields.io/crates/v/itoa.svg?style=for-the-badge&color=fc8d62&logo=rust" height="20">](https://crates.io/crates/itoa)
|
||||||
|
[<img alt="docs.rs" src="https://img.shields.io/badge/docs.rs-itoa-66c2a5?style=for-the-badge&labelColor=555555&logo=docs.rs" height="20">](https://docs.rs/itoa)
|
||||||
|
[<img alt="build status" src="https://img.shields.io/github/actions/workflow/status/dtolnay/itoa/ci.yml?branch=master&style=for-the-badge" height="20">](https://github.com/dtolnay/itoa/actions?query=branch%3Amaster)
|
||||||
|
|
||||||
|
This crate provides a fast conversion of integer primitives to decimal strings.
|
||||||
|
The implementation comes straight from [libcore] but avoids the performance
|
||||||
|
penalty of going through [`core::fmt::Formatter`].
|
||||||
|
|
||||||
|
See also [`zmij`] for printing floating point primitives.
|
||||||
|
|
||||||
|
[libcore]: https://github.com/rust-lang/rust/blob/1.92.0/library/core/src/fmt/num.rs#L190-L253
|
||||||
|
[`core::fmt::Formatter`]: https://doc.rust-lang.org/std/fmt/struct.Formatter.html
|
||||||
|
[`zmij`]: https://github.com/dtolnay/zmij
|
||||||
|
|
||||||
|
```toml
|
||||||
|
[dependencies]
|
||||||
|
itoa = "1.0"
|
||||||
|
```
|
||||||
|
|
||||||
|
<br>
|
||||||
|
|
||||||
|
## Example
|
||||||
|
|
||||||
|
```rust
|
||||||
|
fn main() {
|
||||||
|
let mut buffer = itoa::Buffer::new();
|
||||||
|
let printed = buffer.format(128u64);
|
||||||
|
assert_eq!(printed, "128");
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
<br>
|
||||||
|
|
||||||
|
## Performance
|
||||||
|
|
||||||
|
The [itoa-benchmark] compares this library and other Rust integer formatting
|
||||||
|
implementations across a range of integer sizes. The vertical axis in this chart
|
||||||
|
shows nanoseconds taken by a single execution of
|
||||||
|
`itoa::Buffer::new().format(value)` so a lower result indicates a faster
|
||||||
|
library.
|
||||||
|
|
||||||
|
[itoa-benchmark]: https://github.com/dtolnay/itoa-benchmark
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
<br>
|
||||||
|
|
||||||
|
#### License
|
||||||
|
|
||||||
|
<sup>
|
||||||
|
Licensed under either of <a href="LICENSE-APACHE">Apache License, Version
|
||||||
|
2.0</a> or <a href="LICENSE-MIT">MIT license</a> at your option.
|
||||||
|
</sup>
|
||||||
|
|
||||||
|
<br>
|
||||||
|
|
||||||
|
<sub>
|
||||||
|
Unless you explicitly state otherwise, any contribution intentionally submitted
|
||||||
|
for inclusion in this crate by you, as defined in the Apache-2.0 license, shall
|
||||||
|
be dual licensed as above, without any additional terms or conditions.
|
||||||
|
</sub>
|
||||||
|
|
@ -0,0 +1,41 @@
|
||||||
|
use criterion::{criterion_group, criterion_main, Criterion};
|
||||||
|
use std::fmt::Display;
|
||||||
|
use std::hint;
|
||||||
|
use std::io::Write;
|
||||||
|
|
||||||
|
fn do_bench(c: &mut Criterion, group_name: &str, int: impl itoa::Integer + Display) {
|
||||||
|
let mut group = c.benchmark_group(group_name);
|
||||||
|
group.bench_function("itoa", |b| {
|
||||||
|
let mut buf = itoa::Buffer::new();
|
||||||
|
b.iter(move || {
|
||||||
|
let int = hint::black_box(int);
|
||||||
|
let formatted = buf.format(int);
|
||||||
|
hint::black_box(formatted);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
group.bench_function("std::fmt", |b| {
|
||||||
|
let mut buf = Vec::with_capacity(20);
|
||||||
|
b.iter(|| {
|
||||||
|
buf.clear();
|
||||||
|
let int = hint::black_box(int);
|
||||||
|
write!(&mut buf, "{int}").unwrap();
|
||||||
|
hint::black_box(buf.as_slice());
|
||||||
|
});
|
||||||
|
});
|
||||||
|
group.finish();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn bench(c: &mut Criterion) {
|
||||||
|
do_bench(c, "u64[0]", 0u64);
|
||||||
|
do_bench(c, "u64[half]", u64::from(u32::MAX));
|
||||||
|
do_bench(c, "u64[max]", u64::MAX);
|
||||||
|
|
||||||
|
do_bench(c, "i16[0]", 0i16);
|
||||||
|
do_bench(c, "i16[min]", i16::MIN);
|
||||||
|
|
||||||
|
do_bench(c, "u128[0]", 0u128);
|
||||||
|
do_bench(c, "u128[max]", u128::MAX);
|
||||||
|
}
|
||||||
|
|
||||||
|
criterion_group!(benches, bench);
|
||||||
|
criterion_main!(benches);
|
||||||
|
|
@ -0,0 +1,466 @@
|
||||||
|
//! [![github]](https://github.com/dtolnay/itoa) [![crates-io]](https://crates.io/crates/itoa) [![docs-rs]](https://docs.rs/itoa)
|
||||||
|
//!
|
||||||
|
//! [github]: https://img.shields.io/badge/github-8da0cb?style=for-the-badge&labelColor=555555&logo=github
|
||||||
|
//! [crates-io]: https://img.shields.io/badge/crates.io-fc8d62?style=for-the-badge&labelColor=555555&logo=rust
|
||||||
|
//! [docs-rs]: https://img.shields.io/badge/docs.rs-66c2a5?style=for-the-badge&labelColor=555555&logo=docs.rs
|
||||||
|
//!
|
||||||
|
//! <br>
|
||||||
|
//!
|
||||||
|
//! This crate provides a fast conversion of integer primitives to decimal
|
||||||
|
//! strings. The implementation comes straight from [libcore] but avoids the
|
||||||
|
//! performance penalty of going through [`core::fmt::Formatter`].
|
||||||
|
//!
|
||||||
|
//! See also [`zmij`] for printing floating point primitives.
|
||||||
|
//!
|
||||||
|
//! [libcore]: https://github.com/rust-lang/rust/blob/1.92.0/library/core/src/fmt/num.rs#L190-L253
|
||||||
|
//! [`zmij`]: https://github.com/dtolnay/zmij
|
||||||
|
//!
|
||||||
|
//! # Example
|
||||||
|
//!
|
||||||
|
//! ```
|
||||||
|
//! fn main() {
|
||||||
|
//! let mut buffer = itoa::Buffer::new();
|
||||||
|
//! let printed = buffer.format(128u64);
|
||||||
|
//! assert_eq!(printed, "128");
|
||||||
|
//! }
|
||||||
|
//! ```
|
||||||
|
//!
|
||||||
|
//! # Performance
|
||||||
|
//!
|
||||||
|
//! The [itoa-benchmark] compares this library and other Rust integer formatting
|
||||||
|
//! implementations across a range of integer sizes. The vertical axis in this
|
||||||
|
//! chart shows nanoseconds taken by a single execution of
|
||||||
|
//! `itoa::Buffer::new().format(value)` so a lower result indicates a faster
|
||||||
|
//! library.
|
||||||
|
//!
|
||||||
|
//! [itoa-benchmark]: https://github.com/dtolnay/itoa-benchmark
|
||||||
|
//!
|
||||||
|
//! 
|
||||||
|
|
||||||
|
#![doc(html_root_url = "https://docs.rs/itoa/1.0.18")]
|
||||||
|
#![no_std]
|
||||||
|
#![allow(
|
||||||
|
clippy::cast_lossless,
|
||||||
|
clippy::cast_possible_truncation,
|
||||||
|
clippy::cast_sign_loss,
|
||||||
|
clippy::expl_impl_clone_on_copy,
|
||||||
|
clippy::identity_op,
|
||||||
|
clippy::items_after_statements,
|
||||||
|
clippy::must_use_candidate,
|
||||||
|
clippy::needless_doctest_main,
|
||||||
|
clippy::unreadable_literal
|
||||||
|
)]
|
||||||
|
|
||||||
|
mod u128_ext;
|
||||||
|
|
||||||
|
use core::hint;
|
||||||
|
use core::mem::{self, MaybeUninit};
|
||||||
|
use core::str;
|
||||||
|
#[cfg(feature = "no-panic")]
|
||||||
|
use no_panic::no_panic;
|
||||||
|
|
||||||
|
/// A correctly sized stack allocation for the formatted integer to be written
|
||||||
|
/// into.
|
||||||
|
///
|
||||||
|
/// # Example
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// let mut buffer = itoa::Buffer::new();
|
||||||
|
/// let printed = buffer.format(1234);
|
||||||
|
/// assert_eq!(printed, "1234");
|
||||||
|
/// ```
|
||||||
|
pub struct Buffer {
|
||||||
|
bytes: [MaybeUninit<u8>; i128::MAX_STR_LEN],
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for Buffer {
|
||||||
|
#[inline]
|
||||||
|
fn default() -> Buffer {
|
||||||
|
Buffer::new()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Copy for Buffer {}
|
||||||
|
|
||||||
|
#[allow(clippy::non_canonical_clone_impl)]
|
||||||
|
impl Clone for Buffer {
|
||||||
|
#[inline]
|
||||||
|
fn clone(&self) -> Self {
|
||||||
|
Buffer::new()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Buffer {
|
||||||
|
/// This is a cheap operation; you don't need to worry about reusing buffers
|
||||||
|
/// for efficiency.
|
||||||
|
#[inline]
|
||||||
|
#[cfg_attr(feature = "no-panic", no_panic)]
|
||||||
|
pub fn new() -> Buffer {
|
||||||
|
let bytes = [MaybeUninit::<u8>::uninit(); i128::MAX_STR_LEN];
|
||||||
|
Buffer { bytes }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Print an integer into this buffer and return a reference to its string
|
||||||
|
/// representation within the buffer.
|
||||||
|
#[cfg_attr(feature = "no-panic", no_panic)]
|
||||||
|
pub fn format<I: Integer>(&mut self, i: I) -> &str {
|
||||||
|
let buf_ptr = self.bytes.as_mut_ptr().cast::<I::Buffer>();
|
||||||
|
let string = i.write(unsafe { &mut *buf_ptr });
|
||||||
|
if string.len() > I::MAX_STR_LEN {
|
||||||
|
unsafe { hint::unreachable_unchecked() };
|
||||||
|
}
|
||||||
|
string
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// An integer that can be written into an [`itoa::Buffer`][Buffer].
|
||||||
|
///
|
||||||
|
/// This trait is sealed and cannot be implemented for types outside of itoa.
|
||||||
|
pub trait Integer: private::Sealed {
|
||||||
|
/// The maximum length of string that formatting an integer of this type can
|
||||||
|
/// produce on the current target platform.
|
||||||
|
const MAX_STR_LEN: usize;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Seal to prevent downstream implementations of the Integer trait.
|
||||||
|
mod private {
|
||||||
|
#[doc(hidden)]
|
||||||
|
pub trait Sealed: Copy {
|
||||||
|
#[doc(hidden)]
|
||||||
|
type Buffer: 'static;
|
||||||
|
fn write(self, buf: &mut Self::Buffer) -> &str;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! impl_Integer {
|
||||||
|
($Signed:ident, $Unsigned:ident) => {
|
||||||
|
const _: () = {
|
||||||
|
assert!($Signed::MIN < 0, "need signed");
|
||||||
|
assert!($Unsigned::MIN == 0, "need unsigned");
|
||||||
|
assert!($Signed::BITS == $Unsigned::BITS, "need counterparts");
|
||||||
|
};
|
||||||
|
|
||||||
|
impl Integer for $Unsigned {
|
||||||
|
const MAX_STR_LEN: usize = $Unsigned::MAX.ilog10() as usize + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl private::Sealed for $Unsigned {
|
||||||
|
type Buffer = [MaybeUninit<u8>; Self::MAX_STR_LEN];
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
#[cfg_attr(feature = "no-panic", no_panic)]
|
||||||
|
fn write(self, buf: &mut Self::Buffer) -> &str {
|
||||||
|
let offset = Unsigned::fmt(self, buf);
|
||||||
|
// SAFETY: Starting from `offset`, all elements of the slice have been set.
|
||||||
|
unsafe { slice_buffer_to_str(buf, offset) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Integer for $Signed {
|
||||||
|
const MAX_STR_LEN: usize = $Signed::MAX.ilog10() as usize + 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl private::Sealed for $Signed {
|
||||||
|
type Buffer = [MaybeUninit<u8>; Self::MAX_STR_LEN];
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
#[cfg_attr(feature = "no-panic", no_panic)]
|
||||||
|
fn write(self, buf: &mut Self::Buffer) -> &str {
|
||||||
|
let mut offset = Self::MAX_STR_LEN - $Unsigned::MAX_STR_LEN;
|
||||||
|
offset += Unsigned::fmt(
|
||||||
|
self.unsigned_abs(),
|
||||||
|
(&mut buf[offset..]).try_into().unwrap(),
|
||||||
|
);
|
||||||
|
if self < 0 {
|
||||||
|
offset -= 1;
|
||||||
|
buf[offset].write(b'-');
|
||||||
|
}
|
||||||
|
// SAFETY: Starting from `offset`, all elements of the slice have been set.
|
||||||
|
unsafe { slice_buffer_to_str(buf, offset) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
impl_Integer!(i8, u8);
|
||||||
|
impl_Integer!(i16, u16);
|
||||||
|
impl_Integer!(i32, u32);
|
||||||
|
impl_Integer!(i64, u64);
|
||||||
|
impl_Integer!(i128, u128);
|
||||||
|
|
||||||
|
macro_rules! impl_Integer_size {
|
||||||
|
($t:ty as $primitive:ident #[cfg(target_pointer_width = $width:literal)]) => {
|
||||||
|
#[cfg(target_pointer_width = $width)]
|
||||||
|
impl Integer for $t {
|
||||||
|
const MAX_STR_LEN: usize = <$primitive as Integer>::MAX_STR_LEN;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(target_pointer_width = $width)]
|
||||||
|
impl private::Sealed for $t {
|
||||||
|
type Buffer = <$primitive as private::Sealed>::Buffer;
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
#[cfg_attr(feature = "no-panic", no_panic)]
|
||||||
|
fn write(self, buf: &mut Self::Buffer) -> &str {
|
||||||
|
(self as $primitive).write(buf)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
impl_Integer_size!(isize as i16 #[cfg(target_pointer_width = "16")]);
|
||||||
|
impl_Integer_size!(usize as u16 #[cfg(target_pointer_width = "16")]);
|
||||||
|
impl_Integer_size!(isize as i32 #[cfg(target_pointer_width = "32")]);
|
||||||
|
impl_Integer_size!(usize as u32 #[cfg(target_pointer_width = "32")]);
|
||||||
|
impl_Integer_size!(isize as i64 #[cfg(target_pointer_width = "64")]);
|
||||||
|
impl_Integer_size!(usize as u64 #[cfg(target_pointer_width = "64")]);
|
||||||
|
|
||||||
|
#[repr(C, align(2))]
|
||||||
|
struct DecimalPairs([u8; 200]);
|
||||||
|
|
||||||
|
// The string of all two-digit numbers in range 00..99 is used as a lookup table.
|
||||||
|
static DECIMAL_PAIRS: DecimalPairs = DecimalPairs(
|
||||||
|
*b"0001020304050607080910111213141516171819\
|
||||||
|
2021222324252627282930313233343536373839\
|
||||||
|
4041424344454647484950515253545556575859\
|
||||||
|
6061626364656667686970717273747576777879\
|
||||||
|
8081828384858687888990919293949596979899",
|
||||||
|
);
|
||||||
|
|
||||||
|
// Returns {value / 100, value % 100} correct for values of up to 4 digits.
|
||||||
|
fn divmod100(value: u32) -> (u32, u32) {
|
||||||
|
debug_assert!(value < 10_000);
|
||||||
|
const EXP: u32 = 19; // 19 is faster or equal to 12 even for 3 digits.
|
||||||
|
const SIG: u32 = (1 << EXP) / 100 + 1;
|
||||||
|
let div = (value * SIG) >> EXP; // value / 100
|
||||||
|
(div, value - div * 100)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// This function converts a slice of ascii characters into a `&str` starting
|
||||||
|
/// from `offset`.
|
||||||
|
///
|
||||||
|
/// # Safety
|
||||||
|
///
|
||||||
|
/// `buf` content starting from `offset` index MUST BE initialized and MUST BE
|
||||||
|
/// ascii characters.
|
||||||
|
#[cfg_attr(feature = "no-panic", no_panic)]
|
||||||
|
unsafe fn slice_buffer_to_str(buf: &[MaybeUninit<u8>], offset: usize) -> &str {
|
||||||
|
// SAFETY: `offset` is always included between 0 and `buf`'s length.
|
||||||
|
let written = unsafe { buf.get_unchecked(offset..) };
|
||||||
|
// SAFETY: (`assume_init_ref`) All buf content since offset is set.
|
||||||
|
// SAFETY: (`from_utf8_unchecked`) Writes use ASCII from the lookup table exclusively.
|
||||||
|
unsafe { str::from_utf8_unchecked(&*(written as *const [MaybeUninit<u8>] as *const [u8])) }
|
||||||
|
}
|
||||||
|
|
||||||
|
trait Unsigned: Integer {
|
||||||
|
fn fmt(self, buf: &mut Self::Buffer) -> usize;
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! impl_Unsigned {
|
||||||
|
($Unsigned:ident) => {
|
||||||
|
impl Unsigned for $Unsigned {
|
||||||
|
#[cfg_attr(feature = "no-panic", no_panic)]
|
||||||
|
fn fmt(self, buf: &mut Self::Buffer) -> usize {
|
||||||
|
// Count the number of bytes in buf that are not initialized.
|
||||||
|
let mut offset = buf.len();
|
||||||
|
// Consume the least-significant decimals from a working copy.
|
||||||
|
let mut remain = self;
|
||||||
|
|
||||||
|
// Format per four digits from the lookup table.
|
||||||
|
// Four digits need a 16-bit $Unsigned or wider.
|
||||||
|
while mem::size_of::<Self>() > 1
|
||||||
|
&& remain
|
||||||
|
> 999
|
||||||
|
.try_into()
|
||||||
|
.expect("branch is not hit for types that cannot fit 999 (u8)")
|
||||||
|
{
|
||||||
|
offset -= 4;
|
||||||
|
|
||||||
|
// pull two pairs
|
||||||
|
let scale: Self = 1_00_00
|
||||||
|
.try_into()
|
||||||
|
.expect("branch is not hit for types that cannot fit 1E4 (u8)");
|
||||||
|
let quad = remain % scale;
|
||||||
|
remain /= scale;
|
||||||
|
let (pair1, pair2) = divmod100(quad as u32);
|
||||||
|
unsafe {
|
||||||
|
buf[offset + 0]
|
||||||
|
.write(*DECIMAL_PAIRS.0.get_unchecked(pair1 as usize * 2 + 0));
|
||||||
|
buf[offset + 1]
|
||||||
|
.write(*DECIMAL_PAIRS.0.get_unchecked(pair1 as usize * 2 + 1));
|
||||||
|
buf[offset + 2]
|
||||||
|
.write(*DECIMAL_PAIRS.0.get_unchecked(pair2 as usize * 2 + 0));
|
||||||
|
buf[offset + 3]
|
||||||
|
.write(*DECIMAL_PAIRS.0.get_unchecked(pair2 as usize * 2 + 1));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Format per two digits from the lookup table.
|
||||||
|
if remain > 9 {
|
||||||
|
offset -= 2;
|
||||||
|
|
||||||
|
let (last, pair) = divmod100(remain as u32);
|
||||||
|
remain = last as Self;
|
||||||
|
unsafe {
|
||||||
|
buf[offset + 0]
|
||||||
|
.write(*DECIMAL_PAIRS.0.get_unchecked(pair as usize * 2 + 0));
|
||||||
|
buf[offset + 1]
|
||||||
|
.write(*DECIMAL_PAIRS.0.get_unchecked(pair as usize * 2 + 1));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Format the last remaining digit, if any.
|
||||||
|
if remain != 0 || self == 0 {
|
||||||
|
offset -= 1;
|
||||||
|
|
||||||
|
// Either the compiler sees that remain < 10, or it prevents
|
||||||
|
// a boundary check up next.
|
||||||
|
let last = remain as u8 & 15;
|
||||||
|
buf[offset].write(b'0' + last);
|
||||||
|
// not used: remain = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
offset
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
impl_Unsigned!(u8);
|
||||||
|
impl_Unsigned!(u16);
|
||||||
|
impl_Unsigned!(u32);
|
||||||
|
impl_Unsigned!(u64);
|
||||||
|
|
||||||
|
impl Unsigned for u128 {
|
||||||
|
#[cfg_attr(feature = "no-panic", no_panic)]
|
||||||
|
fn fmt(self, buf: &mut Self::Buffer) -> usize {
|
||||||
|
// Optimize common-case zero, which would also need special treatment due to
|
||||||
|
// its "leading" zero.
|
||||||
|
if self == 0 {
|
||||||
|
let offset = buf.len() - 1;
|
||||||
|
buf[offset].write(b'0');
|
||||||
|
return offset;
|
||||||
|
}
|
||||||
|
// Take the 16 least-significant decimals.
|
||||||
|
let (quot_1e16, mod_1e16) = div_rem_1e16(self);
|
||||||
|
let (mut remain, mut offset) = if quot_1e16 == 0 {
|
||||||
|
(mod_1e16, u128::MAX_STR_LEN)
|
||||||
|
} else {
|
||||||
|
// Write digits at buf[23..39].
|
||||||
|
enc_16lsd::<{ u128::MAX_STR_LEN - 16 }>(buf, mod_1e16);
|
||||||
|
|
||||||
|
// Take another 16 decimals.
|
||||||
|
let (quot2, mod2) = div_rem_1e16(quot_1e16);
|
||||||
|
if quot2 == 0 {
|
||||||
|
(mod2, u128::MAX_STR_LEN - 16)
|
||||||
|
} else {
|
||||||
|
// Write digits at buf[7..23].
|
||||||
|
enc_16lsd::<{ u128::MAX_STR_LEN - 32 }>(buf, mod2);
|
||||||
|
// Quot2 has at most 7 decimals remaining after two 1e16 divisions.
|
||||||
|
(quot2 as u64, u128::MAX_STR_LEN - 32)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Format per four digits from the lookup table.
|
||||||
|
while remain > 999 {
|
||||||
|
offset -= 4;
|
||||||
|
|
||||||
|
// pull two pairs
|
||||||
|
let quad = remain % 1_00_00;
|
||||||
|
remain /= 1_00_00;
|
||||||
|
let (pair1, pair2) = divmod100(quad as u32);
|
||||||
|
unsafe {
|
||||||
|
buf[offset + 0].write(*DECIMAL_PAIRS.0.get_unchecked(pair1 as usize * 2 + 0));
|
||||||
|
buf[offset + 1].write(*DECIMAL_PAIRS.0.get_unchecked(pair1 as usize * 2 + 1));
|
||||||
|
buf[offset + 2].write(*DECIMAL_PAIRS.0.get_unchecked(pair2 as usize * 2 + 0));
|
||||||
|
buf[offset + 3].write(*DECIMAL_PAIRS.0.get_unchecked(pair2 as usize * 2 + 1));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Format per two digits from the lookup table.
|
||||||
|
if remain > 9 {
|
||||||
|
offset -= 2;
|
||||||
|
|
||||||
|
let (last, pair) = divmod100(remain as u32);
|
||||||
|
remain = last as u64;
|
||||||
|
unsafe {
|
||||||
|
buf[offset + 0].write(*DECIMAL_PAIRS.0.get_unchecked(pair as usize * 2 + 0));
|
||||||
|
buf[offset + 1].write(*DECIMAL_PAIRS.0.get_unchecked(pair as usize * 2 + 1));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Format the last remaining digit, if any.
|
||||||
|
if remain != 0 {
|
||||||
|
offset -= 1;
|
||||||
|
|
||||||
|
// Either the compiler sees that remain < 10, or it prevents
|
||||||
|
// a boundary check up next.
|
||||||
|
let last = remain as u8 & 15;
|
||||||
|
buf[offset].write(b'0' + last);
|
||||||
|
// not used: remain = 0;
|
||||||
|
}
|
||||||
|
offset
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Encodes the 16 least-significant decimals of n into `buf[OFFSET..OFFSET + 16]`.
|
||||||
|
#[cfg_attr(feature = "no-panic", no_panic)]
|
||||||
|
fn enc_16lsd<const OFFSET: usize>(buf: &mut [MaybeUninit<u8>], n: u64) {
|
||||||
|
// Consume the least-significant decimals from a working copy.
|
||||||
|
let mut remain = n;
|
||||||
|
|
||||||
|
// Format per four digits from the lookup table.
|
||||||
|
for quad_index in (1..4).rev() {
|
||||||
|
// pull two pairs
|
||||||
|
let quad = remain % 1_00_00;
|
||||||
|
remain /= 1_00_00;
|
||||||
|
let (pair1, pair2) = divmod100(quad as u32);
|
||||||
|
unsafe {
|
||||||
|
buf[quad_index * 4 + OFFSET + 0]
|
||||||
|
.write(*DECIMAL_PAIRS.0.get_unchecked(pair1 as usize * 2 + 0));
|
||||||
|
buf[quad_index * 4 + OFFSET + 1]
|
||||||
|
.write(*DECIMAL_PAIRS.0.get_unchecked(pair1 as usize * 2 + 1));
|
||||||
|
buf[quad_index * 4 + OFFSET + 2]
|
||||||
|
.write(*DECIMAL_PAIRS.0.get_unchecked(pair2 as usize * 2 + 0));
|
||||||
|
buf[quad_index * 4 + OFFSET + 3]
|
||||||
|
.write(*DECIMAL_PAIRS.0.get_unchecked(pair2 as usize * 2 + 1));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// final two pairs
|
||||||
|
let (pair1, pair2) = divmod100(remain as u32);
|
||||||
|
unsafe {
|
||||||
|
buf[OFFSET + 0].write(*DECIMAL_PAIRS.0.get_unchecked(pair1 as usize * 2 + 0));
|
||||||
|
buf[OFFSET + 1].write(*DECIMAL_PAIRS.0.get_unchecked(pair1 as usize * 2 + 1));
|
||||||
|
buf[OFFSET + 2].write(*DECIMAL_PAIRS.0.get_unchecked(pair2 as usize * 2 + 0));
|
||||||
|
buf[OFFSET + 3].write(*DECIMAL_PAIRS.0.get_unchecked(pair2 as usize * 2 + 1));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Euclidean division plus remainder with constant 1E16 basically consumes 16
|
||||||
|
// decimals from n.
|
||||||
|
//
|
||||||
|
// The integer division algorithm is based on the following paper:
|
||||||
|
//
|
||||||
|
// T. Granlund and P. Montgomery, “Division by Invariant Integers Using Multiplication”
|
||||||
|
// in Proc. of the SIGPLAN94 Conference on Programming Language Design and
|
||||||
|
// Implementation, 1994, pp. 61–72
|
||||||
|
//
|
||||||
|
#[cfg_attr(feature = "no-panic", no_panic)]
|
||||||
|
fn div_rem_1e16(n: u128) -> (u128, u64) {
|
||||||
|
const D: u128 = 1_0000_0000_0000_0000;
|
||||||
|
// The check inlines well with the caller flow.
|
||||||
|
if n < D {
|
||||||
|
return (0, n as u64);
|
||||||
|
}
|
||||||
|
|
||||||
|
// These constant values are computed with the CHOOSE_MULTIPLIER procedure
|
||||||
|
// from the Granlund & Montgomery paper, using N=128, prec=128 and d=1E16.
|
||||||
|
const M_HIGH: u128 = 76624777043294442917917351357515459181;
|
||||||
|
const SH_POST: u8 = 51;
|
||||||
|
|
||||||
|
// n.widening_mul(M_HIGH).1 >> SH_POST
|
||||||
|
let quot = u128_ext::mulhi(n, M_HIGH) >> SH_POST;
|
||||||
|
let rem = n - quot * D;
|
||||||
|
(quot, rem as u64)
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,22 @@
|
||||||
|
#[cfg(feature = "no-panic")]
|
||||||
|
use no_panic::no_panic;
|
||||||
|
|
||||||
|
/// Multiply unsigned 128 bit integers, return upper 128 bits of the result
|
||||||
|
#[inline]
|
||||||
|
#[cfg_attr(feature = "no-panic", no_panic)]
|
||||||
|
pub(crate) fn mulhi(x: u128, y: u128) -> u128 {
|
||||||
|
let x_lo = x as u64;
|
||||||
|
let x_hi = (x >> 64) as u64;
|
||||||
|
let y_lo = y as u64;
|
||||||
|
let y_hi = (y >> 64) as u64;
|
||||||
|
|
||||||
|
// handle possibility of overflow
|
||||||
|
let carry = (u128::from(x_lo) * u128::from(y_lo)) >> 64;
|
||||||
|
let m = u128::from(x_lo) * u128::from(y_hi) + carry;
|
||||||
|
let high1 = m >> 64;
|
||||||
|
|
||||||
|
let m_lo = m as u64;
|
||||||
|
let high2 = (u128::from(x_hi) * u128::from(y_lo) + u128::from(m_lo)) >> 64;
|
||||||
|
|
||||||
|
u128::from(x_hi) * u128::from(y_hi) + high1 + high2
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,45 @@
|
||||||
|
#![allow(non_snake_case)]
|
||||||
|
|
||||||
|
macro_rules! test {
|
||||||
|
($($name:ident($value:expr, $expected:expr))*) => {
|
||||||
|
$(
|
||||||
|
#[test]
|
||||||
|
fn $name() {
|
||||||
|
let mut buffer = itoa::Buffer::new();
|
||||||
|
let s = buffer.format($value);
|
||||||
|
assert_eq!(s, $expected);
|
||||||
|
}
|
||||||
|
)*
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
test! {
|
||||||
|
test_u64_0(0u64, "0")
|
||||||
|
test_u64_half(u64::from(u32::MAX), "4294967295")
|
||||||
|
test_u64_max(u64::MAX, "18446744073709551615")
|
||||||
|
test_i64_min(i64::MIN, "-9223372036854775808")
|
||||||
|
|
||||||
|
test_i16_0(0i16, "0")
|
||||||
|
test_i16_min(i16::MIN, "-32768")
|
||||||
|
|
||||||
|
test_u128_0(0u128, "0")
|
||||||
|
test_u128_max(u128::MAX, "340282366920938463463374607431768211455")
|
||||||
|
test_i128_min(i128::MIN, "-170141183460469231731687303715884105728")
|
||||||
|
test_i128_max(i128::MAX, "170141183460469231731687303715884105727")
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_max_str_len() {
|
||||||
|
use itoa::Integer as _;
|
||||||
|
|
||||||
|
assert_eq!(i8::MAX_STR_LEN, 4);
|
||||||
|
assert_eq!(u8::MAX_STR_LEN, 3);
|
||||||
|
assert_eq!(i16::MAX_STR_LEN, 6);
|
||||||
|
assert_eq!(u16::MAX_STR_LEN, 5);
|
||||||
|
assert_eq!(i32::MAX_STR_LEN, 11);
|
||||||
|
assert_eq!(u32::MAX_STR_LEN, 10);
|
||||||
|
assert_eq!(i64::MAX_STR_LEN, 20);
|
||||||
|
assert_eq!(u64::MAX_STR_LEN, 20);
|
||||||
|
assert_eq!(i128::MAX_STR_LEN, 40);
|
||||||
|
assert_eq!(u128::MAX_STR_LEN, 39);
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
{"files":{"Cargo.toml":"cddddd2f5a25156a1afca3460ddabea8e77283ef1870c12aa43a891b44b9f79d","LICENSE":"fab3dd6bdab226f1c08630b1dd917e11fcb4ec5e1e020e2c16f83a0a13863e85","src/diagnostic_graph.rs":"c480b370f97805a7ca2bfd9b69b3b26755ed3e9c6d645640faae7c1dfcd9ebb8","src/diagnostic_node.rs":"1d3114a7daf9df4a2516853e6e274824853d40ab453995fa0173770bf4abe6c9","src/diagnostic_status.rs":"2cb49000d8150f9fd60cca61f41cbd59e2036b83d62b22922d85241060720d14","src/error.rs":"e5b06e19b6200ff808f0b2023d408fe12ec59ed8ec9bcc66d397ea5da9974259","src/lib.rs":"b9342371f268ef8e0d3e336d4ba80b74286370ca07ffd7b290d28c3af7e0417b","src/name_parsing.rs":"c9f3c6d9f08eb229d6912e85159304d2ea3568f40d2f220c9eee7d5a86e8644b","src/tree_view.rs":"7a271d782291bbf4df0ac6a536ba4ca015a2a7201e0e7acbdd91d841694653a4"},"package":null}
|
||||||
|
|
@ -0,0 +1,50 @@
|
||||||
|
# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO
|
||||||
|
#
|
||||||
|
# When uploading crates to the registry Cargo will automatically
|
||||||
|
# "normalize" Cargo.toml files for maximal compatibility
|
||||||
|
# with all versions of Cargo and also rewrite `path` dependencies
|
||||||
|
# to registry (e.g., crates.io) dependencies.
|
||||||
|
#
|
||||||
|
# If you are reading this file be aware that the original Cargo.toml
|
||||||
|
# will likely look very different (and much more reasonable).
|
||||||
|
# See Cargo.toml.orig for the original contents.
|
||||||
|
|
||||||
|
[package]
|
||||||
|
edition = "2024"
|
||||||
|
name = "j7s_diagnostics"
|
||||||
|
version = "0.1.0"
|
||||||
|
build = false
|
||||||
|
autolib = false
|
||||||
|
autobins = false
|
||||||
|
autoexamples = false
|
||||||
|
autotests = false
|
||||||
|
autobenches = false
|
||||||
|
readme = false
|
||||||
|
|
||||||
|
[features]
|
||||||
|
std = ["serde_json/std"]
|
||||||
|
|
||||||
|
[lib]
|
||||||
|
name = "j7s_diagnostics"
|
||||||
|
path = "src/lib.rs"
|
||||||
|
|
||||||
|
[dependencies.limbo_graph]
|
||||||
|
git = "https://git.jpace121.net/public/limbo_graph.git"
|
||||||
|
branch = "main"
|
||||||
|
|
||||||
|
[dependencies.serde]
|
||||||
|
version = "1.0"
|
||||||
|
features = [
|
||||||
|
"derive",
|
||||||
|
"alloc",
|
||||||
|
]
|
||||||
|
default-features = false
|
||||||
|
|
||||||
|
[dependencies.serde_json]
|
||||||
|
version = "1.0"
|
||||||
|
features = ["alloc"]
|
||||||
|
default-features = false
|
||||||
|
|
||||||
|
[dependencies.thiserror]
|
||||||
|
version = "2.0.18"
|
||||||
|
default-features = false
|
||||||
|
|
@ -0,0 +1,373 @@
|
||||||
|
Mozilla Public License Version 2.0
|
||||||
|
==================================
|
||||||
|
|
||||||
|
1. Definitions
|
||||||
|
--------------
|
||||||
|
|
||||||
|
1.1. "Contributor"
|
||||||
|
means each individual or legal entity that creates, contributes to
|
||||||
|
the creation of, or owns Covered Software.
|
||||||
|
|
||||||
|
1.2. "Contributor Version"
|
||||||
|
means the combination of the Contributions of others (if any) used
|
||||||
|
by a Contributor and that particular Contributor's Contribution.
|
||||||
|
|
||||||
|
1.3. "Contribution"
|
||||||
|
means Covered Software of a particular Contributor.
|
||||||
|
|
||||||
|
1.4. "Covered Software"
|
||||||
|
means Source Code Form to which the initial Contributor has attached
|
||||||
|
the notice in Exhibit A, the Executable Form of such Source Code
|
||||||
|
Form, and Modifications of such Source Code Form, in each case
|
||||||
|
including portions thereof.
|
||||||
|
|
||||||
|
1.5. "Incompatible With Secondary Licenses"
|
||||||
|
means
|
||||||
|
|
||||||
|
(a) that the initial Contributor has attached the notice described
|
||||||
|
in Exhibit B to the Covered Software; or
|
||||||
|
|
||||||
|
(b) that the Covered Software was made available under the terms of
|
||||||
|
version 1.1 or earlier of the License, but not also under the
|
||||||
|
terms of a Secondary License.
|
||||||
|
|
||||||
|
1.6. "Executable Form"
|
||||||
|
means any form of the work other than Source Code Form.
|
||||||
|
|
||||||
|
1.7. "Larger Work"
|
||||||
|
means a work that combines Covered Software with other material, in
|
||||||
|
a separate file or files, that is not Covered Software.
|
||||||
|
|
||||||
|
1.8. "License"
|
||||||
|
means this document.
|
||||||
|
|
||||||
|
1.9. "Licensable"
|
||||||
|
means having the right to grant, to the maximum extent possible,
|
||||||
|
whether at the time of the initial grant or subsequently, any and
|
||||||
|
all of the rights conveyed by this License.
|
||||||
|
|
||||||
|
1.10. "Modifications"
|
||||||
|
means any of the following:
|
||||||
|
|
||||||
|
(a) any file in Source Code Form that results from an addition to,
|
||||||
|
deletion from, or modification of the contents of Covered
|
||||||
|
Software; or
|
||||||
|
|
||||||
|
(b) any new file in Source Code Form that contains any Covered
|
||||||
|
Software.
|
||||||
|
|
||||||
|
1.11. "Patent Claims" of a Contributor
|
||||||
|
means any patent claim(s), including without limitation, method,
|
||||||
|
process, and apparatus claims, in any patent Licensable by such
|
||||||
|
Contributor that would be infringed, but for the grant of the
|
||||||
|
License, by the making, using, selling, offering for sale, having
|
||||||
|
made, import, or transfer of either its Contributions or its
|
||||||
|
Contributor Version.
|
||||||
|
|
||||||
|
1.12. "Secondary License"
|
||||||
|
means either the GNU General Public License, Version 2.0, the GNU
|
||||||
|
Lesser General Public License, Version 2.1, the GNU Affero General
|
||||||
|
Public License, Version 3.0, or any later versions of those
|
||||||
|
licenses.
|
||||||
|
|
||||||
|
1.13. "Source Code Form"
|
||||||
|
means the form of the work preferred for making modifications.
|
||||||
|
|
||||||
|
1.14. "You" (or "Your")
|
||||||
|
means an individual or a legal entity exercising rights under this
|
||||||
|
License. For legal entities, "You" includes any entity that
|
||||||
|
controls, is controlled by, or is under common control with You. For
|
||||||
|
purposes of this definition, "control" means (a) the power, direct
|
||||||
|
or indirect, to cause the direction or management of such entity,
|
||||||
|
whether by contract or otherwise, or (b) ownership of more than
|
||||||
|
fifty percent (50%) of the outstanding shares or beneficial
|
||||||
|
ownership of such entity.
|
||||||
|
|
||||||
|
2. License Grants and Conditions
|
||||||
|
--------------------------------
|
||||||
|
|
||||||
|
2.1. Grants
|
||||||
|
|
||||||
|
Each Contributor hereby grants You a world-wide, royalty-free,
|
||||||
|
non-exclusive license:
|
||||||
|
|
||||||
|
(a) under intellectual property rights (other than patent or trademark)
|
||||||
|
Licensable by such Contributor to use, reproduce, make available,
|
||||||
|
modify, display, perform, distribute, and otherwise exploit its
|
||||||
|
Contributions, either on an unmodified basis, with Modifications, or
|
||||||
|
as part of a Larger Work; and
|
||||||
|
|
||||||
|
(b) under Patent Claims of such Contributor to make, use, sell, offer
|
||||||
|
for sale, have made, import, and otherwise transfer either its
|
||||||
|
Contributions or its Contributor Version.
|
||||||
|
|
||||||
|
2.2. Effective Date
|
||||||
|
|
||||||
|
The licenses granted in Section 2.1 with respect to any Contribution
|
||||||
|
become effective for each Contribution on the date the Contributor first
|
||||||
|
distributes such Contribution.
|
||||||
|
|
||||||
|
2.3. Limitations on Grant Scope
|
||||||
|
|
||||||
|
The licenses granted in this Section 2 are the only rights granted under
|
||||||
|
this License. No additional rights or licenses will be implied from the
|
||||||
|
distribution or licensing of Covered Software under this License.
|
||||||
|
Notwithstanding Section 2.1(b) above, no patent license is granted by a
|
||||||
|
Contributor:
|
||||||
|
|
||||||
|
(a) for any code that a Contributor has removed from Covered Software;
|
||||||
|
or
|
||||||
|
|
||||||
|
(b) for infringements caused by: (i) Your and any other third party's
|
||||||
|
modifications of Covered Software, or (ii) the combination of its
|
||||||
|
Contributions with other software (except as part of its Contributor
|
||||||
|
Version); or
|
||||||
|
|
||||||
|
(c) under Patent Claims infringed by Covered Software in the absence of
|
||||||
|
its Contributions.
|
||||||
|
|
||||||
|
This License does not grant any rights in the trademarks, service marks,
|
||||||
|
or logos of any Contributor (except as may be necessary to comply with
|
||||||
|
the notice requirements in Section 3.4).
|
||||||
|
|
||||||
|
2.4. Subsequent Licenses
|
||||||
|
|
||||||
|
No Contributor makes additional grants as a result of Your choice to
|
||||||
|
distribute the Covered Software under a subsequent version of this
|
||||||
|
License (see Section 10.2) or under the terms of a Secondary License (if
|
||||||
|
permitted under the terms of Section 3.3).
|
||||||
|
|
||||||
|
2.5. Representation
|
||||||
|
|
||||||
|
Each Contributor represents that the Contributor believes its
|
||||||
|
Contributions are its original creation(s) or it has sufficient rights
|
||||||
|
to grant the rights to its Contributions conveyed by this License.
|
||||||
|
|
||||||
|
2.6. Fair Use
|
||||||
|
|
||||||
|
This License is not intended to limit any rights You have under
|
||||||
|
applicable copyright doctrines of fair use, fair dealing, or other
|
||||||
|
equivalents.
|
||||||
|
|
||||||
|
2.7. Conditions
|
||||||
|
|
||||||
|
Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted
|
||||||
|
in Section 2.1.
|
||||||
|
|
||||||
|
3. Responsibilities
|
||||||
|
-------------------
|
||||||
|
|
||||||
|
3.1. Distribution of Source Form
|
||||||
|
|
||||||
|
All distribution of Covered Software in Source Code Form, including any
|
||||||
|
Modifications that You create or to which You contribute, must be under
|
||||||
|
the terms of this License. You must inform recipients that the Source
|
||||||
|
Code Form of the Covered Software is governed by the terms of this
|
||||||
|
License, and how they can obtain a copy of this License. You may not
|
||||||
|
attempt to alter or restrict the recipients' rights in the Source Code
|
||||||
|
Form.
|
||||||
|
|
||||||
|
3.2. Distribution of Executable Form
|
||||||
|
|
||||||
|
If You distribute Covered Software in Executable Form then:
|
||||||
|
|
||||||
|
(a) such Covered Software must also be made available in Source Code
|
||||||
|
Form, as described in Section 3.1, and You must inform recipients of
|
||||||
|
the Executable Form how they can obtain a copy of such Source Code
|
||||||
|
Form by reasonable means in a timely manner, at a charge no more
|
||||||
|
than the cost of distribution to the recipient; and
|
||||||
|
|
||||||
|
(b) You may distribute such Executable Form under the terms of this
|
||||||
|
License, or sublicense it under different terms, provided that the
|
||||||
|
license for the Executable Form does not attempt to limit or alter
|
||||||
|
the recipients' rights in the Source Code Form under this License.
|
||||||
|
|
||||||
|
3.3. Distribution of a Larger Work
|
||||||
|
|
||||||
|
You may create and distribute a Larger Work under terms of Your choice,
|
||||||
|
provided that You also comply with the requirements of this License for
|
||||||
|
the Covered Software. If the Larger Work is a combination of Covered
|
||||||
|
Software with a work governed by one or more Secondary Licenses, and the
|
||||||
|
Covered Software is not Incompatible With Secondary Licenses, this
|
||||||
|
License permits You to additionally distribute such Covered Software
|
||||||
|
under the terms of such Secondary License(s), so that the recipient of
|
||||||
|
the Larger Work may, at their option, further distribute the Covered
|
||||||
|
Software under the terms of either this License or such Secondary
|
||||||
|
License(s).
|
||||||
|
|
||||||
|
3.4. Notices
|
||||||
|
|
||||||
|
You may not remove or alter the substance of any license notices
|
||||||
|
(including copyright notices, patent notices, disclaimers of warranty,
|
||||||
|
or limitations of liability) contained within the Source Code Form of
|
||||||
|
the Covered Software, except that You may alter any license notices to
|
||||||
|
the extent required to remedy known factual inaccuracies.
|
||||||
|
|
||||||
|
3.5. Application of Additional Terms
|
||||||
|
|
||||||
|
You may choose to offer, and to charge a fee for, warranty, support,
|
||||||
|
indemnity or liability obligations to one or more recipients of Covered
|
||||||
|
Software. However, You may do so only on Your own behalf, and not on
|
||||||
|
behalf of any Contributor. You must make it absolutely clear that any
|
||||||
|
such warranty, support, indemnity, or liability obligation is offered by
|
||||||
|
You alone, and You hereby agree to indemnify every Contributor for any
|
||||||
|
liability incurred by such Contributor as a result of warranty, support,
|
||||||
|
indemnity or liability terms You offer. You may include additional
|
||||||
|
disclaimers of warranty and limitations of liability specific to any
|
||||||
|
jurisdiction.
|
||||||
|
|
||||||
|
4. Inability to Comply Due to Statute or Regulation
|
||||||
|
---------------------------------------------------
|
||||||
|
|
||||||
|
If it is impossible for You to comply with any of the terms of this
|
||||||
|
License with respect to some or all of the Covered Software due to
|
||||||
|
statute, judicial order, or regulation then You must: (a) comply with
|
||||||
|
the terms of this License to the maximum extent possible; and (b)
|
||||||
|
describe the limitations and the code they affect. Such description must
|
||||||
|
be placed in a text file included with all distributions of the Covered
|
||||||
|
Software under this License. Except to the extent prohibited by statute
|
||||||
|
or regulation, such description must be sufficiently detailed for a
|
||||||
|
recipient of ordinary skill to be able to understand it.
|
||||||
|
|
||||||
|
5. Termination
|
||||||
|
--------------
|
||||||
|
|
||||||
|
5.1. The rights granted under this License will terminate automatically
|
||||||
|
if You fail to comply with any of its terms. However, if You become
|
||||||
|
compliant, then the rights granted under this License from a particular
|
||||||
|
Contributor are reinstated (a) provisionally, unless and until such
|
||||||
|
Contributor explicitly and finally terminates Your grants, and (b) on an
|
||||||
|
ongoing basis, if such Contributor fails to notify You of the
|
||||||
|
non-compliance by some reasonable means prior to 60 days after You have
|
||||||
|
come back into compliance. Moreover, Your grants from a particular
|
||||||
|
Contributor are reinstated on an ongoing basis if such Contributor
|
||||||
|
notifies You of the non-compliance by some reasonable means, this is the
|
||||||
|
first time You have received notice of non-compliance with this License
|
||||||
|
from such Contributor, and You become compliant prior to 30 days after
|
||||||
|
Your receipt of the notice.
|
||||||
|
|
||||||
|
5.2. If You initiate litigation against any entity by asserting a patent
|
||||||
|
infringement claim (excluding declaratory judgment actions,
|
||||||
|
counter-claims, and cross-claims) alleging that a Contributor Version
|
||||||
|
directly or indirectly infringes any patent, then the rights granted to
|
||||||
|
You by any and all Contributors for the Covered Software under Section
|
||||||
|
2.1 of this License shall terminate.
|
||||||
|
|
||||||
|
5.3. In the event of termination under Sections 5.1 or 5.2 above, all
|
||||||
|
end user license agreements (excluding distributors and resellers) which
|
||||||
|
have been validly granted by You or Your distributors under this License
|
||||||
|
prior to termination shall survive termination.
|
||||||
|
|
||||||
|
************************************************************************
|
||||||
|
* *
|
||||||
|
* 6. Disclaimer of Warranty *
|
||||||
|
* ------------------------- *
|
||||||
|
* *
|
||||||
|
* Covered Software is provided under this License on an "as is" *
|
||||||
|
* basis, without warranty of any kind, either expressed, implied, or *
|
||||||
|
* statutory, including, without limitation, warranties that the *
|
||||||
|
* Covered Software is free of defects, merchantable, fit for a *
|
||||||
|
* particular purpose or non-infringing. The entire risk as to the *
|
||||||
|
* quality and performance of the Covered Software is with You. *
|
||||||
|
* Should any Covered Software prove defective in any respect, You *
|
||||||
|
* (not any Contributor) assume the cost of any necessary servicing, *
|
||||||
|
* repair, or correction. This disclaimer of warranty constitutes an *
|
||||||
|
* essential part of this License. No use of any Covered Software is *
|
||||||
|
* authorized under this License except under this disclaimer. *
|
||||||
|
* *
|
||||||
|
************************************************************************
|
||||||
|
|
||||||
|
************************************************************************
|
||||||
|
* *
|
||||||
|
* 7. Limitation of Liability *
|
||||||
|
* -------------------------- *
|
||||||
|
* *
|
||||||
|
* Under no circumstances and under no legal theory, whether tort *
|
||||||
|
* (including negligence), contract, or otherwise, shall any *
|
||||||
|
* Contributor, or anyone who distributes Covered Software as *
|
||||||
|
* permitted above, be liable to You for any direct, indirect, *
|
||||||
|
* special, incidental, or consequential damages of any character *
|
||||||
|
* including, without limitation, damages for lost profits, loss of *
|
||||||
|
* goodwill, work stoppage, computer failure or malfunction, or any *
|
||||||
|
* and all other commercial damages or losses, even if such party *
|
||||||
|
* shall have been informed of the possibility of such damages. This *
|
||||||
|
* limitation of liability shall not apply to liability for death or *
|
||||||
|
* personal injury resulting from such party's negligence to the *
|
||||||
|
* extent applicable law prohibits such limitation. Some *
|
||||||
|
* jurisdictions do not allow the exclusion or limitation of *
|
||||||
|
* incidental or consequential damages, so this exclusion and *
|
||||||
|
* limitation may not apply to You. *
|
||||||
|
* *
|
||||||
|
************************************************************************
|
||||||
|
|
||||||
|
8. Litigation
|
||||||
|
-------------
|
||||||
|
|
||||||
|
Any litigation relating to this License may be brought only in the
|
||||||
|
courts of a jurisdiction where the defendant maintains its principal
|
||||||
|
place of business and such litigation shall be governed by laws of that
|
||||||
|
jurisdiction, without reference to its conflict-of-law provisions.
|
||||||
|
Nothing in this Section shall prevent a party's ability to bring
|
||||||
|
cross-claims or counter-claims.
|
||||||
|
|
||||||
|
9. Miscellaneous
|
||||||
|
----------------
|
||||||
|
|
||||||
|
This License represents the complete agreement concerning the subject
|
||||||
|
matter hereof. If any provision of this License is held to be
|
||||||
|
unenforceable, such provision shall be reformed only to the extent
|
||||||
|
necessary to make it enforceable. Any law or regulation which provides
|
||||||
|
that the language of a contract shall be construed against the drafter
|
||||||
|
shall not be used to construe this License against a Contributor.
|
||||||
|
|
||||||
|
10. Versions of the License
|
||||||
|
---------------------------
|
||||||
|
|
||||||
|
10.1. New Versions
|
||||||
|
|
||||||
|
Mozilla Foundation is the license steward. Except as provided in Section
|
||||||
|
10.3, no one other than the license steward has the right to modify or
|
||||||
|
publish new versions of this License. Each version will be given a
|
||||||
|
distinguishing version number.
|
||||||
|
|
||||||
|
10.2. Effect of New Versions
|
||||||
|
|
||||||
|
You may distribute the Covered Software under the terms of the version
|
||||||
|
of the License under which You originally received the Covered Software,
|
||||||
|
or under the terms of any subsequent version published by the license
|
||||||
|
steward.
|
||||||
|
|
||||||
|
10.3. Modified Versions
|
||||||
|
|
||||||
|
If you create software not governed by this License, and you want to
|
||||||
|
create a new license for such software, you may create and use a
|
||||||
|
modified version of this License if you rename the license and remove
|
||||||
|
any references to the name of the license steward (except to note that
|
||||||
|
such modified license differs from this License).
|
||||||
|
|
||||||
|
10.4. Distributing Source Code Form that is Incompatible With Secondary
|
||||||
|
Licenses
|
||||||
|
|
||||||
|
If You choose to distribute Source Code Form that is Incompatible With
|
||||||
|
Secondary Licenses under the terms of this version of the License, the
|
||||||
|
notice described in Exhibit B of this License must be attached.
|
||||||
|
|
||||||
|
Exhibit A - Source Code Form License Notice
|
||||||
|
-------------------------------------------
|
||||||
|
|
||||||
|
This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
|
|
||||||
|
If it is not possible or desirable to put the notice in a particular
|
||||||
|
file, then You may include the notice in a location (such as a LICENSE
|
||||||
|
file in a relevant directory) where a recipient would be likely to look
|
||||||
|
for such a notice.
|
||||||
|
|
||||||
|
You may add additional accurate notices of copyright ownership.
|
||||||
|
|
||||||
|
Exhibit B - "Incompatible With Secondary Licenses" Notice
|
||||||
|
---------------------------------------------------------
|
||||||
|
|
||||||
|
This Source Code Form is "Incompatible With Secondary Licenses", as
|
||||||
|
defined by the Mozilla Public License, v. 2.0.
|
||||||
|
|
@ -0,0 +1,450 @@
|
||||||
|
//
|
||||||
|
// Copyright 2026 James Pace
|
||||||
|
//
|
||||||
|
// This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
// License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
// file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||||
|
//
|
||||||
|
// This Source Code Form is "Incompatible With Secondary Licenses", as
|
||||||
|
// defined by the Mozilla Public License, v. 2.0.
|
||||||
|
//
|
||||||
|
use alloc::borrow::ToOwned;
|
||||||
|
use alloc::collections::BTreeMap;
|
||||||
|
use alloc::collections::VecDeque;
|
||||||
|
use alloc::string::String;
|
||||||
|
use alloc::string::ToString;
|
||||||
|
use alloc::vec::Vec;
|
||||||
|
|
||||||
|
use crate::diagnostic_node::*;
|
||||||
|
use crate::diagnostic_status::*;
|
||||||
|
use crate::error::*;
|
||||||
|
use crate::name_parsing::*;
|
||||||
|
|
||||||
|
/// A graph of diagnostic statuses, following the general idea of
|
||||||
|
/// ros aggregated diagnostics.
|
||||||
|
///
|
||||||
|
/// Diagnostics are stored in a tree by their namme.
|
||||||
|
/// Their levels can be reconciled, and the individual
|
||||||
|
/// statuses queried.
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct DiagnosticGraph {
|
||||||
|
graph: limbo_graph::Graph<DiagnosticNode>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DiagnosticGraph {
|
||||||
|
/// Generate a empty graph.
|
||||||
|
pub fn new() -> Self {
|
||||||
|
Self {
|
||||||
|
graph: limbo_graph::Graph::<DiagnosticNode>::new(DiagnosticNode::Root),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get the root key.
|
||||||
|
/// Needed to do searches in the graph outside of this crate.
|
||||||
|
pub fn root(&self) -> limbo_graph::Key {
|
||||||
|
self.graph.root_key()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get the value of a specific element of the graph.
|
||||||
|
/// Will error if the key is not in the graph, or if the key
|
||||||
|
/// is the root, which doesn't have a value.
|
||||||
|
pub fn value_of(&self, key: &limbo_graph::Key) -> Result<DiagnosticStatus> {
|
||||||
|
let graph_value = self.graph.value_of(key)?;
|
||||||
|
let result = graph_value.value()?;
|
||||||
|
Ok(result.clone())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Find all the children of key as keys.
|
||||||
|
/// Will error if key is not in the graph.
|
||||||
|
pub fn children_of(&self, key: &limbo_graph::Key) -> Result<Vec<limbo_graph::Key>> {
|
||||||
|
let result = self.graph.children_of(key)?;
|
||||||
|
Ok(result)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Given a key, find the child of that key that has the provided name.
|
||||||
|
/// The provided name must be basic (have no slashes).
|
||||||
|
/// Will return None if there are no children with that name.
|
||||||
|
pub fn child_of_which_has_name(
|
||||||
|
&self,
|
||||||
|
parent: &limbo_graph::Key,
|
||||||
|
desired_child_name: &str,
|
||||||
|
) -> Result<Option<limbo_graph::Key>> {
|
||||||
|
if !name_is_basic(&desired_child_name.to_owned()) {
|
||||||
|
return Err(Error::from_msg("desired child name must be basic."));
|
||||||
|
}
|
||||||
|
let all_children = self.children_of(parent)?;
|
||||||
|
for child in all_children.iter() {
|
||||||
|
let child_name = self.value_of(&child)?.name();
|
||||||
|
if child_name == desired_child_name {
|
||||||
|
return Ok(Some(child.clone()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Ok(None);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Find the key of the item in the graph with the provided full name
|
||||||
|
/// (i.e. the name has slashes.)
|
||||||
|
pub fn key_from_full_name(&self, full_name: &String) -> Result<Option<limbo_graph::Key>> {
|
||||||
|
let name_as_vec = split_name(&full_name);
|
||||||
|
|
||||||
|
let mut cur_base_key = self.graph.root_key();
|
||||||
|
|
||||||
|
for cur_name in name_as_vec.iter() {
|
||||||
|
let key_of_cur_name = self.child_of_which_has_name(&cur_base_key, &cur_name)?;
|
||||||
|
if key_of_cur_name.is_none() {
|
||||||
|
return Ok(None);
|
||||||
|
}
|
||||||
|
cur_base_key = key_of_cur_name.unwrap();
|
||||||
|
}
|
||||||
|
return Ok(Some(cur_base_key));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Provide the full name for a given key. (i.e. the name will have slashes).
|
||||||
|
pub fn full_name_from_key(&self, key: &limbo_graph::Key) -> Result<String> {
|
||||||
|
let path_to_key = self.graph.backtrack_from_key(key)?;
|
||||||
|
let mut full_name = String::new();
|
||||||
|
|
||||||
|
for curr_key in path_to_key.iter() {
|
||||||
|
if *curr_key == self.graph.root_key() {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
let status = self.value_of(&curr_key)?;
|
||||||
|
full_name = full_name + "/" + &status.name();
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(full_name)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Provide the value of a status from the full name.
|
||||||
|
pub fn value_from_name(
|
||||||
|
&self,
|
||||||
|
full_name: &String,
|
||||||
|
) -> Result<Option<(DiagnosticStatus, limbo_graph::Key)>> {
|
||||||
|
let key = self.key_from_full_name(full_name)?;
|
||||||
|
if key.is_none() {
|
||||||
|
return Ok(None);
|
||||||
|
}
|
||||||
|
let key = key.unwrap();
|
||||||
|
let value = self.value_of(&key)?;
|
||||||
|
|
||||||
|
return Ok(Some((value, key)));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Add a status to the graph.
|
||||||
|
/// The name of the status will be used to determine where in the
|
||||||
|
/// graph the status belongs.
|
||||||
|
pub fn add_status(&mut self, status: DiagnosticStatus) -> Result<()> {
|
||||||
|
// If I'm basic I just need to be added as a child of the root.
|
||||||
|
if status.name_is_basic() {
|
||||||
|
self.graph.add(
|
||||||
|
DiagnosticNode::DiagnosticStatus(status),
|
||||||
|
self.graph.root_key(),
|
||||||
|
)?;
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
// Find this status' child name and parent's names
|
||||||
|
let parent_names = status.get_parent_names();
|
||||||
|
|
||||||
|
let mut cur_key = self.graph.root_key();
|
||||||
|
|
||||||
|
'parent_loop: for parent_name in parent_names.iter() {
|
||||||
|
let children = self.graph.children_of(&cur_key)?;
|
||||||
|
// There are no children of this parent, so we can add
|
||||||
|
// the parent and go to the next parent.
|
||||||
|
if children.len() == 0 {
|
||||||
|
let holder_for_parent = DiagnosticStatus::from_name(parent_name.clone());
|
||||||
|
cur_key = self
|
||||||
|
.graph
|
||||||
|
.add(DiagnosticNode::DiagnosticStatus(holder_for_parent), cur_key)?;
|
||||||
|
continue 'parent_loop;
|
||||||
|
}
|
||||||
|
// This parent does have children, look at them and
|
||||||
|
// update loop if appropriate.
|
||||||
|
for child in children {
|
||||||
|
let child_node = self.graph.value_of(&child)?;
|
||||||
|
if child_node.is_root() {
|
||||||
|
// A child node can't be root.
|
||||||
|
return Err(Error::from_msg("A child node can't be root!"));
|
||||||
|
}
|
||||||
|
if child_node.value()?.name() == *parent_name {
|
||||||
|
// The child node matched the parent we were looking for.
|
||||||
|
// Continue to find the next parent, with this key as the
|
||||||
|
// current key.
|
||||||
|
cur_key = child;
|
||||||
|
continue 'parent_loop;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Parent wasn't any of the children. Add it and look for next parent.
|
||||||
|
let holder_for_parent = DiagnosticStatus::from_name(parent_name.clone());
|
||||||
|
cur_key = self
|
||||||
|
.graph
|
||||||
|
.add(DiagnosticNode::DiagnosticStatus(holder_for_parent), cur_key)?;
|
||||||
|
}
|
||||||
|
// We've updated all the parents, so we can add ourselves now.
|
||||||
|
|
||||||
|
// Do we already exist as a child of parent?
|
||||||
|
let children_of_this_parent = self.graph.children_of(&cur_key)?;
|
||||||
|
let mut names_of_children_of_this_parent = children_of_this_parent.iter().map(|x| {
|
||||||
|
self.graph
|
||||||
|
.value_of(&x)
|
||||||
|
.expect("Given child not in graph.")
|
||||||
|
.value()
|
||||||
|
.expect("Given root node as child?")
|
||||||
|
.name()
|
||||||
|
});
|
||||||
|
let child_in_children_of_this_parent =
|
||||||
|
names_of_children_of_this_parent.any(|x| x == status.get_child_name());
|
||||||
|
if !child_in_children_of_this_parent {
|
||||||
|
// If we don't we can be added.
|
||||||
|
self.graph.add(
|
||||||
|
DiagnosticNode::DiagnosticStatus(status.copy_with_child_name()),
|
||||||
|
cur_key,
|
||||||
|
)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Add all the statuses in the provided vector.
|
||||||
|
/// The name of the statuses will be used to determine where in the
|
||||||
|
/// graph the statuses belong.
|
||||||
|
pub fn add_status_vec(&mut self, statuses: &Vec<DiagnosticStatus>) -> Result<()> {
|
||||||
|
for status in statuses {
|
||||||
|
self.add_status(status.clone())?;
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Update the levels for parent nodes based on the level of their children.
|
||||||
|
pub fn reconcile_levels(&mut self) -> Result<()> {
|
||||||
|
let leaf_keys = self.graph.find_leaf_keys()?;
|
||||||
|
|
||||||
|
'leaf_key_loop: for leaf_key in leaf_keys.iter() {
|
||||||
|
let mut child_key = leaf_key.clone();
|
||||||
|
|
||||||
|
while child_key != self.graph.root_key() {
|
||||||
|
let parent_key_opt = self.graph.parent_of(&child_key)?;
|
||||||
|
if parent_key_opt == None || parent_key_opt == Some(self.graph.root_key()) {
|
||||||
|
continue 'leaf_key_loop;
|
||||||
|
}
|
||||||
|
let parent_key = parent_key_opt.unwrap();
|
||||||
|
// Reconcile the parent values.
|
||||||
|
let parent_node = self.graph.value_of(&parent_key)?;
|
||||||
|
let parent_value = parent_node.value()?;
|
||||||
|
let child_node = self.graph.value_of(&child_key)?;
|
||||||
|
let child_value = child_node.value()?;
|
||||||
|
|
||||||
|
// if child level is worse than parent key.
|
||||||
|
// reset parent level.
|
||||||
|
if child_value.level() > parent_value.level() {
|
||||||
|
let replacement_parent = DiagnosticNode::from_status(
|
||||||
|
parent_value.copy_with_new_level(child_value.level()),
|
||||||
|
);
|
||||||
|
self.graph
|
||||||
|
.replace_value_of(&parent_key, replacement_parent)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Push up the graph.
|
||||||
|
child_key = parent_key;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn export_graph(&self) -> Result<Vec<DiagnosticStatus>> {
|
||||||
|
let keys_in_order = self.graph.get_keys_by_depth()?;
|
||||||
|
|
||||||
|
let mut statuses = Vec::<DiagnosticStatus>::new();
|
||||||
|
|
||||||
|
for key in keys_in_order.iter() {
|
||||||
|
if *key == self.root() {
|
||||||
|
// The root key will always be the first one through this
|
||||||
|
// loop.
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
let status_at_key = self.value_of(&key)?;
|
||||||
|
statuses.push(status_at_key.copy_with_new_name(self.full_name_from_key(&key)?));
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(statuses)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
use alloc::vec;
|
||||||
|
|
||||||
|
fn make_a_status_with_name(name: &str) -> DiagnosticStatus {
|
||||||
|
let level = DiagnosticLevel::OK;
|
||||||
|
let message = "I'm ok";
|
||||||
|
let hardware_id = "";
|
||||||
|
let values = BTreeMap::<String, String>::new();
|
||||||
|
|
||||||
|
DiagnosticStatus::new(
|
||||||
|
level,
|
||||||
|
name.to_owned(),
|
||||||
|
message.to_owned(),
|
||||||
|
hardware_id.to_owned(),
|
||||||
|
values,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn make_a_status_with_name_and_level(name: &str, level: DiagnosticLevel) -> DiagnosticStatus {
|
||||||
|
let level = level;
|
||||||
|
let message = "";
|
||||||
|
let hardware_id = "";
|
||||||
|
let values = BTreeMap::<String, String>::new();
|
||||||
|
|
||||||
|
DiagnosticStatus::new(
|
||||||
|
level,
|
||||||
|
name.to_owned(),
|
||||||
|
message.to_owned(),
|
||||||
|
hardware_id.to_owned(),
|
||||||
|
values,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn add_one_to_graph() -> Result<()> {
|
||||||
|
let mut graph = DiagnosticGraph::new();
|
||||||
|
graph.add_status(make_a_status_with_name("/a/b/c"))?;
|
||||||
|
|
||||||
|
let first_child_keys = graph.children_of(&graph.root())?;
|
||||||
|
assert!(first_child_keys.len() == 1);
|
||||||
|
let first_child_key = first_child_keys[0];
|
||||||
|
let first_child_value = graph.value_of(&first_child_key)?;
|
||||||
|
assert!(first_child_value.name() == "a");
|
||||||
|
|
||||||
|
let second_child_keys = graph.children_of(&first_child_key)?;
|
||||||
|
assert!(second_child_keys.len() == 1);
|
||||||
|
let second_child_key = second_child_keys[0];
|
||||||
|
let second_child_value = graph.value_of(&second_child_key)?;
|
||||||
|
assert!(second_child_value.name() == "b");
|
||||||
|
|
||||||
|
let third_child_keys = graph.children_of(&second_child_key)?;
|
||||||
|
assert!(third_child_keys.len() == 1);
|
||||||
|
let third_child_key = third_child_keys[0];
|
||||||
|
let third_child_value = graph.value_of(&third_child_key)?;
|
||||||
|
assert!(third_child_value.name() == "c");
|
||||||
|
assert!(third_child_value.level() == DiagnosticLevel::OK);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn add_multiple_to_graph() -> Result<()> {
|
||||||
|
let statuses = vec![
|
||||||
|
make_a_status_with_name("/a"),
|
||||||
|
make_a_status_with_name("/a/b"),
|
||||||
|
make_a_status_with_name("/a/b/c"),
|
||||||
|
make_a_status_with_name("/a/d/e"),
|
||||||
|
make_a_status_with_name("/a/d/f"),
|
||||||
|
make_a_status_with_name("/a/d"),
|
||||||
|
];
|
||||||
|
|
||||||
|
let mut graph = DiagnosticGraph::new();
|
||||||
|
graph.add_status_vec(&statuses)?;
|
||||||
|
|
||||||
|
let root_children = graph.children_of(&graph.root())?;
|
||||||
|
assert!(root_children.len() == 1);
|
||||||
|
assert!(graph.value_of(&root_children[0])?.name() == "a");
|
||||||
|
|
||||||
|
let children_of_a = graph.children_of(&root_children[0])?;
|
||||||
|
let mut children_of_a_names = children_of_a
|
||||||
|
.iter()
|
||||||
|
.map(|x| graph.value_of(&x).expect("Value of failed.").name());
|
||||||
|
assert!(children_of_a.len() == 2);
|
||||||
|
assert!(children_of_a_names.any(|x| x == "b"));
|
||||||
|
assert!(children_of_a_names.any(|x| x == "d"));
|
||||||
|
|
||||||
|
let b_key = graph.child_of_which_has_name(&root_children[0], "b")?;
|
||||||
|
assert!(b_key.is_some());
|
||||||
|
let b_children = graph.children_of(&b_key.unwrap())?;
|
||||||
|
assert!(b_children.len() == 1);
|
||||||
|
|
||||||
|
let d_key = graph.child_of_which_has_name(&root_children[0], "d")?;
|
||||||
|
assert!(d_key.is_some());
|
||||||
|
let d_children = graph.children_of(&d_key.unwrap())?;
|
||||||
|
assert!(d_children.len() == 2);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn key_name_connections() -> Result<()> {
|
||||||
|
let statuses = vec![
|
||||||
|
make_a_status_with_name("/a"),
|
||||||
|
make_a_status_with_name("/a/b"),
|
||||||
|
make_a_status_with_name("/a/d/e"),
|
||||||
|
make_a_status_with_name("/a/d"),
|
||||||
|
];
|
||||||
|
|
||||||
|
let mut graph = DiagnosticGraph::new();
|
||||||
|
graph.add_status_vec(&statuses)?;
|
||||||
|
|
||||||
|
let key_for_a = graph.key_from_full_name(&"/a".to_owned())?;
|
||||||
|
assert!(key_for_a == Some(1));
|
||||||
|
|
||||||
|
let key_for_e = graph.key_from_full_name(&"/a/d/e".to_owned())?;
|
||||||
|
assert!(key_for_e == Some(4));
|
||||||
|
|
||||||
|
let not_in_graph = graph.key_from_full_name(&"/a/b/c".to_owned())?;
|
||||||
|
assert!(not_in_graph == None);
|
||||||
|
|
||||||
|
let name_for_e = graph.full_name_from_key(&4)?;
|
||||||
|
assert!(name_for_e == "/a/d/e".to_owned());
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn reconcile_graph() -> Result<()> {
|
||||||
|
let statuses = vec![
|
||||||
|
make_a_status_with_name_and_level("/a", DiagnosticLevel::UNSET),
|
||||||
|
make_a_status_with_name_and_level("/a/b", DiagnosticLevel::UNSET),
|
||||||
|
make_a_status_with_name_and_level("/a/b/c", DiagnosticLevel::OK),
|
||||||
|
make_a_status_with_name_and_level("/a/d/e", DiagnosticLevel::WARN),
|
||||||
|
make_a_status_with_name_and_level("/a/d", DiagnosticLevel::WARN),
|
||||||
|
make_a_status_with_name_and_level("/a/d/f", DiagnosticLevel::OK),
|
||||||
|
];
|
||||||
|
let mut graph = DiagnosticGraph::new();
|
||||||
|
graph.add_status_vec(&statuses)?;
|
||||||
|
|
||||||
|
graph.reconcile_levels()?;
|
||||||
|
|
||||||
|
let (a_status, _) = graph.value_from_name(&"/a".to_owned())?.unwrap();
|
||||||
|
assert!(a_status.level() == DiagnosticLevel::WARN);
|
||||||
|
|
||||||
|
let (d_status, _) = graph.value_from_name(&"/a/d".to_owned())?.unwrap();
|
||||||
|
assert!(d_status.level() == DiagnosticLevel::WARN);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn export_graph() -> Result<()> {
|
||||||
|
let statuses = vec![
|
||||||
|
make_a_status_with_name_and_level("/a", DiagnosticLevel::UNSET),
|
||||||
|
make_a_status_with_name_and_level("/a/b/c", DiagnosticLevel::OK),
|
||||||
|
make_a_status_with_name_and_level("/a/b", DiagnosticLevel::UNSET),
|
||||||
|
make_a_status_with_name_and_level("/a/d", DiagnosticLevel::UNSET),
|
||||||
|
];
|
||||||
|
let mut graph = DiagnosticGraph::new();
|
||||||
|
graph.add_status_vec(&statuses)?;
|
||||||
|
|
||||||
|
let exported = graph.export_graph()?;
|
||||||
|
|
||||||
|
assert!(exported.len() == 4);
|
||||||
|
// Searching doen the b tree first would also be
|
||||||
|
// technically correct, but this is the order the implementation
|
||||||
|
// is currently going with.
|
||||||
|
assert!(exported[0].name() == "/a");
|
||||||
|
assert!(exported[1].name() == "/a/d");
|
||||||
|
assert!(exported[2].name() == "/a/b");
|
||||||
|
assert!(exported[3].name() == "/a/b/c");
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,39 @@
|
||||||
|
//
|
||||||
|
// Copyright 2026 James Pace
|
||||||
|
//
|
||||||
|
// This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
// License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
// file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||||
|
//
|
||||||
|
// This Source Code Form is "Incompatible With Secondary Licenses", as
|
||||||
|
// defined by the Mozilla Public License, v. 2.0.
|
||||||
|
//
|
||||||
|
use crate::DiagnosticStatus;
|
||||||
|
use crate::error::{Error, Result};
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub enum DiagnosticNode {
|
||||||
|
Root,
|
||||||
|
DiagnosticStatus(DiagnosticStatus),
|
||||||
|
}
|
||||||
|
impl limbo_graph::NodeValue for DiagnosticNode {}
|
||||||
|
|
||||||
|
impl DiagnosticNode {
|
||||||
|
pub fn from_status(status: DiagnosticStatus) -> Self {
|
||||||
|
Self::DiagnosticStatus(status)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn is_root(&self) -> bool {
|
||||||
|
match self {
|
||||||
|
Self::Root => true,
|
||||||
|
_ => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn value(&self) -> Result<&DiagnosticStatus> {
|
||||||
|
match self {
|
||||||
|
Self::DiagnosticStatus(value) => Ok(value),
|
||||||
|
_ => Err(Error::from_msg("Can't get value of root key.")),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,212 @@
|
||||||
|
//
|
||||||
|
// Copyright 2026 James Pace
|
||||||
|
//
|
||||||
|
// This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
// License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
// file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||||
|
//
|
||||||
|
// This Source Code Form is "Incompatible With Secondary Licenses", as
|
||||||
|
// defined by the Mozilla Public License, v. 2.0.
|
||||||
|
//
|
||||||
|
use alloc::borrow::ToOwned;
|
||||||
|
use alloc::collections::BTreeMap;
|
||||||
|
use alloc::string::String;
|
||||||
|
use alloc::vec::Vec;
|
||||||
|
use core::default::Default;
|
||||||
|
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
|
use crate::name_parsing::{get_child_name, get_parent_names, name_is_basic};
|
||||||
|
|
||||||
|
#[derive(Clone, PartialOrd, PartialEq, Default, Serialize, Deserialize)]
|
||||||
|
pub enum DiagnosticLevel {
|
||||||
|
#[default]
|
||||||
|
UNSET,
|
||||||
|
OK,
|
||||||
|
WARN,
|
||||||
|
ERROR,
|
||||||
|
STALE,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Serialize, Deserialize)]
|
||||||
|
pub struct DiagnosticStatus {
|
||||||
|
level: DiagnosticLevel,
|
||||||
|
name: String,
|
||||||
|
message: String,
|
||||||
|
hardware_id: String,
|
||||||
|
values: BTreeMap<String, String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DiagnosticStatus {
|
||||||
|
pub fn new(
|
||||||
|
level: DiagnosticLevel,
|
||||||
|
name: String,
|
||||||
|
message: String,
|
||||||
|
hardware_id: String,
|
||||||
|
values: BTreeMap<String, String>,
|
||||||
|
) -> Self {
|
||||||
|
let cleaned_name = Self::clean_name(&name);
|
||||||
|
|
||||||
|
Self {
|
||||||
|
level: level,
|
||||||
|
name: cleaned_name,
|
||||||
|
message: message,
|
||||||
|
hardware_id: hardware_id,
|
||||||
|
values: values,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn from_name(name: String) -> Self {
|
||||||
|
let level = DiagnosticLevel::UNSET;
|
||||||
|
let message = "";
|
||||||
|
let hardware_id = "";
|
||||||
|
let values = BTreeMap::<String, String>::new();
|
||||||
|
|
||||||
|
Self::new(
|
||||||
|
level,
|
||||||
|
name,
|
||||||
|
message.to_owned(),
|
||||||
|
hardware_id.to_owned(),
|
||||||
|
values,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn level(&self) -> DiagnosticLevel {
|
||||||
|
self.level.clone()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn name(&self) -> String {
|
||||||
|
self.name.clone()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn message(&self) -> String {
|
||||||
|
self.message.clone()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn hardware_id(&self) -> String {
|
||||||
|
self.hardware_id.clone()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn values(&self) -> BTreeMap<String, String> {
|
||||||
|
self.values.clone()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn keys(&self) -> Vec<String> {
|
||||||
|
self.values.keys().cloned().collect()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn value(&self, key: &str) -> Option<String> {
|
||||||
|
let value = self.values.get(key);
|
||||||
|
if value.is_none() {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
return Some(value.unwrap().clone());
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn name_is_basic(&self) -> bool {
|
||||||
|
name_is_basic(&self.name)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_parent_names(&self) -> Vec<String> {
|
||||||
|
get_parent_names(&self.name)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_child_name(&self) -> String {
|
||||||
|
get_child_name(&self.name)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn copy_with_child_name(&self) -> Self {
|
||||||
|
let mut to_return: Self = self.clone();
|
||||||
|
to_return.name = self.get_child_name();
|
||||||
|
return to_return;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn copy_with_new_level(&self, level: DiagnosticLevel) -> Self {
|
||||||
|
let mut to_return: Self = self.clone();
|
||||||
|
to_return.level = level;
|
||||||
|
return to_return;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn copy_with_new_name(&self, name: String) -> Self {
|
||||||
|
let mut to_return = self.clone();
|
||||||
|
to_return.name = name;
|
||||||
|
return to_return;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn clean_name(name: &str) -> String {
|
||||||
|
// Remove prefix "/"
|
||||||
|
let without_prefix = name.strip_prefix("/").unwrap_or(name);
|
||||||
|
// and suffix
|
||||||
|
let without_suffix = name.strip_suffix("/").unwrap_or(without_prefix);
|
||||||
|
|
||||||
|
return without_suffix.to_owned();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn basic_diagnostic_creation() {
|
||||||
|
let level = DiagnosticLevel::OK;
|
||||||
|
let name = "/a/b/c";
|
||||||
|
let message = "I'm ok";
|
||||||
|
let hardware_id = "";
|
||||||
|
let values = BTreeMap::<String, String>::new();
|
||||||
|
|
||||||
|
let diag_status = DiagnosticStatus::new(
|
||||||
|
level,
|
||||||
|
name.to_owned(),
|
||||||
|
message.to_owned(),
|
||||||
|
hardware_id.to_owned(),
|
||||||
|
values,
|
||||||
|
);
|
||||||
|
assert!(diag_status.level() == DiagnosticLevel::OK);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn diagnostic_name_parsing() {
|
||||||
|
let level = DiagnosticLevel::OK;
|
||||||
|
let name = "/a/b/c";
|
||||||
|
let message = "I'm ok";
|
||||||
|
let hardware_id = "";
|
||||||
|
let values = BTreeMap::<String, String>::new();
|
||||||
|
|
||||||
|
let diag_status = DiagnosticStatus::new(
|
||||||
|
level,
|
||||||
|
name.to_owned(),
|
||||||
|
message.to_owned(),
|
||||||
|
hardware_id.to_owned(),
|
||||||
|
values,
|
||||||
|
);
|
||||||
|
|
||||||
|
assert!(!diag_status.name_is_basic());
|
||||||
|
|
||||||
|
let parent_names = diag_status.get_parent_names();
|
||||||
|
let child_name = diag_status.get_child_name();
|
||||||
|
assert!(parent_names[0] == "a");
|
||||||
|
assert!(parent_names[1] == "b");
|
||||||
|
assert!(child_name == "c");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn diagnostic_name_cleaning() {
|
||||||
|
let level = DiagnosticLevel::OK;
|
||||||
|
let name = "/a";
|
||||||
|
let message = "I'm ok";
|
||||||
|
let hardware_id = "";
|
||||||
|
let values = BTreeMap::<String, String>::new();
|
||||||
|
|
||||||
|
let diag_status = DiagnosticStatus::new(
|
||||||
|
level,
|
||||||
|
name.to_owned(),
|
||||||
|
message.to_owned(),
|
||||||
|
hardware_id.to_owned(),
|
||||||
|
values,
|
||||||
|
);
|
||||||
|
|
||||||
|
assert!(diag_status.name_is_basic());
|
||||||
|
assert!(diag_status.name() == "a");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,30 @@
|
||||||
|
//
|
||||||
|
// Copyright 2026 James Pace
|
||||||
|
//
|
||||||
|
// This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
// License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
// file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||||
|
//
|
||||||
|
// This Source Code Form is "Incompatible With Secondary Licenses", as
|
||||||
|
// defined by the Mozilla Public License, v. 2.0.
|
||||||
|
//
|
||||||
|
|
||||||
|
use alloc::string::{String, ToString};
|
||||||
|
|
||||||
|
#[derive(thiserror::Error, Debug)]
|
||||||
|
pub enum Error {
|
||||||
|
#[error("GraphError: {0}")]
|
||||||
|
GraphError(#[from] limbo_graph::Error),
|
||||||
|
#[error("serde_json Error: {0}")]
|
||||||
|
JsonError(#[from] serde_json::Error),
|
||||||
|
#[error("Error from j7s_diagnostics: {0}")]
|
||||||
|
Msg(String),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Error {
|
||||||
|
pub fn from_msg(msg: &str) -> Self {
|
||||||
|
Error::Msg(msg.to_string())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub type Result<T, E = Error> = core::result::Result<T, E>;
|
||||||
|
|
@ -0,0 +1,30 @@
|
||||||
|
//
|
||||||
|
// Copyright 2026 James Pace
|
||||||
|
//
|
||||||
|
// This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
// License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
// file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||||
|
//
|
||||||
|
// This Source Code Form is "Incompatible With Secondary Licenses", as
|
||||||
|
// defined by the Mozilla Public License, v. 2.0.
|
||||||
|
//
|
||||||
|
|
||||||
|
#![allow(unused_imports)]
|
||||||
|
#![cfg_attr(not(feature = "std"), no_std)]
|
||||||
|
|
||||||
|
extern crate alloc;
|
||||||
|
|
||||||
|
mod diagnostic_graph;
|
||||||
|
mod diagnostic_node;
|
||||||
|
mod diagnostic_status;
|
||||||
|
mod error;
|
||||||
|
mod name_parsing;
|
||||||
|
|
||||||
|
pub use crate::diagnostic_graph::*;
|
||||||
|
pub use crate::diagnostic_status::*;
|
||||||
|
pub use crate::error::*;
|
||||||
|
|
||||||
|
#[cfg(feature = "std")]
|
||||||
|
mod tree_view;
|
||||||
|
#[cfg(feature = "std")]
|
||||||
|
pub use crate::tree_view::*;
|
||||||
|
|
@ -0,0 +1,82 @@
|
||||||
|
//
|
||||||
|
// Copyright 2026 James Pace
|
||||||
|
//
|
||||||
|
// This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
// License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
// file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||||
|
//
|
||||||
|
// This Source Code Form is "Incompatible With Secondary Licenses", as
|
||||||
|
// defined by the Mozilla Public License, v. 2.0.
|
||||||
|
//
|
||||||
|
use alloc::borrow::ToOwned;
|
||||||
|
use alloc::string::String;
|
||||||
|
use alloc::vec::Vec;
|
||||||
|
|
||||||
|
pub fn name_is_basic(name: &String) -> bool {
|
||||||
|
// A basic name is one that doesn't have slashes in it other than the
|
||||||
|
// first character.
|
||||||
|
let is_not_basic = name.strip_prefix("/").unwrap_or(name).contains("/");
|
||||||
|
return !is_not_basic;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_parent_names(name: &String) -> Vec<String> {
|
||||||
|
if name_is_basic(&name) {
|
||||||
|
return Vec::<String>::new();
|
||||||
|
}
|
||||||
|
|
||||||
|
let split: Vec<String> = name
|
||||||
|
.split("/")
|
||||||
|
.map(|x| x.to_owned())
|
||||||
|
.filter(|x| !x.is_empty())
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
return split
|
||||||
|
.iter()
|
||||||
|
.take(split.len() - 1)
|
||||||
|
.map(|x| x.to_owned())
|
||||||
|
.collect();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_child_name(name: &String) -> String {
|
||||||
|
if name_is_basic(&name) {
|
||||||
|
return name.clone();
|
||||||
|
}
|
||||||
|
let split: Vec<String> = name.split("/").map(|x| x.to_owned()).collect();
|
||||||
|
return split.last().unwrap().clone();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn split_name(name: &String) -> Vec<String> {
|
||||||
|
name.split("/")
|
||||||
|
.map(|x| x.to_owned())
|
||||||
|
.filter(|x| !x.is_empty())
|
||||||
|
.collect()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_is_basic() {
|
||||||
|
assert!(name_is_basic(&"a".to_owned()));
|
||||||
|
assert!(name_is_basic(&"/a".to_owned()));
|
||||||
|
assert!(!name_is_basic(&"/a/b".to_owned()));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_get_names() {
|
||||||
|
let name = "/a/b/c";
|
||||||
|
|
||||||
|
let parent_names = get_parent_names(&name.to_owned());
|
||||||
|
assert!(parent_names[0] == "a");
|
||||||
|
assert!(parent_names[1] == "b");
|
||||||
|
|
||||||
|
let child_name = get_child_name(&name.to_owned());
|
||||||
|
assert!(child_name == "c");
|
||||||
|
|
||||||
|
let split = split_name(&name.to_owned());
|
||||||
|
assert!(split[0] == "a");
|
||||||
|
assert!(split[1] == "b");
|
||||||
|
assert!(split[2] == "c");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,118 @@
|
||||||
|
//
|
||||||
|
// Copyright 2026 James Pace
|
||||||
|
//
|
||||||
|
// This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
// License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
// file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||||
|
//
|
||||||
|
// This Source Code Form is "Incompatible With Secondary Licenses", as
|
||||||
|
// defined by the Mozilla Public License, v. 2.0.
|
||||||
|
//
|
||||||
|
use crate::diagnostic_graph::DiagnosticGraph;
|
||||||
|
use crate::diagnostic_status::DiagnosticStatus;
|
||||||
|
use crate::error::Result;
|
||||||
|
use alloc::string::String;
|
||||||
|
use alloc::vec::Vec;
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
|
#[derive(Clone, Serialize, Deserialize)]
|
||||||
|
pub struct TreeView {
|
||||||
|
children: Vec<TreeViewNode>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Serialize, Deserialize)]
|
||||||
|
struct TreeViewNode {
|
||||||
|
id: String,
|
||||||
|
status: DiagnosticStatus,
|
||||||
|
children: Vec<TreeViewNode>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TreeView {
|
||||||
|
fn get_nodes(key: &limbo_graph::Key, graph: &DiagnosticGraph) -> Result<Vec<TreeViewNode>> {
|
||||||
|
let children = graph.children_of(&key)?;
|
||||||
|
if children.len() == 0 {
|
||||||
|
return Ok(Vec::<TreeViewNode>::new());
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut to_ret = Vec::<TreeViewNode>::new();
|
||||||
|
|
||||||
|
for child in children {
|
||||||
|
let status = graph.value_of(&child)?;
|
||||||
|
let node = TreeViewNode {
|
||||||
|
id: graph.full_name_from_key(&child)?,
|
||||||
|
status: status,
|
||||||
|
children: Self::get_nodes(&child, &graph)?,
|
||||||
|
};
|
||||||
|
|
||||||
|
to_ret.push(node);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Make the order of same id'd (named) entries consistent.
|
||||||
|
to_ret.sort_by(|a, b| a.id.cmp(&b.id));
|
||||||
|
|
||||||
|
return Ok(to_ret);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn from_graph(graph: &DiagnosticGraph) -> Result<TreeView> {
|
||||||
|
let view = TreeView {
|
||||||
|
children: Self::get_nodes(&graph.root(), &graph)?,
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok(view)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn to_json(&self) -> Result<String> {
|
||||||
|
Ok(serde_json::to_string(self)?)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
use crate::*;
|
||||||
|
use alloc::collections::BTreeMap;
|
||||||
|
|
||||||
|
fn make_a_status_with_name(name: &str) -> DiagnosticStatus {
|
||||||
|
let level = DiagnosticLevel::OK;
|
||||||
|
let message = "I'm ok";
|
||||||
|
let hardware_id = "";
|
||||||
|
let values = BTreeMap::<String, String>::new();
|
||||||
|
|
||||||
|
DiagnosticStatus::new(
|
||||||
|
level,
|
||||||
|
name.to_owned(),
|
||||||
|
message.to_owned(),
|
||||||
|
hardware_id.to_owned(),
|
||||||
|
values,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn make_view() -> Result<()> {
|
||||||
|
let statuses = vec![
|
||||||
|
make_a_status_with_name("/a"),
|
||||||
|
make_a_status_with_name("/a/b"),
|
||||||
|
make_a_status_with_name("/a/b/c"),
|
||||||
|
make_a_status_with_name("/a/d/e"),
|
||||||
|
make_a_status_with_name("/a/d"),
|
||||||
|
];
|
||||||
|
|
||||||
|
let mut graph = DiagnosticGraph::new();
|
||||||
|
graph.add_status_vec(&statuses)?;
|
||||||
|
|
||||||
|
let view = TreeView::from_graph(&graph)?;
|
||||||
|
|
||||||
|
// First level is just a
|
||||||
|
assert!(view.children.len() == 1);
|
||||||
|
// a has children b and d.
|
||||||
|
assert!(view.children[0].children.len() == 2);
|
||||||
|
// regardless is this is b or d, it has one child.
|
||||||
|
// TODO: This isn't the best test.
|
||||||
|
assert!(view.children[0].children[0].children.len() == 1);
|
||||||
|
|
||||||
|
// Just to confirm it doesn't panic.
|
||||||
|
let _js = view.to_json()?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
File diff suppressed because one or more lines are too long
|
|
@ -0,0 +1,6 @@
|
||||||
|
{
|
||||||
|
"git": {
|
||||||
|
"sha1": "ef0906e20828777175f65caa7e681a0ce33c559a"
|
||||||
|
},
|
||||||
|
"path_in_vcs": ""
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,7 @@
|
||||||
|
[*.sh]
|
||||||
|
# See https://github.com/mvdan/sh/blob/master/cmd/shfmt/shfmt.1.scd#examples
|
||||||
|
indent_style = space
|
||||||
|
indent_size = 4
|
||||||
|
|
||||||
|
switch_case_indent = true
|
||||||
|
space_redirects = true
|
||||||
|
|
@ -0,0 +1,6 @@
|
||||||
|
# Format macro bodies
|
||||||
|
50f26e08e146b7e9c7d1af9614486eba327d1e31
|
||||||
|
|
||||||
|
# Automated changes related to the 2021 edition upgrade
|
||||||
|
643182f7da26cedb09349b8bb3735c2e58ba24e6
|
||||||
|
108310db03e7db35ef48a902d9ce9a88ab8f9b77
|
||||||
|
|
@ -0,0 +1,49 @@
|
||||||
|
[workspace]
|
||||||
|
git_release_name = "{{ version }}"
|
||||||
|
git_tag_name = "{{ version }}"
|
||||||
|
|
||||||
|
[changelog]
|
||||||
|
body = """
|
||||||
|
## [{{ version | trim_start_matches(pat="v") }}]\
|
||||||
|
{%- if release_link -%}\
|
||||||
|
({{ release_link }})\
|
||||||
|
{% endif %} \
|
||||||
|
- {{ timestamp | date(format="%Y-%m-%d") }}
|
||||||
|
{% for group, commits in commits | group_by(attribute="group") %}
|
||||||
|
### {{ group | upper_first }}
|
||||||
|
{% for commit in commits %}
|
||||||
|
- {% if commit.scope -%}{{ commit.scope | upper_first }}: {% endif %}
|
||||||
|
{%- if commit.breaking %}[**breaking**] {% endif %}
|
||||||
|
{{- commit.message }}
|
||||||
|
{%- if commit.links %} ([{{ commit.links.1.text }}]({{ commit.links.1.href }})){% endif -%}
|
||||||
|
{% endfor %}
|
||||||
|
{% endfor %}
|
||||||
|
{%- if github -%}
|
||||||
|
{% if github.contributors | filter(attribute="is_first_time", value=true) | length != 0 %}
|
||||||
|
## New Contributors ❤️
|
||||||
|
{% endif %}\
|
||||||
|
{% for contributor in github.contributors | filter(attribute="is_first_time", value=true) %}
|
||||||
|
* @{{ contributor.username }} made their first contribution
|
||||||
|
{%- if contributor.pr_number %} in \
|
||||||
|
[#{{ contributor.pr_number }}]({{ self::remote_url() }}/pull/{{ contributor.pr_number }}) \
|
||||||
|
{%- endif %}
|
||||||
|
{%- endfor -%}
|
||||||
|
{%- endif %}
|
||||||
|
"""
|
||||||
|
|
||||||
|
commit_parsers = [
|
||||||
|
{ message = '(?i)^(\w+: )?feat', group = "added" },
|
||||||
|
{ message = '(?i)^(\w+: )?add', group = "added" },
|
||||||
|
{ message = '(?i)^(\w+: )?change', group = "changed" },
|
||||||
|
{ message = '(?i)^(\w+: )?cleanup', group = "cleanup" },
|
||||||
|
{ message = '(?i)^(\w+: )?deprecate', group = "deprecated" },
|
||||||
|
{ message = '(?i)^(\w+: )?remove', group = "removed" },
|
||||||
|
{ message = '(?i)^(\w+: )?fix', group = "fixed" },
|
||||||
|
{ message = '(?i)^(\w+: )?fix', group = "fixed" },
|
||||||
|
{ message = '^.*', group = "other" },
|
||||||
|
]
|
||||||
|
|
||||||
|
link_parsers = [
|
||||||
|
# Extract backport patterns
|
||||||
|
{ pattern = '\(backport <.*/(\d+)>\)', text = "#$1", href = "https://github.com/rust-lang/libc/pull/$1"}
|
||||||
|
]
|
||||||
|
|
@ -0,0 +1,6 @@
|
||||||
|
edition = "2021"
|
||||||
|
error_on_line_overflow = true
|
||||||
|
group_imports = "StdExternalCrate"
|
||||||
|
imports_granularity = "Module"
|
||||||
|
# This crate gets large lists of reexports. Use vertical to reduce conflicts.
|
||||||
|
imports_layout = "Vertical"
|
||||||
File diff suppressed because it is too large
Load Diff
|
|
@ -0,0 +1,152 @@
|
||||||
|
# Contributing to `libc`
|
||||||
|
|
||||||
|
Welcome! If you are reading this document, it means you are interested in
|
||||||
|
contributing to the `libc` crate.
|
||||||
|
|
||||||
|
## v1.0 Roadmap
|
||||||
|
|
||||||
|
`libc` has two active branches: `main` and `libc-0.2`. `main` is for active
|
||||||
|
development of the upcoming v1.0 release, and should be the target of all pull
|
||||||
|
requests. `libc-0.2` is for updates to the currently released version.
|
||||||
|
|
||||||
|
If a pull request to `main` is a good candidate for inclusion in an `0.2.x`
|
||||||
|
release, include `@rustbot label stable-nominated` in a comment to propose this.
|
||||||
|
Almost everything should be included in stable, unless it involves breaking
|
||||||
|
changes.
|
||||||
|
|
||||||
|
Once a `stable-nominated` PR targeting `main` has merged, it can be cherry
|
||||||
|
picked to the `libc-0.2` branch. A maintainer will likely do these cherry picks
|
||||||
|
in a batch before a release, so there is no need for any action as a PR author.
|
||||||
|
|
||||||
|
When cherry picking, run the following after branching from `libc-0.2`:
|
||||||
|
`git cherry-pick -xe commit-sha-on-main` (or `git cherry-pick -xe
|
||||||
|
start-sha^..end-sha` if a range of commits is needed). `git` will automatically
|
||||||
|
add the "cherry picked from commit" note, but try to add a backport note so the
|
||||||
|
original PR gets crosslinked:
|
||||||
|
|
||||||
|
```
|
||||||
|
# ... original commit message ...
|
||||||
|
|
||||||
|
(backport <https://github.com/rust-lang/libc/pull/1234>) # add manually
|
||||||
|
(cherry picked from commit 104b6a4ae31c726814c36318dc718470cc96e167) # added by git
|
||||||
|
```
|
||||||
|
|
||||||
|
Cherry pick PRs can then target `libc-0.2`.
|
||||||
|
|
||||||
|
See the [tracking issue](https://github.com/rust-lang/libc/issues/3248) for
|
||||||
|
details.
|
||||||
|
|
||||||
|
## Adding an API
|
||||||
|
|
||||||
|
Want to use an API which currently isn't bound in `libc`? It's quite easy to add
|
||||||
|
one!
|
||||||
|
|
||||||
|
If you are adding API for a header that doesn't already have some bindings,
|
||||||
|
create a new file in the appropriate location in `src/new`. These modules should
|
||||||
|
approximately match source trees: try to follow the patterns that are there but
|
||||||
|
don't hesitate to ask maintainers if guidance is needed.
|
||||||
|
|
||||||
|
If some bindings for the relevant header has already been added outside of
|
||||||
|
`src/new`, it is fine to extend what already exists. Everything outside of
|
||||||
|
`src/new` uses a hierarchial structure: a single path from root to a leaf node
|
||||||
|
represents a single platform, and adding API at a given level will make it
|
||||||
|
available on all children.
|
||||||
|
|
||||||
|
We are currently in a reorganization process, moving from the hierarchial
|
||||||
|
structure to the source-mapped structure in `src/new`.
|
||||||
|
|
||||||
|
New items (i.e. functions, constants etc.) should also be added to the symbol
|
||||||
|
list(s) found in the `libc-test/semver` directory. These lists track of what
|
||||||
|
API is public in the libc crate and ensures they remain available between
|
||||||
|
changes to the crate. If the new symbol(s) are available on all supported Unixes
|
||||||
|
it should be added to `unix.txt` list[^1], otherwise they should be added to the
|
||||||
|
OS-specific list(s).
|
||||||
|
|
||||||
|
With that in mind, the steps for adding a new API are:
|
||||||
|
|
||||||
|
1. Determine where to add your API.
|
||||||
|
2. Add the API, including adding new symbol(s) to the semver lists.
|
||||||
|
3. Send a PR to this repo.
|
||||||
|
4. Wait for CI to pass, fixing errors.
|
||||||
|
5. Wait for a merge!
|
||||||
|
|
||||||
|
[^1]: Note that this list has nothing to do with any Unix or Posix standard,
|
||||||
|
it's just a list shared among all OSs that declare `#[cfg(unix)]`.
|
||||||
|
|
||||||
|
## Test before you commit
|
||||||
|
|
||||||
|
There are a few relevant tests in `libc`:
|
||||||
|
|
||||||
|
1. `libc-test` is the main test suite. This can be run locally with `cargo test
|
||||||
|
--workspace`.
|
||||||
|
|
||||||
|
If needed, the `skip_*()` functions in `libc-test/build.rs` can be used to
|
||||||
|
skip testing specific API.
|
||||||
|
2. Style checker and formatter, located at [`./ci/style.py`][style-py]. Running
|
||||||
|
this also invokes the code formatter. (This also formats code within macros,
|
||||||
|
which `cargo fmt` won't do.)
|
||||||
|
3. `ci/verify-build.py`, which checks the build on a wide range of targets.
|
||||||
|
Typically there is no need to run this locally.
|
||||||
|
|
||||||
|
[style-py]: https://github.com/rust-lang/libc/blob/main/ci/style.py
|
||||||
|
|
||||||
|
## Submitting a Pull Request
|
||||||
|
|
||||||
|
When you submit a PR, please follow these guidelines to give your PR the best
|
||||||
|
chance of being accepted:
|
||||||
|
|
||||||
|
1. All new API should be added to `libc-test/semver`, which makes sure it
|
||||||
|
doesn't get removed in the future.
|
||||||
|
2. All changes *must* have permalink to headers in commit messages. See
|
||||||
|
[Source links](#source-links) below for more details.
|
||||||
|
3. For any constants that are expected to change, e.g. `*LAST` or `*MAX`, try to
|
||||||
|
add the following doc comment:
|
||||||
|
|
||||||
|
```rust
|
||||||
|
/// Constants may change across releases. See the [usage guidelines](crate#usage-guidelines)
|
||||||
|
/// for details.
|
||||||
|
```
|
||||||
|
5. Run tests locally, following the directions at
|
||||||
|
[Test before you commit](test-before-you-commit). This is especially relevant
|
||||||
|
for platforms that aren't tested on CI.
|
||||||
|
|
||||||
|
### Source links
|
||||||
|
|
||||||
|
Please include permalinks to headers in commit messages for all API changes.
|
||||||
|
Common sources include:
|
||||||
|
|
||||||
|
* Linux uapi: https://github.com/torvalds/linux/tree/master/include/uapi
|
||||||
|
* Glibc: https://sourceware.org/git/?p=glibc.git;a=tree
|
||||||
|
* Musl: https://github.com/kraj/musl (original is https://git.musl-libc.org/cgit/musl/tree/)
|
||||||
|
* Apple XNU: https://github.com/apple-oss-distributions/xnu, libc https://github.com/apple-oss-distributions/Libc/tree/main/include
|
||||||
|
* Android: https://cs.android.com/android/platform/superproject/main
|
||||||
|
* FreeBSD: https://github.com/freebsd/freebsd-src/tree/main/lib/libc
|
||||||
|
* Illumos: https://github.com/illumos/illumos-gate/tree/master/usr/src/lib/libc
|
||||||
|
* Fuchsia: https://cs.opensource.google/fuchsia/fuchsia/+/main:zircon/
|
||||||
|
|
||||||
|
After navigating to the relevant file and selecting relevant lines, get a
|
||||||
|
permalink. On GitHub this is available by clicking the triple dots and
|
||||||
|
selecting "copy permalink", and on the Android and Fuchsia source viewers
|
||||||
|
this is available via l-r (links->commit).
|
||||||
|
|
||||||
|
If sources are closed, link to documentation or paste relevant C declarations.
|
||||||
|
|
||||||
|
(Including this information in the PR description is fine too, commit messages
|
||||||
|
are preferred because they become part of history.)
|
||||||
|
|
||||||
|
## Breaking change policy
|
||||||
|
|
||||||
|
See `src/lib.rs` for details.
|
||||||
|
|
||||||
|
## Supported target policy
|
||||||
|
|
||||||
|
When Rust removes a support for a target, the libc crate also may remove the
|
||||||
|
support at any time. MSRV may be different for different targets.
|
||||||
|
|
||||||
|
## Releasing change to crates.io
|
||||||
|
|
||||||
|
This repository uses [release-plz] to handle releases. Once your pull request
|
||||||
|
has been merged, a maintainer needs to create the changelog and merge a PR
|
||||||
|
bumping the version. This will automatically publish to crates.io!
|
||||||
|
|
||||||
|
[release-plz]: https://github.com/MarcoIeni/release-plz
|
||||||
|
|
@ -0,0 +1,16 @@
|
||||||
|
# This file is automatically @generated by Cargo.
|
||||||
|
# It is not intended for manual editing.
|
||||||
|
version = 3
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "libc"
|
||||||
|
version = "0.2.189"
|
||||||
|
dependencies = [
|
||||||
|
"rustc-std-workspace-core",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rustc-std-workspace-core"
|
||||||
|
version = "1.0.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "aa9c45b374136f52f2d6311062c7146bff20fec063c3f5d46a410bd937746955"
|
||||||
|
|
@ -0,0 +1,225 @@
|
||||||
|
# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO
|
||||||
|
#
|
||||||
|
# When uploading crates to the registry Cargo will automatically
|
||||||
|
# "normalize" Cargo.toml files for maximal compatibility
|
||||||
|
# with all versions of Cargo and also rewrite `path` dependencies
|
||||||
|
# to registry (e.g., crates.io) dependencies.
|
||||||
|
#
|
||||||
|
# If you are reading this file be aware that the original Cargo.toml
|
||||||
|
# will likely look very different (and much more reasonable).
|
||||||
|
# See Cargo.toml.orig for the original contents.
|
||||||
|
|
||||||
|
[package]
|
||||||
|
edition = "2021"
|
||||||
|
rust-version = "1.65"
|
||||||
|
name = "libc"
|
||||||
|
version = "0.2.189"
|
||||||
|
build = "build.rs"
|
||||||
|
exclude = [
|
||||||
|
"/ci/*",
|
||||||
|
"/.github/*",
|
||||||
|
"/triagebot.toml",
|
||||||
|
"cherry-pick-stable.sh",
|
||||||
|
]
|
||||||
|
autolib = false
|
||||||
|
autobins = false
|
||||||
|
autoexamples = false
|
||||||
|
autotests = false
|
||||||
|
autobenches = false
|
||||||
|
description = "Raw FFI bindings to platform libraries like libc."
|
||||||
|
readme = "README.md"
|
||||||
|
keywords = [
|
||||||
|
"libc",
|
||||||
|
"ffi",
|
||||||
|
"bindings",
|
||||||
|
"operating",
|
||||||
|
"system",
|
||||||
|
]
|
||||||
|
categories = [
|
||||||
|
"external-ffi-bindings",
|
||||||
|
"no-std",
|
||||||
|
"os",
|
||||||
|
]
|
||||||
|
license = "MIT OR Apache-2.0"
|
||||||
|
repository = "https://github.com/rust-lang/libc"
|
||||||
|
|
||||||
|
[package.metadata.docs.rs]
|
||||||
|
features = ["extra_traits"]
|
||||||
|
default-target = "x86_64-unknown-linux-gnu"
|
||||||
|
targets = [
|
||||||
|
"aarch64-apple-darwin",
|
||||||
|
"aarch64-pc-windows-msvc",
|
||||||
|
"aarch64-unknown-linux-gnu",
|
||||||
|
"i686-pc-windows-msvc",
|
||||||
|
"i686-unknown-linux-gnu",
|
||||||
|
"x86_64-pc-windows-gnu",
|
||||||
|
"x86_64-pc-windows-msvc",
|
||||||
|
"x86_64-unknown-linux-gnu",
|
||||||
|
"aarch64-pc-windows-gnullvm",
|
||||||
|
"aarch64-unknown-linux-musl",
|
||||||
|
"aarch64-unknown-linux-ohos",
|
||||||
|
"arm-unknown-linux-gnueabi",
|
||||||
|
"arm-unknown-linux-gnueabihf",
|
||||||
|
"armv7-unknown-linux-gnueabihf",
|
||||||
|
"armv7-unknown-linux-ohos",
|
||||||
|
"i686-pc-windows-gnu",
|
||||||
|
"loongarch64-unknown-linux-gnu",
|
||||||
|
"loongarch64-unknown-linux-musl",
|
||||||
|
"powerpc-unknown-linux-gnu",
|
||||||
|
"powerpc64-unknown-linux-gnu",
|
||||||
|
"powerpc64-unknown-linux-musl",
|
||||||
|
"powerpc64le-unknown-linux-gnu",
|
||||||
|
"powerpc64le-unknown-linux-musl",
|
||||||
|
"riscv64gc-unknown-linux-gnu",
|
||||||
|
"s390x-unknown-linux-gnu",
|
||||||
|
"sparcv9-sun-solaris",
|
||||||
|
"x86_64-apple-darwin",
|
||||||
|
"x86_64-pc-solaris",
|
||||||
|
"x86_64-pc-windows-gnullvm",
|
||||||
|
"x86_64-unknown-freebsd",
|
||||||
|
"x86_64-unknown-illumos",
|
||||||
|
"x86_64-unknown-linux-musl",
|
||||||
|
"x86_64-unknown-linux-ohos",
|
||||||
|
"x86_64-unknown-netbsd",
|
||||||
|
"aarch64-apple-ios",
|
||||||
|
"aarch64-apple-tvos",
|
||||||
|
"aarch64-apple-visionos",
|
||||||
|
"aarch64-apple-watchos",
|
||||||
|
"aarch64-linux-android",
|
||||||
|
"aarch64-unknown-fuchsia",
|
||||||
|
"arm-linux-androideabi",
|
||||||
|
"arm-unknown-linux-musleabi",
|
||||||
|
"arm-unknown-linux-musleabihf",
|
||||||
|
"arm64ec-pc-windows-msvc",
|
||||||
|
"armv5te-unknown-linux-gnueabi",
|
||||||
|
"armv5te-unknown-linux-musleabi",
|
||||||
|
"armv7-linux-androideabi",
|
||||||
|
"armv7-unknown-linux-musleabihf",
|
||||||
|
"i586-unknown-linux-gnu",
|
||||||
|
"i586-unknown-linux-musl",
|
||||||
|
"i686-linux-android",
|
||||||
|
"i686-unknown-freebsd",
|
||||||
|
"i686-unknown-linux-musl",
|
||||||
|
"nvptx64-nvidia-cuda",
|
||||||
|
"riscv64gc-unknown-linux-musl",
|
||||||
|
"sparc64-unknown-linux-gnu",
|
||||||
|
"thumbv7neon-linux-androideabi",
|
||||||
|
"thumbv7neon-unknown-linux-gnueabihf",
|
||||||
|
"wasm32-unknown-emscripten",
|
||||||
|
"wasm32-unknown-unknown",
|
||||||
|
"wasm32-wasip1",
|
||||||
|
"wasm32-wasip2",
|
||||||
|
"x86_64-fortanix-unknown-sgx",
|
||||||
|
"x86_64-linux-android",
|
||||||
|
"x86_64-unknown-fuchsia",
|
||||||
|
"x86_64-unknown-linux-gnux32",
|
||||||
|
"x86_64-unknown-redox",
|
||||||
|
"aarch64-unknown-freebsd",
|
||||||
|
"aarch64-unknown-hermit",
|
||||||
|
"aarch64-unknown-illumos",
|
||||||
|
"aarch64-unknown-netbsd",
|
||||||
|
"aarch64-unknown-qnx",
|
||||||
|
"aarch64-unknown-openbsd",
|
||||||
|
"aarch64-unknown-redox",
|
||||||
|
"aarch64-wrs-vxworks",
|
||||||
|
"aarch64_be-unknown-linux-gnu",
|
||||||
|
"aarch64_be-unknown-linux-musl",
|
||||||
|
"armebv7r-none-eabi",
|
||||||
|
"armebv7r-none-eabihf",
|
||||||
|
"armv7-linux-androideabi",
|
||||||
|
"armv7-wrs-vxworks-eabihf",
|
||||||
|
"armv7r-none-eabi",
|
||||||
|
"armv7r-none-eabihf",
|
||||||
|
"hexagon-unknown-linux-musl",
|
||||||
|
"i686-unknown-haiku",
|
||||||
|
"i686-unknown-netbsd",
|
||||||
|
"i686-unknown-openbsd",
|
||||||
|
"i686-wrs-vxworks",
|
||||||
|
"mips-unknown-linux-gnu",
|
||||||
|
"mips-unknown-linux-musl",
|
||||||
|
"mips64-unknown-linux-gnuabi64",
|
||||||
|
"mips64-unknown-linux-muslabi64",
|
||||||
|
"mips64el-unknown-linux-gnuabi64",
|
||||||
|
"mips64el-unknown-linux-muslabi64",
|
||||||
|
"mipsel-sony-psp",
|
||||||
|
"mipsel-unknown-linux-gnu",
|
||||||
|
"mipsel-unknown-linux-musl",
|
||||||
|
"powerpc-unknown-linux-gnuspe",
|
||||||
|
"powerpc-unknown-netbsd",
|
||||||
|
"powerpc-wrs-vxworks",
|
||||||
|
"powerpc-wrs-vxworks-spe",
|
||||||
|
"powerpc64-ibm-aix",
|
||||||
|
"powerpc64-unknown-freebsd",
|
||||||
|
"powerpc64-unknown-linux-gnu",
|
||||||
|
"powerpc64-wrs-vxworks",
|
||||||
|
"riscv32-wrs-vxworks",
|
||||||
|
"riscv32gc-unknown-linux-musl",
|
||||||
|
"riscv32i-unknown-none-elf",
|
||||||
|
"riscv32imac-unknown-none-elf",
|
||||||
|
"riscv32imc-unknown-none-elf",
|
||||||
|
"riscv64-wrs-vxworks",
|
||||||
|
"riscv64gc-unknown-freebsd",
|
||||||
|
"riscv64gc-unknown-hermit",
|
||||||
|
"riscv64gc-unknown-none-elf",
|
||||||
|
"riscv64imac-unknown-none-elf",
|
||||||
|
"s390x-unknown-linux-musl",
|
||||||
|
"sparc-unknown-linux-gnu",
|
||||||
|
"sparc64-unknown-netbsd",
|
||||||
|
"thumbv6m-none-eabi",
|
||||||
|
"thumbv7em-none-eabi",
|
||||||
|
"thumbv7em-none-eabihf",
|
||||||
|
"thumbv7m-none-eabi",
|
||||||
|
"wasm32-wasip3",
|
||||||
|
"x86_64-apple-ios",
|
||||||
|
"x86_64-pc-cygwin",
|
||||||
|
"x86_64-unknown-dragonfly",
|
||||||
|
"x86_64-unknown-haiku",
|
||||||
|
"x86_64-unknown-hermit",
|
||||||
|
"x86_64-unknown-hurd-gnu",
|
||||||
|
"x86_64-unknown-l4re-uclibc",
|
||||||
|
"x86_64-unknown-openbsd",
|
||||||
|
"x86_64-wrs-vxworks",
|
||||||
|
]
|
||||||
|
cargo-args = ["-Zbuild-std=core"]
|
||||||
|
|
||||||
|
[package.metadata.cargo-semver-checks.lints]
|
||||||
|
repr_align_removed = "warn"
|
||||||
|
global_value_marked_deprecated = "warn"
|
||||||
|
|
||||||
|
[features]
|
||||||
|
align = []
|
||||||
|
const-extern-fn = []
|
||||||
|
default = ["std"]
|
||||||
|
extra_traits = []
|
||||||
|
rustc-dep-of-std = [
|
||||||
|
"align",
|
||||||
|
"rustc-std-workspace-core",
|
||||||
|
]
|
||||||
|
std = []
|
||||||
|
use_std = ["std"]
|
||||||
|
|
||||||
|
[lib]
|
||||||
|
name = "libc"
|
||||||
|
path = "src/lib.rs"
|
||||||
|
|
||||||
|
[[test]]
|
||||||
|
name = "const_fn"
|
||||||
|
path = "tests/const_fn.rs"
|
||||||
|
|
||||||
|
[dependencies.rustc-std-workspace-core]
|
||||||
|
version = "1.0.1"
|
||||||
|
optional = true
|
||||||
|
|
||||||
|
[lints.clippy]
|
||||||
|
explicit_iter_loop = "warn"
|
||||||
|
identity_op = "allow"
|
||||||
|
manual_assert = "warn"
|
||||||
|
map_unwrap_or = "warn"
|
||||||
|
missing_safety_doc = "allow"
|
||||||
|
non_minimal_cfg = "allow"
|
||||||
|
ptr_as_ptr = "warn"
|
||||||
|
unnecessary_cast = "allow"
|
||||||
|
unnecessary_semicolon = "warn"
|
||||||
|
|
||||||
|
[lints.rust]
|
||||||
|
unused_qualifications = "allow"
|
||||||
|
|
@ -0,0 +1,214 @@
|
||||||
|
[package]
|
||||||
|
name = "libc"
|
||||||
|
version = "0.2.189"
|
||||||
|
keywords = ["libc", "ffi", "bindings", "operating", "system"]
|
||||||
|
categories = ["external-ffi-bindings", "no-std", "os"]
|
||||||
|
exclude = ["/ci/*", "/.github/*", "/triagebot.toml", "cherry-pick-stable.sh"]
|
||||||
|
description = "Raw FFI bindings to platform libraries like libc."
|
||||||
|
edition = "2021"
|
||||||
|
license = "MIT OR Apache-2.0"
|
||||||
|
repository = "https://github.com/rust-lang/libc"
|
||||||
|
rust-version = "1.65"
|
||||||
|
|
||||||
|
[package.metadata.docs.rs]
|
||||||
|
features = ["extra_traits"]
|
||||||
|
default-target = "x86_64-unknown-linux-gnu"
|
||||||
|
targets = [
|
||||||
|
# Note: Keep this in sync with ci/verify-build.py
|
||||||
|
#
|
||||||
|
# Tier 1
|
||||||
|
"aarch64-apple-darwin",
|
||||||
|
"aarch64-pc-windows-msvc",
|
||||||
|
"aarch64-unknown-linux-gnu",
|
||||||
|
"i686-pc-windows-msvc",
|
||||||
|
"i686-unknown-linux-gnu",
|
||||||
|
"x86_64-pc-windows-gnu",
|
||||||
|
"x86_64-pc-windows-msvc",
|
||||||
|
"x86_64-unknown-linux-gnu",
|
||||||
|
#
|
||||||
|
# Tier 2 with host tools
|
||||||
|
"aarch64-pc-windows-gnullvm",
|
||||||
|
"aarch64-unknown-linux-musl",
|
||||||
|
"aarch64-unknown-linux-ohos",
|
||||||
|
"arm-unknown-linux-gnueabi",
|
||||||
|
"arm-unknown-linux-gnueabihf",
|
||||||
|
"armv7-unknown-linux-gnueabihf",
|
||||||
|
"armv7-unknown-linux-ohos",
|
||||||
|
"i686-pc-windows-gnu",
|
||||||
|
"loongarch64-unknown-linux-gnu",
|
||||||
|
"loongarch64-unknown-linux-musl",
|
||||||
|
"powerpc-unknown-linux-gnu",
|
||||||
|
"powerpc64-unknown-linux-gnu",
|
||||||
|
"powerpc64-unknown-linux-musl",
|
||||||
|
"powerpc64le-unknown-linux-gnu",
|
||||||
|
"powerpc64le-unknown-linux-musl",
|
||||||
|
"riscv64gc-unknown-linux-gnu",
|
||||||
|
"s390x-unknown-linux-gnu",
|
||||||
|
"sparcv9-sun-solaris",
|
||||||
|
"x86_64-apple-darwin",
|
||||||
|
"x86_64-pc-solaris",
|
||||||
|
"x86_64-pc-windows-gnullvm",
|
||||||
|
"x86_64-unknown-freebsd",
|
||||||
|
"x86_64-unknown-illumos",
|
||||||
|
"x86_64-unknown-linux-musl",
|
||||||
|
"x86_64-unknown-linux-ohos",
|
||||||
|
"x86_64-unknown-netbsd",
|
||||||
|
#
|
||||||
|
# Tier 2 without host tools
|
||||||
|
"aarch64-apple-ios",
|
||||||
|
"aarch64-apple-tvos",
|
||||||
|
"aarch64-apple-visionos",
|
||||||
|
"aarch64-apple-watchos",
|
||||||
|
"aarch64-linux-android",
|
||||||
|
"aarch64-unknown-fuchsia",
|
||||||
|
"arm-linux-androideabi",
|
||||||
|
"arm-unknown-linux-musleabi",
|
||||||
|
"arm-unknown-linux-musleabihf",
|
||||||
|
"arm64ec-pc-windows-msvc",
|
||||||
|
"armv5te-unknown-linux-gnueabi",
|
||||||
|
"armv5te-unknown-linux-musleabi",
|
||||||
|
"armv7-linux-androideabi",
|
||||||
|
"armv7-unknown-linux-musleabihf",
|
||||||
|
"i586-unknown-linux-gnu",
|
||||||
|
"i586-unknown-linux-musl",
|
||||||
|
"i686-linux-android",
|
||||||
|
"i686-unknown-freebsd",
|
||||||
|
"i686-unknown-linux-musl",
|
||||||
|
"nvptx64-nvidia-cuda",
|
||||||
|
"riscv64gc-unknown-linux-musl",
|
||||||
|
"sparc64-unknown-linux-gnu",
|
||||||
|
"thumbv7neon-linux-androideabi",
|
||||||
|
"thumbv7neon-unknown-linux-gnueabihf",
|
||||||
|
"wasm32-unknown-emscripten",
|
||||||
|
"wasm32-unknown-unknown",
|
||||||
|
"wasm32-wasip1",
|
||||||
|
"wasm32-wasip2",
|
||||||
|
"x86_64-fortanix-unknown-sgx",
|
||||||
|
"x86_64-linux-android",
|
||||||
|
"x86_64-unknown-fuchsia",
|
||||||
|
"x86_64-unknown-linux-gnux32",
|
||||||
|
"x86_64-unknown-redox",
|
||||||
|
#
|
||||||
|
# Tier 3 targets that are distinct enough to be useful, or have historically
|
||||||
|
# been documented.
|
||||||
|
"aarch64-unknown-freebsd",
|
||||||
|
"aarch64-unknown-hermit",
|
||||||
|
"aarch64-unknown-illumos",
|
||||||
|
"aarch64-unknown-netbsd",
|
||||||
|
"aarch64-unknown-qnx",
|
||||||
|
"aarch64-unknown-openbsd",
|
||||||
|
"aarch64-unknown-redox",
|
||||||
|
"aarch64-wrs-vxworks",
|
||||||
|
"aarch64_be-unknown-linux-gnu",
|
||||||
|
"aarch64_be-unknown-linux-musl",
|
||||||
|
"armebv7r-none-eabi",
|
||||||
|
"armebv7r-none-eabihf",
|
||||||
|
"armv7-linux-androideabi",
|
||||||
|
"armv7-wrs-vxworks-eabihf",
|
||||||
|
"armv7r-none-eabi",
|
||||||
|
"armv7r-none-eabihf",
|
||||||
|
"hexagon-unknown-linux-musl",
|
||||||
|
"i686-unknown-haiku",
|
||||||
|
"i686-unknown-netbsd",
|
||||||
|
"i686-unknown-openbsd",
|
||||||
|
"i686-wrs-vxworks",
|
||||||
|
"mips-unknown-linux-gnu",
|
||||||
|
"mips-unknown-linux-musl",
|
||||||
|
"mips64-unknown-linux-gnuabi64",
|
||||||
|
"mips64-unknown-linux-muslabi64",
|
||||||
|
"mips64el-unknown-linux-gnuabi64",
|
||||||
|
"mips64el-unknown-linux-muslabi64",
|
||||||
|
"mipsel-sony-psp",
|
||||||
|
"mipsel-unknown-linux-gnu",
|
||||||
|
"mipsel-unknown-linux-musl",
|
||||||
|
"powerpc-unknown-linux-gnuspe",
|
||||||
|
"powerpc-unknown-netbsd",
|
||||||
|
"powerpc-wrs-vxworks",
|
||||||
|
"powerpc-wrs-vxworks-spe",
|
||||||
|
"powerpc64-ibm-aix",
|
||||||
|
"powerpc64-unknown-freebsd",
|
||||||
|
"powerpc64-unknown-linux-gnu",
|
||||||
|
"powerpc64-wrs-vxworks",
|
||||||
|
"riscv32-wrs-vxworks",
|
||||||
|
"riscv32gc-unknown-linux-musl",
|
||||||
|
"riscv32i-unknown-none-elf",
|
||||||
|
"riscv32imac-unknown-none-elf",
|
||||||
|
"riscv32imc-unknown-none-elf",
|
||||||
|
"riscv64-wrs-vxworks",
|
||||||
|
"riscv64gc-unknown-freebsd",
|
||||||
|
"riscv64gc-unknown-hermit",
|
||||||
|
"riscv64gc-unknown-none-elf",
|
||||||
|
"riscv64imac-unknown-none-elf",
|
||||||
|
"s390x-unknown-linux-musl",
|
||||||
|
"sparc-unknown-linux-gnu",
|
||||||
|
"sparc64-unknown-netbsd",
|
||||||
|
"thumbv6m-none-eabi",
|
||||||
|
"thumbv7em-none-eabi",
|
||||||
|
"thumbv7em-none-eabihf",
|
||||||
|
"thumbv7m-none-eabi",
|
||||||
|
"wasm32-wasip3",
|
||||||
|
"x86_64-apple-ios",
|
||||||
|
"x86_64-pc-cygwin",
|
||||||
|
"x86_64-unknown-dragonfly",
|
||||||
|
"x86_64-unknown-haiku",
|
||||||
|
"x86_64-unknown-hermit",
|
||||||
|
"x86_64-unknown-hurd-gnu",
|
||||||
|
"x86_64-unknown-l4re-uclibc",
|
||||||
|
"x86_64-unknown-openbsd",
|
||||||
|
"x86_64-wrs-vxworks"
|
||||||
|
]
|
||||||
|
cargo-args = ["-Zbuild-std=core"]
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
rustc-std-workspace-core = { version = "1.0.1", optional = true }
|
||||||
|
|
||||||
|
[features]
|
||||||
|
default = ["std"]
|
||||||
|
std = []
|
||||||
|
rustc-dep-of-std = ['align', 'rustc-std-workspace-core']
|
||||||
|
extra_traits = []
|
||||||
|
|
||||||
|
# `const-extern-function` is deprecated and no longer does anything
|
||||||
|
const-extern-fn = []
|
||||||
|
|
||||||
|
# `align` is deprecated and no longer does anything
|
||||||
|
align = []
|
||||||
|
|
||||||
|
# use_std is deprecated, use `std` instead
|
||||||
|
use_std = ['std']
|
||||||
|
|
||||||
|
[workspace]
|
||||||
|
members = [
|
||||||
|
"ctest",
|
||||||
|
"libc-test",
|
||||||
|
]
|
||||||
|
|
||||||
|
[workspace.lints.rust]
|
||||||
|
# FIXME(cleanup): make ident usage consistent in each file
|
||||||
|
unused_qualifications = "allow"
|
||||||
|
|
||||||
|
[workspace.lints.clippy]
|
||||||
|
# Enable pedantic lints - use this manually once in a while, but don't enable by default
|
||||||
|
# pedantic = { level = "warn", priority = -1 }
|
||||||
|
|
||||||
|
# We are okay with the current state of these lints
|
||||||
|
explicit_iter_loop = "warn"
|
||||||
|
identity_op = "allow" # some expressions like `0 | x` are clearer for bit ops
|
||||||
|
manual_assert = "warn"
|
||||||
|
map_unwrap_or = "warn"
|
||||||
|
missing_safety_doc = "allow" # safety? in libc? seriously?
|
||||||
|
non_minimal_cfg = "allow" # for some reason cfg_if! sometimes trigger this
|
||||||
|
ptr_as_ptr = "warn"
|
||||||
|
unnecessary_semicolon = "warn"
|
||||||
|
|
||||||
|
# FIXME(clippy): these should be fixed if possible
|
||||||
|
unnecessary_cast = "allow" # some casts like `as usize` are only needed for some targets
|
||||||
|
|
||||||
|
[lints]
|
||||||
|
workspace = true
|
||||||
|
|
||||||
|
[package.metadata.cargo-semver-checks.lints]
|
||||||
|
# Alignment is an internal detail that users must not rely upon
|
||||||
|
repr_align_removed = "warn"
|
||||||
|
# We deprecate things all the time
|
||||||
|
global_value_marked_deprecated = "warn"
|
||||||
|
|
@ -0,0 +1,176 @@
|
||||||
|
Apache License
|
||||||
|
Version 2.0, January 2004
|
||||||
|
http://www.apache.org/licenses/
|
||||||
|
|
||||||
|
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||||
|
|
||||||
|
1. Definitions.
|
||||||
|
|
||||||
|
"License" shall mean the terms and conditions for use, reproduction,
|
||||||
|
and distribution as defined by Sections 1 through 9 of this document.
|
||||||
|
|
||||||
|
"Licensor" shall mean the copyright owner or entity authorized by
|
||||||
|
the copyright owner that is granting the License.
|
||||||
|
|
||||||
|
"Legal Entity" shall mean the union of the acting entity and all
|
||||||
|
other entities that control, are controlled by, or are under common
|
||||||
|
control with that entity. For the purposes of this definition,
|
||||||
|
"control" means (i) the power, direct or indirect, to cause the
|
||||||
|
direction or management of such entity, whether by contract or
|
||||||
|
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||||
|
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||||
|
|
||||||
|
"You" (or "Your") shall mean an individual or Legal Entity
|
||||||
|
exercising permissions granted by this License.
|
||||||
|
|
||||||
|
"Source" form shall mean the preferred form for making modifications,
|
||||||
|
including but not limited to software source code, documentation
|
||||||
|
source, and configuration files.
|
||||||
|
|
||||||
|
"Object" form shall mean any form resulting from mechanical
|
||||||
|
transformation or translation of a Source form, including but
|
||||||
|
not limited to compiled object code, generated documentation,
|
||||||
|
and conversions to other media types.
|
||||||
|
|
||||||
|
"Work" shall mean the work of authorship, whether in Source or
|
||||||
|
Object form, made available under the License, as indicated by a
|
||||||
|
copyright notice that is included in or attached to the work
|
||||||
|
(an example is provided in the Appendix below).
|
||||||
|
|
||||||
|
"Derivative Works" shall mean any work, whether in Source or Object
|
||||||
|
form, that is based on (or derived from) the Work and for which the
|
||||||
|
editorial revisions, annotations, elaborations, or other modifications
|
||||||
|
represent, as a whole, an original work of authorship. For the purposes
|
||||||
|
of this License, Derivative Works shall not include works that remain
|
||||||
|
separable from, or merely link (or bind by name) to the interfaces of,
|
||||||
|
the Work and Derivative Works thereof.
|
||||||
|
|
||||||
|
"Contribution" shall mean any work of authorship, including
|
||||||
|
the original version of the Work and any modifications or additions
|
||||||
|
to that Work or Derivative Works thereof, that is intentionally
|
||||||
|
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||||
|
or by an individual or Legal Entity authorized to submit on behalf of
|
||||||
|
the copyright owner. For the purposes of this definition, "submitted"
|
||||||
|
means any form of electronic, verbal, or written communication sent
|
||||||
|
to the Licensor or its representatives, including but not limited to
|
||||||
|
communication on electronic mailing lists, source code control systems,
|
||||||
|
and issue tracking systems that are managed by, or on behalf of, the
|
||||||
|
Licensor for the purpose of discussing and improving the Work, but
|
||||||
|
excluding communication that is conspicuously marked or otherwise
|
||||||
|
designated in writing by the copyright owner as "Not a Contribution."
|
||||||
|
|
||||||
|
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||||
|
on behalf of whom a Contribution has been received by Licensor and
|
||||||
|
subsequently incorporated within the Work.
|
||||||
|
|
||||||
|
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||||
|
this License, each Contributor hereby grants to You a perpetual,
|
||||||
|
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||||
|
copyright license to reproduce, prepare Derivative Works of,
|
||||||
|
publicly display, publicly perform, sublicense, and distribute the
|
||||||
|
Work and such Derivative Works in Source or Object form.
|
||||||
|
|
||||||
|
3. Grant of Patent License. Subject to the terms and conditions of
|
||||||
|
this License, each Contributor hereby grants to You a perpetual,
|
||||||
|
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||||
|
(except as stated in this section) patent license to make, have made,
|
||||||
|
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||||
|
where such license applies only to those patent claims licensable
|
||||||
|
by such Contributor that are necessarily infringed by their
|
||||||
|
Contribution(s) alone or by combination of their Contribution(s)
|
||||||
|
with the Work to which such Contribution(s) was submitted. If You
|
||||||
|
institute patent litigation against any entity (including a
|
||||||
|
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||||
|
or a Contribution incorporated within the Work constitutes direct
|
||||||
|
or contributory patent infringement, then any patent licenses
|
||||||
|
granted to You under this License for that Work shall terminate
|
||||||
|
as of the date such litigation is filed.
|
||||||
|
|
||||||
|
4. Redistribution. You may reproduce and distribute copies of the
|
||||||
|
Work or Derivative Works thereof in any medium, with or without
|
||||||
|
modifications, and in Source or Object form, provided that You
|
||||||
|
meet the following conditions:
|
||||||
|
|
||||||
|
(a) You must give any other recipients of the Work or
|
||||||
|
Derivative Works a copy of this License; and
|
||||||
|
|
||||||
|
(b) You must cause any modified files to carry prominent notices
|
||||||
|
stating that You changed the files; and
|
||||||
|
|
||||||
|
(c) You must retain, in the Source form of any Derivative Works
|
||||||
|
that You distribute, all copyright, patent, trademark, and
|
||||||
|
attribution notices from the Source form of the Work,
|
||||||
|
excluding those notices that do not pertain to any part of
|
||||||
|
the Derivative Works; and
|
||||||
|
|
||||||
|
(d) If the Work includes a "NOTICE" text file as part of its
|
||||||
|
distribution, then any Derivative Works that You distribute must
|
||||||
|
include a readable copy of the attribution notices contained
|
||||||
|
within such NOTICE file, excluding those notices that do not
|
||||||
|
pertain to any part of the Derivative Works, in at least one
|
||||||
|
of the following places: within a NOTICE text file distributed
|
||||||
|
as part of the Derivative Works; within the Source form or
|
||||||
|
documentation, if provided along with the Derivative Works; or,
|
||||||
|
within a display generated by the Derivative Works, if and
|
||||||
|
wherever such third-party notices normally appear. The contents
|
||||||
|
of the NOTICE file are for informational purposes only and
|
||||||
|
do not modify the License. You may add Your own attribution
|
||||||
|
notices within Derivative Works that You distribute, alongside
|
||||||
|
or as an addendum to the NOTICE text from the Work, provided
|
||||||
|
that such additional attribution notices cannot be construed
|
||||||
|
as modifying the License.
|
||||||
|
|
||||||
|
You may add Your own copyright statement to Your modifications and
|
||||||
|
may provide additional or different license terms and conditions
|
||||||
|
for use, reproduction, or distribution of Your modifications, or
|
||||||
|
for any such Derivative Works as a whole, provided Your use,
|
||||||
|
reproduction, and distribution of the Work otherwise complies with
|
||||||
|
the conditions stated in this License.
|
||||||
|
|
||||||
|
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||||
|
any Contribution intentionally submitted for inclusion in the Work
|
||||||
|
by You to the Licensor shall be under the terms and conditions of
|
||||||
|
this License, without any additional terms or conditions.
|
||||||
|
Notwithstanding the above, nothing herein shall supersede or modify
|
||||||
|
the terms of any separate license agreement you may have executed
|
||||||
|
with Licensor regarding such Contributions.
|
||||||
|
|
||||||
|
6. Trademarks. This License does not grant permission to use the trade
|
||||||
|
names, trademarks, service marks, or product names of the Licensor,
|
||||||
|
except as required for reasonable and customary use in describing the
|
||||||
|
origin of the Work and reproducing the content of the NOTICE file.
|
||||||
|
|
||||||
|
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||||
|
agreed to in writing, Licensor provides the Work (and each
|
||||||
|
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||||
|
implied, including, without limitation, any warranties or conditions
|
||||||
|
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||||
|
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||||
|
appropriateness of using or redistributing the Work and assume any
|
||||||
|
risks associated with Your exercise of permissions under this License.
|
||||||
|
|
||||||
|
8. Limitation of Liability. In no event and under no legal theory,
|
||||||
|
whether in tort (including negligence), contract, or otherwise,
|
||||||
|
unless required by applicable law (such as deliberate and grossly
|
||||||
|
negligent acts) or agreed to in writing, shall any Contributor be
|
||||||
|
liable to You for damages, including any direct, indirect, special,
|
||||||
|
incidental, or consequential damages of any character arising as a
|
||||||
|
result of this License or out of the use or inability to use the
|
||||||
|
Work (including but not limited to damages for loss of goodwill,
|
||||||
|
work stoppage, computer failure or malfunction, or any and all
|
||||||
|
other commercial damages or losses), even if such Contributor
|
||||||
|
has been advised of the possibility of such damages.
|
||||||
|
|
||||||
|
9. Accepting Warranty or Additional Liability. While redistributing
|
||||||
|
the Work or Derivative Works thereof, You may choose to offer,
|
||||||
|
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||||
|
or other liability obligations and/or rights consistent with this
|
||||||
|
License. However, in accepting such obligations, You may act only
|
||||||
|
on Your own behalf and on Your sole responsibility, not on behalf
|
||||||
|
of any other Contributor, and only if You agree to indemnify,
|
||||||
|
defend, and hold each Contributor harmless for any liability
|
||||||
|
incurred by, or claims asserted against, such Contributor by reason
|
||||||
|
of your accepting any such warranty or additional liability.
|
||||||
|
|
||||||
|
END OF TERMS AND CONDITIONS
|
||||||
|
|
@ -0,0 +1,25 @@
|
||||||
|
Copyright (c) The Rust Project Developers
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any
|
||||||
|
person obtaining a copy of this software and associated
|
||||||
|
documentation files (the "Software"), to deal in the
|
||||||
|
Software without restriction, including without
|
||||||
|
limitation the rights to use, copy, modify, merge,
|
||||||
|
publish, distribute, sublicense, and/or sell copies of
|
||||||
|
the Software, and to permit persons to whom the Software
|
||||||
|
is furnished to do so, subject to the following
|
||||||
|
conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice
|
||||||
|
shall be included in all copies or substantial portions
|
||||||
|
of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
|
||||||
|
ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
|
||||||
|
TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
|
||||||
|
PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
|
||||||
|
SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||||
|
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||||
|
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
|
||||||
|
IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||||
|
DEALINGS IN THE SOFTWARE.
|
||||||
|
|
@ -0,0 +1,101 @@
|
||||||
|
# libc - Raw FFI bindings to platforms' system libraries
|
||||||
|
|
||||||
|
[![GHA Status]][GitHub Actions] [![Latest Version]][crates.io] [![Documentation]][docs.rs] ![License]
|
||||||
|
|
||||||
|
`libc` provides all of the definitions necessary to easily interoperate with C
|
||||||
|
code (or "C-like" code) on each of the platforms that Rust supports. This
|
||||||
|
includes type definitions (e.g. `c_int`), constants (e.g. `EINVAL`) as well as
|
||||||
|
function headers (e.g. `malloc`).
|
||||||
|
|
||||||
|
This crate exports all underlying platform types, functions, and constants under
|
||||||
|
the crate root, so all items are accessible as `libc::foo`. The types and values
|
||||||
|
of all the exported APIs match the platform that libc is compiled for.
|
||||||
|
|
||||||
|
Windows API bindings are not included in this crate. If you are looking for
|
||||||
|
WinAPI bindings, consider using crates like [windows-sys].
|
||||||
|
|
||||||
|
More detailed information about the design of this library can be found in its
|
||||||
|
[associated RFC][rfc].
|
||||||
|
|
||||||
|
[rfc]: https://github.com/rust-lang/rfcs/blob/HEAD/text/1291-promote-libc.md
|
||||||
|
[windows-sys]: https://docs.rs/windows-sys
|
||||||
|
|
||||||
|
## v1.0 Roadmap
|
||||||
|
|
||||||
|
Currently, `libc` has two active branches: `main` for the upcoming v1.0 release,
|
||||||
|
and `libc-0.2` for the currently published version. By default all pull requests
|
||||||
|
should target `main`; once reviewed, they can be cherry picked to the `libc-0.2`
|
||||||
|
branch if needed.
|
||||||
|
|
||||||
|
We will stop making new v0.2 releases once v1.0 is released.
|
||||||
|
|
||||||
|
See the section in [CONTRIBUTING.md](CONTRIBUTING.md#v10-roadmap) for more
|
||||||
|
details.
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
Add the following to your `Cargo.toml`:
|
||||||
|
|
||||||
|
```toml
|
||||||
|
[dependencies]
|
||||||
|
libc = "0.2"
|
||||||
|
```
|
||||||
|
|
||||||
|
## Rust version support
|
||||||
|
|
||||||
|
The minimum supported Rust toolchain version is currently **Rust 1.65**.
|
||||||
|
|
||||||
|
Increases to the MSRV are allowed to change without a major (i.e. semver-
|
||||||
|
breaking) release in order to avoid a ripple effect in the ecosystem. A policy
|
||||||
|
for when this may change is a work in progress.
|
||||||
|
|
||||||
|
`libc` may continue to compile with Rust versions older than the current MSRV
|
||||||
|
but this is not guaranteed.
|
||||||
|
|
||||||
|
## Platform support
|
||||||
|
|
||||||
|
You can see the platform(target)-specific docs on [docs.rs], select a platform
|
||||||
|
you want to see.
|
||||||
|
|
||||||
|
See [`ci/verify-build.py`](https://github.com/rust-lang/libc/blob/HEAD/ci/verify-build.py) for
|
||||||
|
the platforms on which `libc` is guaranteed to build for each Rust toolchain.
|
||||||
|
The test matrices at [GitHub Actions] show the platforms in which `libc` tests
|
||||||
|
are run.
|
||||||
|
|
||||||
|
<div class="platform_docs"></div>
|
||||||
|
|
||||||
|
## License
|
||||||
|
|
||||||
|
This project is licensed under either of
|
||||||
|
|
||||||
|
* [Apache License, Version 2.0](https://www.apache.org/licenses/LICENSE-2.0)
|
||||||
|
([LICENSE-APACHE](https://github.com/rust-lang/libc/blob/HEAD/LICENSE-APACHE))
|
||||||
|
|
||||||
|
* [MIT License](https://opensource.org/licenses/MIT)
|
||||||
|
([LICENSE-MIT](https://github.com/rust-lang/libc/blob/HEAD/LICENSE-MIT))
|
||||||
|
|
||||||
|
at your option.
|
||||||
|
|
||||||
|
## Contributing
|
||||||
|
|
||||||
|
We welcome all people who want to contribute. Please see the
|
||||||
|
[contributing instructions] for more information.
|
||||||
|
|
||||||
|
[contributing instructions]: https://github.com/rust-lang/libc/blob/HEAD/CONTRIBUTING.md
|
||||||
|
|
||||||
|
Contributions in any form (issues, pull requests, etc.) to this project must
|
||||||
|
adhere to Rust's [Code of Conduct].
|
||||||
|
|
||||||
|
[Code of Conduct]: https://www.rust-lang.org/policies/code-of-conduct
|
||||||
|
|
||||||
|
Unless you explicitly state otherwise, any contribution intentionally submitted
|
||||||
|
for inclusion in `libc` by you, as defined in the Apache-2.0 license, shall be
|
||||||
|
dual licensed as above, without any additional terms or conditions.
|
||||||
|
|
||||||
|
[GitHub Actions]: https://github.com/rust-lang/libc/actions
|
||||||
|
[GHA Status]: https://github.com/rust-lang/libc/workflows/CI/badge.svg
|
||||||
|
[crates.io]: https://crates.io/crates/libc
|
||||||
|
[Latest Version]: https://img.shields.io/crates/v/libc.svg
|
||||||
|
[Documentation]: https://docs.rs/libc/badge.svg
|
||||||
|
[docs.rs]: https://docs.rs/libc
|
||||||
|
[License]: https://img.shields.io/crates/l/libc.svg
|
||||||
|
|
@ -0,0 +1,393 @@
|
||||||
|
use std::env::VarError;
|
||||||
|
use std::process::{
|
||||||
|
Command,
|
||||||
|
Output,
|
||||||
|
};
|
||||||
|
use std::sync::atomic::AtomicBool;
|
||||||
|
use std::sync::atomic::Ordering::Relaxed;
|
||||||
|
use std::{
|
||||||
|
env,
|
||||||
|
str,
|
||||||
|
};
|
||||||
|
|
||||||
|
// List of cfgs this build script is allowed to set. The list is needed to support check-cfg, as we
|
||||||
|
// need to know all the possible cfgs that this script will set. If you need to set another cfg
|
||||||
|
// make sure to add it to this list as well.
|
||||||
|
const ALLOWED_CFGS: &[&str] = &[
|
||||||
|
"emscripten_old_stat_abi",
|
||||||
|
// Should be enabled by users if esp-idf (>=6.0) is build with picolibc instead of newlib.
|
||||||
|
"espidf_picolibc",
|
||||||
|
"espidf_time32",
|
||||||
|
"freebsd10",
|
||||||
|
"freebsd11",
|
||||||
|
"freebsd12",
|
||||||
|
"freebsd13",
|
||||||
|
"freebsd14",
|
||||||
|
"freebsd15",
|
||||||
|
// Corresponds to `_FILE_OFFSET_BITS=64` in glibc
|
||||||
|
"gnu_file_offset_bits64",
|
||||||
|
// Corresponds to `_TIME_BITS=64` in glibc. Also used in x86 Windows with
|
||||||
|
// GNU to expose a 64-bit `time_t`.
|
||||||
|
"gnu_time_bits64",
|
||||||
|
"libc_deny_warnings",
|
||||||
|
// Corresponds to `__USE_TIME_BITS64` in UAPI
|
||||||
|
"linux_time_bits64",
|
||||||
|
"musl_v1_2_3",
|
||||||
|
// musl v1.2.3+ && 32-bit: time_t is i64, struct layouts change
|
||||||
|
"musl32_time64",
|
||||||
|
// Corresponds to `_REDIR_TIME64` in musl: symbol redirects to __*_time64
|
||||||
|
"musl_redir_time64",
|
||||||
|
"vxworks_lt_25_09",
|
||||||
|
"libc_pauthtest",
|
||||||
|
];
|
||||||
|
|
||||||
|
// Extra values to allow for check-cfg.
|
||||||
|
const CHECK_CFG_EXTRA: &[(&str, &[&str])] = &[
|
||||||
|
(
|
||||||
|
"target_os",
|
||||||
|
&[
|
||||||
|
"switch", "aix", "ohos", "hurd", "rtems", "visionos", "nuttx", "cygwin", "qurt", "qnx",
|
||||||
|
],
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"target_env",
|
||||||
|
&["illumos", "wasi", "aix", "ohos", "nto71_iosock"],
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"target_arch",
|
||||||
|
&["loongarch64", "mips32r6", "mips64r6", "csky"],
|
||||||
|
),
|
||||||
|
];
|
||||||
|
|
||||||
|
/// Musl architectures that define `_REDIR_TIME64` (i.e. those that transitioned
|
||||||
|
/// from 32-bit to 64-bit `time_t` and need `__*_time64` symbol redirects).
|
||||||
|
const MUSL_REDIR_TIME64_ARCHES: &[&str] = &["arm", "mips", "powerpc", "x86"];
|
||||||
|
|
||||||
|
/// Read from env, print more debug output via `cargo:warning` if set.
|
||||||
|
static VERBOSE_BUILD: AtomicBool = AtomicBool::new(false);
|
||||||
|
|
||||||
|
/// Print info via warnings if `LIBC_BUILD_VERBOSE` is set.
|
||||||
|
macro_rules! info {
|
||||||
|
($($tt:tt)+) => {
|
||||||
|
if VERBOSE_BUILD.load(Relaxed) {
|
||||||
|
println!("cargo:warning=info: {}", format_args!($($tt)*));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
// Avoid unnecessary re-building.
|
||||||
|
println!("cargo:rerun-if-changed=build.rs");
|
||||||
|
|
||||||
|
println!("cargo:rerun-if-env-changed=LIBC_BUILD_VERBOSE");
|
||||||
|
if env_flag("LIBC_BUILD_VERBOSE") {
|
||||||
|
VERBOSE_BUILD.store(true, Relaxed);
|
||||||
|
}
|
||||||
|
|
||||||
|
let (rustc_minor_ver, _is_nightly) = rustc_minor_nightly();
|
||||||
|
let libc_ci = env_flag("LIBC_CI");
|
||||||
|
let target_env = env::var("CARGO_CFG_TARGET_ENV").unwrap_or_default();
|
||||||
|
let target_os = env::var("CARGO_CFG_TARGET_OS").unwrap_or_default();
|
||||||
|
let target_ptr_width = env::var("CARGO_CFG_TARGET_POINTER_WIDTH").unwrap_or_default();
|
||||||
|
let target_arch = env::var("CARGO_CFG_TARGET_ARCH").unwrap_or_default();
|
||||||
|
let target_abi = env::var("CARGO_CFG_TARGET_ABI").unwrap_or_default();
|
||||||
|
|
||||||
|
// FIXME(msrv): Once the MSRV is 1.78, use `cfg(target_abi = "pauthtest")`
|
||||||
|
// directly instead of translating it to `libc_pauthtest`. `target_abi`
|
||||||
|
// cannot be used directly in cfg expressions on the current MSRV.
|
||||||
|
if target_abi == "pauthtest" {
|
||||||
|
set_cfg("libc_pauthtest");
|
||||||
|
}
|
||||||
|
|
||||||
|
// FIXME: this can be removed in 1-2 releases
|
||||||
|
println!("cargo:rerun-if-env-changed=RUST_LIBC_UNSTABLE_FREEBSD_VERSION");
|
||||||
|
if env::var("RUST_LIBC_UNSTABLE_FREEBSD_VERSION").is_ok() {
|
||||||
|
println!(
|
||||||
|
"cargo:warning=RUST_LIBC_UNSTABLE_FREEBSD_VERSION has been removed; set \
|
||||||
|
the cfg libc_unstable_freebsd_version via RUSTFLAGS instead"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// The ABI of libc used by std is backward compatible with FreeBSD 12.
|
||||||
|
// The ABI of libc from crates.io is backward compatible with FreeBSD 12.
|
||||||
|
//
|
||||||
|
// On CI, we detect the actual FreeBSD version and match its ABI exactly,
|
||||||
|
// running tests to ensure that the ABI is correct.
|
||||||
|
// Allow overriding the default version for testing
|
||||||
|
let which_freebsd = if let Ok(version) = env::var("CARGO_CFG_LIBC_UNSTABLE_FREEBSD_VERSION") {
|
||||||
|
let vers = version.parse().unwrap();
|
||||||
|
println!("cargo:warning=setting FreeBSD version to {vers}");
|
||||||
|
vers
|
||||||
|
} else if libc_ci {
|
||||||
|
which_freebsd().unwrap_or(12)
|
||||||
|
} else {
|
||||||
|
12
|
||||||
|
};
|
||||||
|
|
||||||
|
match which_freebsd {
|
||||||
|
x if x < 10 => panic!("FreeBSD older than 10 is not supported"),
|
||||||
|
10 => set_cfg("freebsd10"),
|
||||||
|
11 => set_cfg("freebsd11"),
|
||||||
|
12 => set_cfg("freebsd12"),
|
||||||
|
13 => set_cfg("freebsd13"),
|
||||||
|
14 => set_cfg("freebsd14"),
|
||||||
|
_ => set_cfg("freebsd15"),
|
||||||
|
}
|
||||||
|
|
||||||
|
match emcc_version_code() {
|
||||||
|
Some(v) if (v < 30142) => set_cfg("emscripten_old_stat_abi"),
|
||||||
|
// Non-Emscripten or version >= 3.1.42.
|
||||||
|
_ => (),
|
||||||
|
}
|
||||||
|
|
||||||
|
match vxworks_version_code() {
|
||||||
|
Some(v) if (v < (25, 9)) => set_cfg("vxworks_lt_25_09"),
|
||||||
|
// VxWorks version >= 25.09
|
||||||
|
_ => (),
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut musl_v1_2_3 = env_flag("CARGO_CFG_LIBC_UNSTABLE_MUSL_V1_2_3");
|
||||||
|
|
||||||
|
// OpenHarmony uses a fork of the musl libc
|
||||||
|
let musl = target_env == "musl" || target_env == "ohos";
|
||||||
|
|
||||||
|
// loongarch64, hexagon, ohos and pauthtest only exist with recent musl
|
||||||
|
if target_arch == "loongarch64"
|
||||||
|
|| target_arch == "hexagon"
|
||||||
|
|| target_env == "ohos"
|
||||||
|
|| target_abi == "pauthtest"
|
||||||
|
{
|
||||||
|
musl_v1_2_3 = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if musl && musl_v1_2_3 {
|
||||||
|
set_cfg("musl_v1_2_3");
|
||||||
|
if target_ptr_width == "32" {
|
||||||
|
set_cfg("musl32_time64");
|
||||||
|
set_cfg("linux_time_bits64");
|
||||||
|
}
|
||||||
|
if MUSL_REDIR_TIME64_ARCHES.contains(&target_arch.as_str()) {
|
||||||
|
set_cfg("musl_redir_time64");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let uclibc_use_time64 = env_flag("CARGO_CFG_LIBC_UNSTABLE_UCLIBC_TIME64");
|
||||||
|
if target_env == "uclibc" && uclibc_use_time64 {
|
||||||
|
set_cfg("linux_time_bits64");
|
||||||
|
}
|
||||||
|
|
||||||
|
if target_env == "gnu"
|
||||||
|
&& matches!(target_os.as_str(), "linux" | "windows")
|
||||||
|
&& target_ptr_width == "32"
|
||||||
|
&& target_arch != "riscv32"
|
||||||
|
&& target_arch != "x86_64"
|
||||||
|
{
|
||||||
|
let defaultbits = "32";
|
||||||
|
|
||||||
|
let mut tb_env = env::var("CARGO_CFG_LIBC_UNSTABLE_GNU_TIME_BITS");
|
||||||
|
|
||||||
|
// FIXME: remove these fallbacks in a few releases
|
||||||
|
if let Ok(old_tb_env) = env::var("RUST_LIBC_UNSTABLE_GNU_TIME_BITS") {
|
||||||
|
println!(
|
||||||
|
"cargo:warning=RUST_LIBC_UNSTABLE_GNU_TIME_BITS will be removed; \
|
||||||
|
set `--cfg=libc_unstable_gnu_time_bits=\"...\"` via RUSTFLAGS instead"
|
||||||
|
);
|
||||||
|
tb_env = tb_env.or(Ok(old_tb_env));
|
||||||
|
}
|
||||||
|
if env::var("RUST_LIBC_UNSTABLE_GNU_FILE_OFFSET_BITS").is_ok()
|
||||||
|
|| env::var("CARGO_CFG_LIBC_UNSTABLE_GNU_FILE_OFFSET_BITS").is_ok()
|
||||||
|
{
|
||||||
|
println!(
|
||||||
|
"cargo:warning=glibc file offset can no longer be set independently of \
|
||||||
|
`gnu_time_bits`"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
let timebits = match tb_env.as_deref() {
|
||||||
|
Err(_) => defaultbits,
|
||||||
|
Ok(tb) if tb == "64" => tb,
|
||||||
|
Ok(tb) if tb == "32" => tb,
|
||||||
|
Ok(_) => {
|
||||||
|
panic!("Invalid value for libc_unstable_gnu_time_bits. Must be 32, 64, or unset.")
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
if timebits == "64" {
|
||||||
|
set_cfg("linux_time_bits64");
|
||||||
|
set_cfg("gnu_file_offset_bits64");
|
||||||
|
set_cfg("gnu_time_bits64");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// On CI: deny all warnings
|
||||||
|
if libc_ci {
|
||||||
|
set_cfg("libc_deny_warnings");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Since Rust 1.80, configuration that isn't recognized by default needs to be provided to
|
||||||
|
// avoid warnings.
|
||||||
|
if rustc_minor_ver >= 80 {
|
||||||
|
for cfg in ALLOWED_CFGS {
|
||||||
|
println!("cargo:rustc-check-cfg=cfg({cfg})");
|
||||||
|
}
|
||||||
|
for &(name, values) in CHECK_CFG_EXTRA {
|
||||||
|
let values = values.join("\",\"");
|
||||||
|
println!("cargo:rustc-check-cfg=cfg({name},values(\"{values}\"))");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Run `rustc --version` and capture the output, adjusting arguments as needed if `clippy-driver`
|
||||||
|
/// is used instead.
|
||||||
|
fn rustc_version_cmd(is_clippy_driver: bool) -> Output {
|
||||||
|
let rustc = env::var_os("RUSTC").expect("Failed to get rustc version: missing RUSTC env");
|
||||||
|
|
||||||
|
let mut cmd = match env::var_os("RUSTC_WRAPPER") {
|
||||||
|
Some(ref wrapper) if wrapper.is_empty() => Command::new(rustc),
|
||||||
|
Some(wrapper) => {
|
||||||
|
let mut cmd = Command::new(wrapper);
|
||||||
|
cmd.arg(rustc);
|
||||||
|
if is_clippy_driver {
|
||||||
|
cmd.arg("--rustc");
|
||||||
|
}
|
||||||
|
|
||||||
|
cmd
|
||||||
|
}
|
||||||
|
None => Command::new(rustc),
|
||||||
|
};
|
||||||
|
|
||||||
|
cmd.arg("--version");
|
||||||
|
|
||||||
|
let output = cmd.output().expect("Failed to get rustc version");
|
||||||
|
|
||||||
|
assert!(
|
||||||
|
output.status.success(),
|
||||||
|
"failed to run rustc: {}",
|
||||||
|
String::from_utf8_lossy(output.stderr.as_slice())
|
||||||
|
);
|
||||||
|
|
||||||
|
output
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Return the minor version of `rustc`, as well as a bool indicating whether or not the version
|
||||||
|
/// is a nightly.
|
||||||
|
fn rustc_minor_nightly() -> (u32, bool) {
|
||||||
|
macro_rules! otry {
|
||||||
|
($e:expr) => {
|
||||||
|
match $e {
|
||||||
|
Some(e) => e,
|
||||||
|
None => panic!("Failed to get rustc version"),
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut output = rustc_version_cmd(false);
|
||||||
|
|
||||||
|
if otry!(str::from_utf8(&output.stdout).ok()).starts_with("clippy") {
|
||||||
|
output = rustc_version_cmd(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
let version = otry!(str::from_utf8(&output.stdout).ok());
|
||||||
|
|
||||||
|
let mut pieces = version.split('.');
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
pieces.next(),
|
||||||
|
Some("rustc 1"),
|
||||||
|
"Failed to get rustc version"
|
||||||
|
);
|
||||||
|
|
||||||
|
let minor = pieces.next();
|
||||||
|
|
||||||
|
// If `rustc` was built from a tarball, its version string
|
||||||
|
// will have neither a git hash nor a commit date
|
||||||
|
// (e.g. "rustc 1.39.0"). Treat this case as non-nightly,
|
||||||
|
// since a nightly build should either come from CI
|
||||||
|
// or a git checkout
|
||||||
|
let nightly_raw = otry!(pieces.next()).split('-').nth(1);
|
||||||
|
let nightly = nightly_raw.map_or(false, |raw| {
|
||||||
|
raw.starts_with("dev") || raw.starts_with("nightly")
|
||||||
|
});
|
||||||
|
let minor = otry!(otry!(minor).parse().ok());
|
||||||
|
|
||||||
|
info!("detected rust 1.{minor}, nightly={nightly}");
|
||||||
|
|
||||||
|
(minor, nightly)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn which_freebsd() -> Option<i32> {
|
||||||
|
let output = Command::new("freebsd-version").output().ok()?;
|
||||||
|
if !output.status.success() {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
|
let stdout = String::from_utf8(output.stdout).ok()?;
|
||||||
|
|
||||||
|
match &stdout {
|
||||||
|
s if s.starts_with("10") => Some(10),
|
||||||
|
s if s.starts_with("11") => Some(11),
|
||||||
|
s if s.starts_with("12") => Some(12),
|
||||||
|
s if s.starts_with("13") => Some(13),
|
||||||
|
s if s.starts_with("14") => Some(14),
|
||||||
|
s if s.starts_with("15") => Some(15),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn emcc_version_code() -> Option<u64> {
|
||||||
|
let emcc = if cfg!(target_os = "windows") {
|
||||||
|
"emcc.bat"
|
||||||
|
} else {
|
||||||
|
"emcc"
|
||||||
|
};
|
||||||
|
|
||||||
|
let output = Command::new(emcc).arg("-dumpversion").output().ok()?;
|
||||||
|
if !output.status.success() {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
|
let version = String::from_utf8(output.stdout).ok()?;
|
||||||
|
|
||||||
|
// Some Emscripten versions come with `-git` attached, so split the
|
||||||
|
// version string also on the `-` char.
|
||||||
|
let mut pieces = version.trim().split(['.', '-']);
|
||||||
|
|
||||||
|
let major = pieces.next().and_then(|x| x.parse().ok()).unwrap_or(0);
|
||||||
|
let minor = pieces.next().and_then(|x| x.parse().ok()).unwrap_or(0);
|
||||||
|
let patch = pieces.next().and_then(|x| x.parse().ok()).unwrap_or(0);
|
||||||
|
|
||||||
|
Some(major * 10000 + minor * 100 + patch)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Retrieve the VxWorks release version from the environment variable set by the VxWorks build
|
||||||
|
/// environment, in `(minor, patch)` form. Currently the only major version supported by Rust
|
||||||
|
/// is 7.
|
||||||
|
fn vxworks_version_code() -> Option<(u32, u32)> {
|
||||||
|
let version = env::var("WIND_RELEASE_ID").ok()?;
|
||||||
|
|
||||||
|
let mut pieces = version.trim().split(['.']);
|
||||||
|
|
||||||
|
let major: u32 = pieces.next().and_then(|x| x.parse().ok()).unwrap_or(0);
|
||||||
|
let minor: u32 = pieces.next().and_then(|x| x.parse().ok()).unwrap_or(0);
|
||||||
|
|
||||||
|
Some((major, minor))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_cfg(cfg: &str) {
|
||||||
|
assert!(
|
||||||
|
ALLOWED_CFGS.contains(&cfg),
|
||||||
|
"trying to set cfg {cfg}, but it is not in ALLOWED_CFGS",
|
||||||
|
);
|
||||||
|
println!("cargo:rustc-cfg={cfg}");
|
||||||
|
info!("setting config `{cfg}`");
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Return true if the env is set to a value other than `0`.
|
||||||
|
fn env_flag(key: &str) -> bool {
|
||||||
|
match env::var(key) {
|
||||||
|
Ok(x) if x == "0" => false,
|
||||||
|
Err(VarError::NotPresent) => false,
|
||||||
|
Err(VarError::NotUnicode(_)) => panic!("non-unicode var for `{key}`"),
|
||||||
|
Ok(_) => true,
|
||||||
|
}
|
||||||
|
}
|
||||||
File diff suppressed because it is too large
Load Diff
|
|
@ -0,0 +1,69 @@
|
||||||
|
use crate::off_t;
|
||||||
|
use crate::prelude::*;
|
||||||
|
|
||||||
|
pub type __u64 = c_ulonglong;
|
||||||
|
pub type wchar_t = u32;
|
||||||
|
pub type nlink_t = c_ulong;
|
||||||
|
pub type blksize_t = c_long;
|
||||||
|
|
||||||
|
s! {
|
||||||
|
pub struct stat {
|
||||||
|
pub st_dev: crate::dev_t,
|
||||||
|
pub st_ino: crate::ino_t,
|
||||||
|
pub st_mode: crate::mode_t,
|
||||||
|
pub st_nlink: crate::nlink_t,
|
||||||
|
pub st_uid: crate::uid_t,
|
||||||
|
pub st_gid: crate::gid_t,
|
||||||
|
pub st_rdev: crate::dev_t,
|
||||||
|
__pad0: Padding<c_ulong>,
|
||||||
|
pub st_size: off_t,
|
||||||
|
pub st_blksize: crate::blksize_t,
|
||||||
|
__pad1: Padding<c_int>,
|
||||||
|
pub st_blocks: crate::blkcnt_t,
|
||||||
|
pub st_atime: crate::time_t,
|
||||||
|
pub st_atime_nsec: c_long,
|
||||||
|
pub st_mtime: crate::time_t,
|
||||||
|
pub st_mtime_nsec: c_long,
|
||||||
|
pub st_ctime: crate::time_t,
|
||||||
|
pub st_ctime_nsec: c_long,
|
||||||
|
__unused: Padding<[c_uint; 2]>,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct stat64 {
|
||||||
|
pub st_dev: crate::dev_t,
|
||||||
|
pub st_ino: crate::ino_t,
|
||||||
|
pub st_mode: crate::mode_t,
|
||||||
|
pub st_nlink: crate::nlink_t,
|
||||||
|
pub st_uid: crate::uid_t,
|
||||||
|
pub st_gid: crate::gid_t,
|
||||||
|
pub st_rdev: crate::dev_t,
|
||||||
|
__pad0: Padding<c_ulong>,
|
||||||
|
pub st_size: off_t,
|
||||||
|
pub st_blksize: crate::blksize_t,
|
||||||
|
__pad1: Padding<c_int>,
|
||||||
|
pub st_blocks: crate::blkcnt_t,
|
||||||
|
pub st_atime: crate::time_t,
|
||||||
|
pub st_atime_nsec: c_long,
|
||||||
|
pub st_mtime: crate::time_t,
|
||||||
|
pub st_mtime_nsec: c_long,
|
||||||
|
pub st_ctime: crate::time_t,
|
||||||
|
pub st_ctime_nsec: c_long,
|
||||||
|
__unused: Padding<[c_uint; 2]>,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct ipc_perm {
|
||||||
|
pub __ipc_perm_key: crate::key_t,
|
||||||
|
pub uid: crate::uid_t,
|
||||||
|
pub gid: crate::gid_t,
|
||||||
|
pub cuid: crate::uid_t,
|
||||||
|
pub cgid: crate::gid_t,
|
||||||
|
pub mode: crate::mode_t,
|
||||||
|
pub __seq: c_ushort,
|
||||||
|
__unused1: Padding<c_ulong>,
|
||||||
|
__unused2: Padding<c_ulong>,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// From https://cs.opensource.google/fuchsia/fuchsia/+/main:zircon/third_party/ulib/musl/include/bits/signal.h;l=20-21;drc=0827b18ab9540c46f8037f407d17ea15a79e9ba7
|
||||||
|
pub const MINSIGSTKSZ: size_t = 6144;
|
||||||
|
pub const SIGSTKSZ: size_t = 12288;
|
||||||
File diff suppressed because it is too large
Load Diff
|
|
@ -0,0 +1,46 @@
|
||||||
|
use crate::off_t;
|
||||||
|
use crate::prelude::*;
|
||||||
|
|
||||||
|
// From psABI Calling Convention for RV64
|
||||||
|
pub type __u64 = c_ulonglong;
|
||||||
|
pub type wchar_t = i32;
|
||||||
|
|
||||||
|
pub type nlink_t = c_ulong;
|
||||||
|
pub type blksize_t = c_long;
|
||||||
|
|
||||||
|
pub type stat64 = stat;
|
||||||
|
s! {
|
||||||
|
pub struct stat {
|
||||||
|
pub st_dev: crate::dev_t,
|
||||||
|
pub st_ino: crate::ino_t,
|
||||||
|
pub st_nlink: crate::nlink_t,
|
||||||
|
pub st_mode: crate::mode_t,
|
||||||
|
pub st_uid: crate::uid_t,
|
||||||
|
pub st_gid: crate::gid_t,
|
||||||
|
__pad0: Padding<c_int>,
|
||||||
|
pub st_rdev: crate::dev_t,
|
||||||
|
pub st_size: off_t,
|
||||||
|
pub st_blksize: crate::blksize_t,
|
||||||
|
pub st_blocks: crate::blkcnt_t,
|
||||||
|
pub st_atime: crate::time_t,
|
||||||
|
pub st_atime_nsec: c_long,
|
||||||
|
pub st_mtime: crate::time_t,
|
||||||
|
pub st_mtime_nsec: c_long,
|
||||||
|
pub st_ctime: crate::time_t,
|
||||||
|
pub st_ctime_nsec: c_long,
|
||||||
|
__unused: Padding<[c_long; 3]>,
|
||||||
|
}
|
||||||
|
|
||||||
|
// Not actually used, IPC calls just return ENOSYS
|
||||||
|
pub struct ipc_perm {
|
||||||
|
pub __ipc_perm_key: crate::key_t,
|
||||||
|
pub uid: crate::uid_t,
|
||||||
|
pub gid: crate::gid_t,
|
||||||
|
pub cuid: crate::uid_t,
|
||||||
|
pub cgid: crate::gid_t,
|
||||||
|
pub mode: crate::mode_t,
|
||||||
|
pub __seq: c_ushort,
|
||||||
|
__unused1: Padding<c_ulong>,
|
||||||
|
__unused2: Padding<c_ulong>,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,110 @@
|
||||||
|
use crate::off_t;
|
||||||
|
use crate::prelude::*;
|
||||||
|
|
||||||
|
pub type wchar_t = i32;
|
||||||
|
pub type nlink_t = u64;
|
||||||
|
pub type blksize_t = c_long;
|
||||||
|
pub type __u64 = c_ulonglong;
|
||||||
|
|
||||||
|
s! {
|
||||||
|
pub struct stat {
|
||||||
|
pub st_dev: crate::dev_t,
|
||||||
|
pub st_ino: crate::ino_t,
|
||||||
|
pub st_nlink: crate::nlink_t,
|
||||||
|
pub st_mode: crate::mode_t,
|
||||||
|
pub st_uid: crate::uid_t,
|
||||||
|
pub st_gid: crate::gid_t,
|
||||||
|
__pad0: Padding<c_int>,
|
||||||
|
pub st_rdev: crate::dev_t,
|
||||||
|
pub st_size: off_t,
|
||||||
|
pub st_blksize: crate::blksize_t,
|
||||||
|
pub st_blocks: crate::blkcnt_t,
|
||||||
|
pub st_atime: crate::time_t,
|
||||||
|
pub st_atime_nsec: c_long,
|
||||||
|
pub st_mtime: crate::time_t,
|
||||||
|
pub st_mtime_nsec: c_long,
|
||||||
|
pub st_ctime: crate::time_t,
|
||||||
|
pub st_ctime_nsec: c_long,
|
||||||
|
__unused: Padding<[c_long; 3]>,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct stat64 {
|
||||||
|
pub st_dev: crate::dev_t,
|
||||||
|
pub st_ino: crate::ino64_t,
|
||||||
|
pub st_nlink: crate::nlink_t,
|
||||||
|
pub st_mode: crate::mode_t,
|
||||||
|
pub st_uid: crate::uid_t,
|
||||||
|
pub st_gid: crate::gid_t,
|
||||||
|
__pad0: Padding<c_int>,
|
||||||
|
pub st_rdev: crate::dev_t,
|
||||||
|
pub st_size: off_t,
|
||||||
|
pub st_blksize: crate::blksize_t,
|
||||||
|
pub st_blocks: crate::blkcnt64_t,
|
||||||
|
pub st_atime: crate::time_t,
|
||||||
|
pub st_atime_nsec: c_long,
|
||||||
|
pub st_mtime: crate::time_t,
|
||||||
|
pub st_mtime_nsec: c_long,
|
||||||
|
pub st_ctime: crate::time_t,
|
||||||
|
pub st_ctime_nsec: c_long,
|
||||||
|
__reserved: Padding<[c_long; 3]>,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct mcontext_t {
|
||||||
|
__private: [u64; 32],
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct ipc_perm {
|
||||||
|
pub __ipc_perm_key: crate::key_t,
|
||||||
|
pub uid: crate::uid_t,
|
||||||
|
pub gid: crate::gid_t,
|
||||||
|
pub cuid: crate::uid_t,
|
||||||
|
pub cgid: crate::gid_t,
|
||||||
|
pub mode: crate::mode_t,
|
||||||
|
pub __seq: c_int,
|
||||||
|
__unused1: Padding<c_long>,
|
||||||
|
__unused2: Padding<c_long>,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct ucontext_t {
|
||||||
|
pub uc_flags: c_ulong,
|
||||||
|
pub uc_link: *mut ucontext_t,
|
||||||
|
pub uc_stack: crate::stack_t,
|
||||||
|
pub uc_mcontext: mcontext_t,
|
||||||
|
pub uc_sigmask: crate::sigset_t,
|
||||||
|
__private: [u8; 512],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// offsets in user_regs_structs, from sys/reg.h
|
||||||
|
pub const R15: c_int = 0;
|
||||||
|
pub const R14: c_int = 1;
|
||||||
|
pub const R13: c_int = 2;
|
||||||
|
pub const R12: c_int = 3;
|
||||||
|
pub const RBP: c_int = 4;
|
||||||
|
pub const RBX: c_int = 5;
|
||||||
|
pub const R11: c_int = 6;
|
||||||
|
pub const R10: c_int = 7;
|
||||||
|
pub const R9: c_int = 8;
|
||||||
|
pub const R8: c_int = 9;
|
||||||
|
pub const RAX: c_int = 10;
|
||||||
|
pub const RCX: c_int = 11;
|
||||||
|
pub const RDX: c_int = 12;
|
||||||
|
pub const RSI: c_int = 13;
|
||||||
|
pub const RDI: c_int = 14;
|
||||||
|
pub const ORIG_RAX: c_int = 15;
|
||||||
|
pub const RIP: c_int = 16;
|
||||||
|
pub const CS: c_int = 17;
|
||||||
|
pub const EFLAGS: c_int = 18;
|
||||||
|
pub const RSP: c_int = 19;
|
||||||
|
pub const SS: c_int = 20;
|
||||||
|
pub const FS_BASE: c_int = 21;
|
||||||
|
pub const GS_BASE: c_int = 22;
|
||||||
|
pub const DS: c_int = 23;
|
||||||
|
pub const ES: c_int = 24;
|
||||||
|
pub const FS: c_int = 25;
|
||||||
|
pub const GS: c_int = 26;
|
||||||
|
|
||||||
|
pub const MAP_32BIT: c_int = 0x0040;
|
||||||
|
|
||||||
|
pub const SIGSTKSZ: size_t = 8192;
|
||||||
|
pub const MINSIGSTKSZ: size_t = 2048;
|
||||||
|
|
@ -0,0 +1,562 @@
|
||||||
|
//! Hermit C type definitions
|
||||||
|
|
||||||
|
use crate::prelude::*;
|
||||||
|
|
||||||
|
pub type intmax_t = i64;
|
||||||
|
pub type uintmax_t = u64;
|
||||||
|
pub type intptr_t = isize;
|
||||||
|
pub type uintptr_t = usize;
|
||||||
|
|
||||||
|
pub type size_t = usize;
|
||||||
|
pub type ssize_t = isize;
|
||||||
|
pub type ptrdiff_t = isize;
|
||||||
|
|
||||||
|
pub type clockid_t = i32;
|
||||||
|
pub type in_addr_t = u32;
|
||||||
|
pub type in_port_t = u16;
|
||||||
|
pub type mode_t = u32;
|
||||||
|
pub type nfds_t = usize;
|
||||||
|
pub type pid_t = i32;
|
||||||
|
pub type sa_family_t = u8;
|
||||||
|
pub type socklen_t = u32;
|
||||||
|
pub type time_t = i64;
|
||||||
|
|
||||||
|
s! {
|
||||||
|
pub struct addrinfo {
|
||||||
|
pub ai_flags: i32,
|
||||||
|
pub ai_family: i32,
|
||||||
|
pub ai_socktype: i32,
|
||||||
|
pub ai_protocol: i32,
|
||||||
|
pub ai_addrlen: socklen_t,
|
||||||
|
pub ai_canonname: *mut c_char,
|
||||||
|
pub ai_addr: *mut sockaddr,
|
||||||
|
pub ai_next: *mut addrinfo,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct dirent64 {
|
||||||
|
pub d_ino: u64,
|
||||||
|
pub d_off: i64,
|
||||||
|
pub d_reclen: u16,
|
||||||
|
pub d_type: u8,
|
||||||
|
pub d_name: [c_char; 256],
|
||||||
|
}
|
||||||
|
|
||||||
|
#[repr(align(4))]
|
||||||
|
pub struct in6_addr {
|
||||||
|
pub s6_addr: [u8; 16],
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct in_addr {
|
||||||
|
pub s_addr: in_addr_t,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct iovec {
|
||||||
|
iov_base: *mut c_void,
|
||||||
|
iov_len: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct pollfd {
|
||||||
|
pub fd: i32,
|
||||||
|
pub events: i16,
|
||||||
|
pub revents: i16,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct sockaddr {
|
||||||
|
pub sa_len: u8,
|
||||||
|
pub sa_family: sa_family_t,
|
||||||
|
pub sa_data: [c_char; 14],
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct sockaddr_in {
|
||||||
|
pub sin_len: u8,
|
||||||
|
pub sin_family: sa_family_t,
|
||||||
|
pub sin_port: in_port_t,
|
||||||
|
pub sin_addr: in_addr,
|
||||||
|
pub sin_zero: [c_char; 8],
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct sockaddr_in6 {
|
||||||
|
pub sin6_len: u8,
|
||||||
|
pub sin6_family: sa_family_t,
|
||||||
|
pub sin6_port: in_port_t,
|
||||||
|
pub sin6_flowinfo: u32,
|
||||||
|
pub sin6_addr: in6_addr,
|
||||||
|
pub sin6_scope_id: u32,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct sockaddr_storage {
|
||||||
|
pub ss_len: u8,
|
||||||
|
pub ss_family: sa_family_t,
|
||||||
|
__ss_pad1: Padding<[u8; 6]>,
|
||||||
|
__ss_align: i64,
|
||||||
|
__ss_pad2: Padding<[u8; 112]>,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct stat {
|
||||||
|
pub st_dev: u64,
|
||||||
|
pub st_ino: u64,
|
||||||
|
pub st_nlink: u64,
|
||||||
|
pub st_mode: mode_t,
|
||||||
|
pub st_uid: u32,
|
||||||
|
pub st_gid: u32,
|
||||||
|
pub st_rdev: u64,
|
||||||
|
pub st_size: i64,
|
||||||
|
pub st_blksize: i64,
|
||||||
|
pub st_blocks: i64,
|
||||||
|
pub st_atim: timespec,
|
||||||
|
pub st_mtim: timespec,
|
||||||
|
pub st_ctim: timespec,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Default)]
|
||||||
|
pub struct timespec {
|
||||||
|
pub tv_sec: time_t,
|
||||||
|
pub tv_nsec: i32,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub const AF_UNSPEC: i32 = 0;
|
||||||
|
pub const AF_INET: i32 = 3;
|
||||||
|
pub const AF_INET6: i32 = 1;
|
||||||
|
pub const AF_VSOCK: i32 = 2;
|
||||||
|
|
||||||
|
pub const CLOCK_REALTIME: clockid_t = 1;
|
||||||
|
pub const CLOCK_MONOTONIC: clockid_t = 4;
|
||||||
|
|
||||||
|
pub const DT_UNKNOWN: u8 = 0;
|
||||||
|
pub const DT_FIFO: u8 = 1;
|
||||||
|
pub const DT_CHR: u8 = 2;
|
||||||
|
pub const DT_DIR: u8 = 4;
|
||||||
|
pub const DT_BLK: u8 = 6;
|
||||||
|
pub const DT_REG: u8 = 8;
|
||||||
|
pub const DT_LNK: u8 = 10;
|
||||||
|
pub const DT_SOCK: u8 = 12;
|
||||||
|
pub const DT_WHT: u8 = 14;
|
||||||
|
|
||||||
|
pub const EAI_AGAIN: i32 = 2;
|
||||||
|
pub const EAI_BADFLAGS: i32 = 3;
|
||||||
|
pub const EAI_FAIL: i32 = 4;
|
||||||
|
pub const EAI_FAMILY: i32 = 5;
|
||||||
|
pub const EAI_MEMORY: i32 = 6;
|
||||||
|
pub const EAI_NODATA: i32 = 7;
|
||||||
|
pub const EAI_NONAME: i32 = 8;
|
||||||
|
pub const EAI_SERVICE: i32 = 9;
|
||||||
|
pub const EAI_SOCKTYPE: i32 = 10;
|
||||||
|
pub const EAI_SYSTEM: i32 = 11;
|
||||||
|
pub const EAI_OVERFLOW: i32 = 14;
|
||||||
|
|
||||||
|
pub const EFD_SEMAPHORE: i16 = 0o1;
|
||||||
|
pub const EFD_NONBLOCK: i16 = 0o4000;
|
||||||
|
pub const EFD_CLOEXEC: i16 = 0o40000;
|
||||||
|
|
||||||
|
pub const F_DUPFD: i32 = 0;
|
||||||
|
pub const F_GETFD: i32 = 1;
|
||||||
|
pub const F_SETFD: i32 = 2;
|
||||||
|
pub const F_GETFL: i32 = 3;
|
||||||
|
pub const F_SETFL: i32 = 4;
|
||||||
|
|
||||||
|
pub const FD_CLOEXEC: i32 = 1;
|
||||||
|
|
||||||
|
pub const FIONBIO: i32 = u32_cast_int(0x8008667e);
|
||||||
|
|
||||||
|
pub const FUTEX_RELATIVE_TIMEOUT: u32 = 1;
|
||||||
|
|
||||||
|
pub const IP_TOS: i32 = 1;
|
||||||
|
pub const IP_TTL: i32 = 2;
|
||||||
|
pub const IP_ADD_MEMBERSHIP: i32 = 3;
|
||||||
|
pub const IP_DROP_MEMBERSHIP: i32 = 4;
|
||||||
|
pub const IP_MULTICAST_TTL: i32 = 5;
|
||||||
|
pub const IP_MULTICAST_LOOP: i32 = 7;
|
||||||
|
|
||||||
|
pub const IPPROTO_IP: i32 = 0;
|
||||||
|
pub const IPPROTO_TCP: i32 = 6;
|
||||||
|
pub const IPPROTO_UDP: i32 = 17;
|
||||||
|
pub const IPPROTO_IPV6: i32 = 41;
|
||||||
|
|
||||||
|
pub const IPV6_ADD_MEMBERSHIP: i32 = 12;
|
||||||
|
pub const IPV6_DROP_MEMBERSHIP: i32 = 13;
|
||||||
|
pub const IPV6_MULTICAST_LOOP: i32 = 19;
|
||||||
|
pub const IPV6_V6ONLY: i32 = 27;
|
||||||
|
|
||||||
|
pub const MSG_PEEK: i32 = 1;
|
||||||
|
|
||||||
|
pub const O_RDONLY: i32 = 0o0;
|
||||||
|
pub const O_WRONLY: i32 = 0o1;
|
||||||
|
pub const O_RDWR: i32 = 0o2;
|
||||||
|
pub const O_CREAT: i32 = 0o100;
|
||||||
|
pub const O_EXCL: i32 = 0o200;
|
||||||
|
pub const O_TRUNC: i32 = 0o1000;
|
||||||
|
pub const O_APPEND: i32 = 0o2000;
|
||||||
|
pub const O_NONBLOCK: i32 = 0o4000;
|
||||||
|
pub const O_DIRECTORY: i32 = 0o200000;
|
||||||
|
|
||||||
|
pub const POLLIN: i16 = 0x1;
|
||||||
|
pub const POLLPRI: i16 = 0x2;
|
||||||
|
pub const POLLOUT: i16 = 0x4;
|
||||||
|
pub const POLLERR: i16 = 0x8;
|
||||||
|
pub const POLLHUP: i16 = 0x10;
|
||||||
|
pub const POLLNVAL: i16 = 0x20;
|
||||||
|
pub const POLLRDNORM: i16 = 0x040;
|
||||||
|
pub const POLLRDBAND: i16 = 0x080;
|
||||||
|
pub const POLLWRNORM: i16 = 0x0100;
|
||||||
|
pub const POLLWRBAND: i16 = 0x0200;
|
||||||
|
pub const POLLRDHUP: i16 = 0x2000;
|
||||||
|
|
||||||
|
pub const S_IRWXU: mode_t = 0o0700;
|
||||||
|
pub const S_IRUSR: mode_t = 0o0400;
|
||||||
|
pub const S_IWUSR: mode_t = 0o0200;
|
||||||
|
pub const S_IXUSR: mode_t = 0o0100;
|
||||||
|
pub const S_IRWXG: mode_t = 0o0070;
|
||||||
|
pub const S_IRGRP: mode_t = 0o0040;
|
||||||
|
pub const S_IWGRP: mode_t = 0o0020;
|
||||||
|
pub const S_IXGRP: mode_t = 0o0010;
|
||||||
|
pub const S_IRWXO: mode_t = 0o0007;
|
||||||
|
pub const S_IROTH: mode_t = 0o0004;
|
||||||
|
pub const S_IWOTH: mode_t = 0o0002;
|
||||||
|
pub const S_IXOTH: mode_t = 0o0001;
|
||||||
|
|
||||||
|
pub const S_IFMT: mode_t = 0o17_0000;
|
||||||
|
pub const S_IFSOCK: mode_t = 0o14_0000;
|
||||||
|
pub const S_IFLNK: mode_t = 0o12_0000;
|
||||||
|
pub const S_IFREG: mode_t = 0o10_0000;
|
||||||
|
pub const S_IFBLK: mode_t = 0o6_0000;
|
||||||
|
pub const S_IFDIR: mode_t = 0o4_0000;
|
||||||
|
pub const S_IFCHR: mode_t = 0o2_0000;
|
||||||
|
pub const S_IFIFO: mode_t = 0o1_0000;
|
||||||
|
|
||||||
|
pub const SHUT_RD: i32 = 0;
|
||||||
|
pub const SHUT_WR: i32 = 1;
|
||||||
|
pub const SHUT_RDWR: i32 = 2;
|
||||||
|
|
||||||
|
pub const SO_REUSEADDR: i32 = 0x0004;
|
||||||
|
pub const SO_KEEPALIVE: i32 = 0x0008;
|
||||||
|
pub const SO_BROADCAST: i32 = 0x0020;
|
||||||
|
pub const SO_LINGER: i32 = 0x0080;
|
||||||
|
pub const SO_SNDBUF: i32 = 0x1001;
|
||||||
|
pub const SO_RCVBUF: i32 = 0x1002;
|
||||||
|
pub const SO_SNDTIMEO: i32 = 0x1005;
|
||||||
|
pub const SO_RCVTIMEO: i32 = 0x1006;
|
||||||
|
pub const SO_ERROR: i32 = 0x1007;
|
||||||
|
|
||||||
|
pub const SOCK_STREAM: i32 = 1;
|
||||||
|
pub const SOCK_DGRAM: i32 = 2;
|
||||||
|
pub const SOCK_NONBLOCK: i32 = 0o4000;
|
||||||
|
pub const SOCK_CLOEXEC: i32 = 0o40000;
|
||||||
|
|
||||||
|
pub const SOL_SOCKET: i32 = 4095;
|
||||||
|
|
||||||
|
pub const STDIN_FILENO: c_int = 0;
|
||||||
|
pub const STDOUT_FILENO: c_int = 1;
|
||||||
|
pub const STDERR_FILENO: c_int = 2;
|
||||||
|
|
||||||
|
pub const TCP_NODELAY: i32 = 1;
|
||||||
|
|
||||||
|
pub const EPERM: i32 = 1;
|
||||||
|
pub const ENOENT: i32 = 2;
|
||||||
|
pub const ESRCH: i32 = 3;
|
||||||
|
pub const EINTR: i32 = 4;
|
||||||
|
pub const EIO: i32 = 5;
|
||||||
|
pub const ENXIO: i32 = 6;
|
||||||
|
pub const E2BIG: i32 = 7;
|
||||||
|
pub const ENOEXEC: i32 = 8;
|
||||||
|
pub const EBADF: i32 = 9;
|
||||||
|
pub const ECHILD: i32 = 10;
|
||||||
|
pub const EAGAIN: i32 = 11;
|
||||||
|
pub const ENOMEM: i32 = 12;
|
||||||
|
pub const EACCES: i32 = 13;
|
||||||
|
pub const EFAULT: i32 = 14;
|
||||||
|
pub const ENOTBLK: i32 = 15;
|
||||||
|
pub const EBUSY: i32 = 16;
|
||||||
|
pub const EEXIST: i32 = 17;
|
||||||
|
pub const EXDEV: i32 = 18;
|
||||||
|
pub const ENODEV: i32 = 19;
|
||||||
|
pub const ENOTDIR: i32 = 20;
|
||||||
|
pub const EISDIR: i32 = 21;
|
||||||
|
pub const EINVAL: i32 = 22;
|
||||||
|
pub const ENFILE: i32 = 23;
|
||||||
|
pub const EMFILE: i32 = 24;
|
||||||
|
pub const ENOTTY: i32 = 25;
|
||||||
|
pub const ETXTBSY: i32 = 26;
|
||||||
|
pub const EFBIG: i32 = 27;
|
||||||
|
pub const ENOSPC: i32 = 28;
|
||||||
|
pub const ESPIPE: i32 = 29;
|
||||||
|
pub const EROFS: i32 = 30;
|
||||||
|
pub const EMLINK: i32 = 31;
|
||||||
|
pub const EPIPE: i32 = 32;
|
||||||
|
pub const EDOM: i32 = 33;
|
||||||
|
pub const ERANGE: i32 = 34;
|
||||||
|
pub const EDEADLK: i32 = 35;
|
||||||
|
pub const ENAMETOOLONG: i32 = 36;
|
||||||
|
pub const ENOLCK: i32 = 37;
|
||||||
|
pub const ENOSYS: i32 = 38;
|
||||||
|
pub const ENOTEMPTY: i32 = 39;
|
||||||
|
pub const ELOOP: i32 = 40;
|
||||||
|
pub const EWOULDBLOCK: i32 = EAGAIN;
|
||||||
|
pub const ENOMSG: i32 = 42;
|
||||||
|
pub const EIDRM: i32 = 43;
|
||||||
|
pub const ECHRNG: i32 = 44;
|
||||||
|
pub const EL2NSYNC: i32 = 45;
|
||||||
|
pub const EL3HLT: i32 = 46;
|
||||||
|
pub const EL3RST: i32 = 47;
|
||||||
|
pub const ELNRNG: i32 = 48;
|
||||||
|
pub const EUNATCH: i32 = 49;
|
||||||
|
pub const ENOCSI: i32 = 50;
|
||||||
|
pub const EL2HLT: i32 = 51;
|
||||||
|
pub const EBADE: i32 = 52;
|
||||||
|
pub const EBADR: i32 = 53;
|
||||||
|
pub const EXFULL: i32 = 54;
|
||||||
|
pub const ENOANO: i32 = 55;
|
||||||
|
pub const EBADRQC: i32 = 56;
|
||||||
|
pub const EBADSLT: i32 = 57;
|
||||||
|
pub const EDEADLOCK: i32 = EDEADLK;
|
||||||
|
pub const EBFONT: i32 = 59;
|
||||||
|
pub const ENOSTR: i32 = 60;
|
||||||
|
pub const ENODATA: i32 = 61;
|
||||||
|
pub const ETIME: i32 = 62;
|
||||||
|
pub const ENOSR: i32 = 63;
|
||||||
|
pub const ENONET: i32 = 64;
|
||||||
|
pub const ENOPKG: i32 = 65;
|
||||||
|
pub const EREMOTE: i32 = 66;
|
||||||
|
pub const ENOLINK: i32 = 67;
|
||||||
|
pub const EADV: i32 = 68;
|
||||||
|
pub const ESRMNT: i32 = 69;
|
||||||
|
pub const ECOMM: i32 = 70;
|
||||||
|
pub const EPROTO: i32 = 71;
|
||||||
|
pub const EMULTIHOP: i32 = 72;
|
||||||
|
pub const EDOTDOT: i32 = 73;
|
||||||
|
pub const EBADMSG: i32 = 74;
|
||||||
|
pub const EOVERFLOW: i32 = 75;
|
||||||
|
pub const ENOTUNIQ: i32 = 76;
|
||||||
|
pub const EBADFD: i32 = 77;
|
||||||
|
pub const EREMCHG: i32 = 78;
|
||||||
|
pub const ELIBACC: i32 = 79;
|
||||||
|
pub const ELIBBAD: i32 = 80;
|
||||||
|
pub const ELIBSCN: i32 = 81;
|
||||||
|
pub const ELIBMAX: i32 = 82;
|
||||||
|
pub const ELIBEXEC: i32 = 83;
|
||||||
|
pub const EILSEQ: i32 = 84;
|
||||||
|
pub const ERESTART: i32 = 85;
|
||||||
|
pub const ESTRPIPE: i32 = 86;
|
||||||
|
pub const EUSERS: i32 = 87;
|
||||||
|
pub const ENOTSOCK: i32 = 88;
|
||||||
|
pub const EDESTADDRREQ: i32 = 89;
|
||||||
|
pub const EMSGSIZE: i32 = 90;
|
||||||
|
pub const EPROTOTYPE: i32 = 91;
|
||||||
|
pub const ENOPROTOOPT: i32 = 92;
|
||||||
|
pub const EPROTONOSUPPORT: i32 = 93;
|
||||||
|
pub const ESOCKTNOSUPPORT: i32 = 94;
|
||||||
|
pub const EOPNOTSUPP: i32 = 95;
|
||||||
|
pub const EPFNOSUPPORT: i32 = 96;
|
||||||
|
pub const EAFNOSUPPORT: i32 = 97;
|
||||||
|
pub const EADDRINUSE: i32 = 98;
|
||||||
|
pub const EADDRNOTAVAIL: i32 = 99;
|
||||||
|
pub const ENETDOWN: i32 = 100;
|
||||||
|
pub const ENETUNREACH: i32 = 101;
|
||||||
|
pub const ENETRESET: i32 = 102;
|
||||||
|
pub const ECONNABORTED: i32 = 103;
|
||||||
|
pub const ECONNRESET: i32 = 104;
|
||||||
|
pub const ENOBUFS: i32 = 105;
|
||||||
|
pub const EISCONN: i32 = 106;
|
||||||
|
pub const ENOTCONN: i32 = 107;
|
||||||
|
pub const ESHUTDOWN: i32 = 108;
|
||||||
|
pub const ETOOMANYREFS: i32 = 109;
|
||||||
|
pub const ETIMEDOUT: i32 = 110;
|
||||||
|
pub const ECONNREFUSED: i32 = 111;
|
||||||
|
pub const EHOSTDOWN: i32 = 112;
|
||||||
|
pub const EHOSTUNREACH: i32 = 113;
|
||||||
|
pub const EALREADY: i32 = 114;
|
||||||
|
pub const EINPROGRESS: i32 = 115;
|
||||||
|
pub const ESTALE: i32 = 116;
|
||||||
|
pub const EUCLEAN: i32 = 117;
|
||||||
|
pub const ENOTNAM: i32 = 118;
|
||||||
|
pub const ENAVAIL: i32 = 119;
|
||||||
|
pub const EISNAM: i32 = 120;
|
||||||
|
pub const EREMOTEIO: i32 = 121;
|
||||||
|
pub const EDQUOT: i32 = 122;
|
||||||
|
pub const ENOMEDIUM: i32 = 123;
|
||||||
|
pub const EMEDIUMTYPE: i32 = 124;
|
||||||
|
pub const ECANCELED: i32 = 125;
|
||||||
|
pub const ENOKEY: i32 = 126;
|
||||||
|
pub const EKEYEXPIRED: i32 = 127;
|
||||||
|
pub const EKEYREVOKED: i32 = 128;
|
||||||
|
pub const EKEYREJECTED: i32 = 129;
|
||||||
|
pub const EOWNERDEAD: i32 = 130;
|
||||||
|
pub const ENOTRECOVERABLE: i32 = 131;
|
||||||
|
pub const ERFKILL: i32 = 132;
|
||||||
|
pub const EHWPOISON: i32 = 133;
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
#[link_name = "sys_alloc"]
|
||||||
|
pub fn alloc(size: usize, align: usize) -> *mut u8;
|
||||||
|
|
||||||
|
#[link_name = "sys_alloc_zeroed"]
|
||||||
|
pub fn alloc_zeroed(size: usize, align: usize) -> *mut u8;
|
||||||
|
|
||||||
|
#[link_name = "sys_realloc"]
|
||||||
|
pub fn realloc(ptr: *mut u8, size: usize, align: usize, new_size: usize) -> *mut u8;
|
||||||
|
|
||||||
|
#[link_name = "sys_dealloc"]
|
||||||
|
pub fn dealloc(ptr: *mut u8, size: usize, align: usize);
|
||||||
|
|
||||||
|
#[link_name = "sys_exit"]
|
||||||
|
pub fn exit(status: i32) -> !;
|
||||||
|
|
||||||
|
#[link_name = "sys_abort"]
|
||||||
|
pub fn abort() -> !;
|
||||||
|
|
||||||
|
#[link_name = "sys_errno"]
|
||||||
|
pub fn errno() -> i32;
|
||||||
|
|
||||||
|
#[link_name = "sys_clock_gettime"]
|
||||||
|
pub fn clock_gettime(clockid: clockid_t, tp: *mut timespec) -> i32;
|
||||||
|
|
||||||
|
#[link_name = "sys_nanosleep"]
|
||||||
|
pub fn nanosleep(req: *const timespec) -> i32;
|
||||||
|
|
||||||
|
#[link_name = "sys_available_parallelism"]
|
||||||
|
pub fn available_parallelism() -> usize;
|
||||||
|
|
||||||
|
#[link_name = "sys_futex_wait"]
|
||||||
|
pub fn futex_wait(
|
||||||
|
address: *mut u32,
|
||||||
|
expected: u32,
|
||||||
|
timeout: *const timespec,
|
||||||
|
flags: u32,
|
||||||
|
) -> i32;
|
||||||
|
|
||||||
|
#[link_name = "sys_futex_wake"]
|
||||||
|
pub fn futex_wake(address: *mut u32, count: i32) -> i32;
|
||||||
|
|
||||||
|
#[link_name = "sys_stat"]
|
||||||
|
pub fn stat(path: *const c_char, stat: *mut stat) -> i32;
|
||||||
|
|
||||||
|
#[link_name = "sys_fstat"]
|
||||||
|
pub fn fstat(fd: i32, stat: *mut stat) -> i32;
|
||||||
|
|
||||||
|
#[link_name = "sys_lstat"]
|
||||||
|
pub fn lstat(path: *const c_char, stat: *mut stat) -> i32;
|
||||||
|
|
||||||
|
#[link_name = "sys_open"]
|
||||||
|
pub fn open(path: *const c_char, flags: i32, mode: mode_t) -> i32;
|
||||||
|
|
||||||
|
#[link_name = "sys_unlink"]
|
||||||
|
pub fn unlink(path: *const c_char) -> i32;
|
||||||
|
|
||||||
|
#[link_name = "sys_mkdir"]
|
||||||
|
pub fn mkdir(path: *const c_char, mode: mode_t) -> i32;
|
||||||
|
|
||||||
|
#[link_name = "sys_rmdir"]
|
||||||
|
pub fn rmdir(path: *const c_char) -> i32;
|
||||||
|
|
||||||
|
#[link_name = "sys_read"]
|
||||||
|
pub fn read(fd: i32, buf: *mut u8, len: usize) -> isize;
|
||||||
|
|
||||||
|
#[link_name = "sys_write"]
|
||||||
|
pub fn write(fd: i32, buf: *const u8, len: usize) -> isize;
|
||||||
|
|
||||||
|
#[link_name = "sys_readv"]
|
||||||
|
pub fn readv(fd: i32, iov: *const iovec, iovcnt: usize) -> isize;
|
||||||
|
|
||||||
|
#[link_name = "sys_writev"]
|
||||||
|
pub fn writev(fd: i32, iov: *const iovec, iovcnt: usize) -> isize;
|
||||||
|
|
||||||
|
#[link_name = "sys_close"]
|
||||||
|
pub fn close(fd: i32) -> i32;
|
||||||
|
|
||||||
|
#[link_name = "sys_dup"]
|
||||||
|
pub fn dup(fd: i32) -> i32;
|
||||||
|
|
||||||
|
#[link_name = "sys_fcntl"]
|
||||||
|
pub fn fcntl(fd: i32, cmd: i32, arg: i32) -> i32;
|
||||||
|
|
||||||
|
#[link_name = "sys_getdents64"]
|
||||||
|
pub fn getdents64(fd: i32, dirp: *mut dirent64, count: usize) -> isize;
|
||||||
|
|
||||||
|
#[link_name = "sys_getaddrinfo"]
|
||||||
|
pub fn getaddrinfo(
|
||||||
|
nodename: *const c_char,
|
||||||
|
servname: *const c_char,
|
||||||
|
hints: *const addrinfo,
|
||||||
|
res: *mut *mut addrinfo,
|
||||||
|
) -> i32;
|
||||||
|
|
||||||
|
#[link_name = "sys_freeaddrinfo"]
|
||||||
|
pub fn freeaddrinfo(ai: *mut addrinfo);
|
||||||
|
|
||||||
|
#[link_name = "sys_socket"]
|
||||||
|
pub fn socket(domain: i32, ty: i32, protocol: i32) -> i32;
|
||||||
|
|
||||||
|
#[link_name = "sys_bind"]
|
||||||
|
pub fn bind(sockfd: i32, addr: *const sockaddr, addrlen: socklen_t) -> i32;
|
||||||
|
|
||||||
|
#[link_name = "sys_listen"]
|
||||||
|
pub fn listen(sockfd: i32, backlog: i32) -> i32;
|
||||||
|
|
||||||
|
#[link_name = "sys_accept"]
|
||||||
|
pub fn accept(sockfd: i32, addr: *mut sockaddr, addrlen: *mut socklen_t) -> i32;
|
||||||
|
|
||||||
|
#[link_name = "sys_connect"]
|
||||||
|
pub fn connect(sockfd: i32, addr: *const sockaddr, addrlen: socklen_t) -> i32;
|
||||||
|
|
||||||
|
#[link_name = "sys_recv"]
|
||||||
|
pub fn recv(sockfd: i32, buf: *mut u8, len: usize, flags: i32) -> isize;
|
||||||
|
|
||||||
|
#[link_name = "sys_recvfrom"]
|
||||||
|
pub fn recvfrom(
|
||||||
|
sockfd: i32,
|
||||||
|
buf: *mut c_void,
|
||||||
|
len: usize,
|
||||||
|
flags: i32,
|
||||||
|
addr: *mut sockaddr,
|
||||||
|
addrlen: *mut socklen_t,
|
||||||
|
) -> isize;
|
||||||
|
|
||||||
|
#[link_name = "sys_send"]
|
||||||
|
pub fn send(sockfd: i32, buf: *const c_void, len: usize, flags: i32) -> isize;
|
||||||
|
|
||||||
|
#[link_name = "sys_sendto"]
|
||||||
|
pub fn sendto(
|
||||||
|
sockfd: i32,
|
||||||
|
buf: *const c_void,
|
||||||
|
len: usize,
|
||||||
|
flags: i32,
|
||||||
|
to: *const sockaddr,
|
||||||
|
tolen: socklen_t,
|
||||||
|
) -> isize;
|
||||||
|
|
||||||
|
#[link_name = "sys_getpeername"]
|
||||||
|
pub fn getpeername(sockfd: i32, addr: *mut sockaddr, addrlen: *mut socklen_t) -> i32;
|
||||||
|
|
||||||
|
#[link_name = "sys_getsockname"]
|
||||||
|
pub fn getsockname(sockfd: i32, addr: *mut sockaddr, addrlen: *mut socklen_t) -> i32;
|
||||||
|
|
||||||
|
#[link_name = "sys_getsockopt"]
|
||||||
|
pub fn getsockopt(
|
||||||
|
sockfd: i32,
|
||||||
|
level: i32,
|
||||||
|
optname: i32,
|
||||||
|
optval: *mut c_void,
|
||||||
|
optlen: *mut socklen_t,
|
||||||
|
) -> i32;
|
||||||
|
|
||||||
|
#[link_name = "sys_setsockopt"]
|
||||||
|
pub fn setsockopt(
|
||||||
|
sockfd: i32,
|
||||||
|
level: i32,
|
||||||
|
optname: i32,
|
||||||
|
optval: *const c_void,
|
||||||
|
optlen: socklen_t,
|
||||||
|
) -> i32;
|
||||||
|
|
||||||
|
#[link_name = "sys_ioctl"]
|
||||||
|
pub fn ioctl(sockfd: i32, cmd: i32, argp: *mut c_void) -> i32;
|
||||||
|
|
||||||
|
#[link_name = "sys_shutdown"]
|
||||||
|
pub fn shutdown(sockfd: i32, how: i32) -> i32;
|
||||||
|
|
||||||
|
#[link_name = "sys_eventfd"]
|
||||||
|
pub fn eventfd(initval: u64, flags: i16) -> i32;
|
||||||
|
|
||||||
|
#[link_name = "sys_poll"]
|
||||||
|
pub fn poll(fds: *mut pollfd, nfds: nfds_t, timeout: i32) -> i32;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,309 @@
|
||||||
|
//! Raw FFI bindings to platform system libraries.
|
||||||
|
//!
|
||||||
|
//! # Usage Guidelines
|
||||||
|
//!
|
||||||
|
//! `libc` exposes non-Rust interfaces in Rust, which makes for some caveats to its use that are
|
||||||
|
//! not present in most Rust libraries. Observing the following guidelines are recommended to help
|
||||||
|
//! avoid soundness and stability pitfalls.
|
||||||
|
//!
|
||||||
|
//! 1. *Never* construct a `libc` struct with `MaybeUninit::uninit()`, initialize it, then call
|
||||||
|
//! `assume_init`. Many structures have padding fields or may gain fields in the future, and
|
||||||
|
//! it is far too easy to end up calling `assume_init` on partially initialized data.
|
||||||
|
//!
|
||||||
|
//! Instead, use `MaybeUninit::zeroed()` or the `Default` implementations that are slowly being
|
||||||
|
//! added. Alternatively, access fields only via raw pointer without ever using `assume_init`.
|
||||||
|
//!
|
||||||
|
//! 2. Avoid relying on the exact value of constants, the exact length of arrays, or the exact
|
||||||
|
//! types of type aliases, as they may change across `libc` versions. That is, if `libc`
|
||||||
|
//! contains code like:
|
||||||
|
//!
|
||||||
|
//! <!-- relevant for how rustdoc displays these structs:
|
||||||
|
//! https://github.com/rust-lang/rust/issues/102456 -->
|
||||||
|
//! ```ignore
|
||||||
|
//! const IFNAMSIZ: usize = 16;
|
||||||
|
//!
|
||||||
|
//! pub struct ifreq {
|
||||||
|
//! pub ifr_name: [c_char; IFNAMSIZ],
|
||||||
|
//! // ...
|
||||||
|
//! }
|
||||||
|
//!
|
||||||
|
//! extern "C" {
|
||||||
|
//! pub fn time(time: *mut time_t) -> time_t;
|
||||||
|
//! }
|
||||||
|
//! ```
|
||||||
|
//!
|
||||||
|
//! Then avoid writing code like:
|
||||||
|
//!
|
||||||
|
//! ```ignore
|
||||||
|
//! // Bad assumption that the length will always be 16.
|
||||||
|
//! fn takes_ifr_name(ifr_name: [c_char; 16]) { /* ... */ }
|
||||||
|
//!
|
||||||
|
//! fn process_ifr(ifr: ifreq) {
|
||||||
|
//! takes_ifr_name(ifr.ifr_name);
|
||||||
|
//! }
|
||||||
|
//!
|
||||||
|
//! // Bad assumption that `time_t` will always be an `i64`. Use `-> time_t` instead, or
|
||||||
|
//! // explicitly cast to an `i64`.`
|
||||||
|
//! fn get_time() -> i64 {
|
||||||
|
//! unsafe { time(ptr::null_mut()) }
|
||||||
|
//! }
|
||||||
|
//!
|
||||||
|
//! ```
|
||||||
|
//!
|
||||||
|
//! For `takes_ifr_name`, use `[c_char; IFNAMSIZ]` or just `&[c_char]` instead. For `get_time`,
|
||||||
|
//! return a `time_t` or explicitly cast to an `i64`.
|
||||||
|
//!
|
||||||
|
//! Along the same lines, if you write code along the lines of `assert_eq!(libc::ELAST, 97)`,
|
||||||
|
//! expect that there may be a release where this starts to fail.
|
||||||
|
//!
|
||||||
|
//! 3. Do not name `__c_anonymous_*` types anywhere, which exist to represent anonymous fields in
|
||||||
|
//! C. For example, FreeBSD defines:
|
||||||
|
//!
|
||||||
|
//! ```c
|
||||||
|
//! struct filestat {
|
||||||
|
//! int fs_type;
|
||||||
|
//! // ...
|
||||||
|
//! struct { struct filestat stqe_next; } next;
|
||||||
|
//! };
|
||||||
|
//! ```
|
||||||
|
//!
|
||||||
|
//! Which is represented in `libc` as:
|
||||||
|
//!
|
||||||
|
//! ```ignore
|
||||||
|
//! struct filestat {
|
||||||
|
//! fs_type: c_int,
|
||||||
|
//! // ...
|
||||||
|
//! next: __c_anonymous_filestat,
|
||||||
|
//! }
|
||||||
|
//!
|
||||||
|
//! struct __c_anonymous_filestat { stqe_next: *mut filestat }
|
||||||
|
//! ```
|
||||||
|
//!
|
||||||
|
//! Accessing `some_filestat.next.stqe_next` is completely fine, but `__c_anonymous_filestat`
|
||||||
|
//! should not be used anywhere (e.g. in a function signature). This is done to permit `libc` to
|
||||||
|
//! switch to anonymous fields if the feature is ever added to Rust.
|
||||||
|
//!
|
||||||
|
//! 4. Avoid accessing fields with names such as `__reserved`, `_pad`, or `_spare`. Usually the
|
||||||
|
//! platform libraries use these to allow adding new fields without changing the size of a
|
||||||
|
//! struct, but this means their types change frequently.
|
||||||
|
//!
|
||||||
|
//! 5. Be aware of deprecation warnings. These are used as a way to migrate necessary API changes.
|
||||||
|
//!
|
||||||
|
//! # Cargo Features
|
||||||
|
//!
|
||||||
|
//! - `std`: by default `libc` assumes that the standard library contains link directives necessary
|
||||||
|
//! to use the APIs in this crate. If `std` is disabled, `libc` will emit the directives instead.
|
||||||
|
//!
|
||||||
|
//! This feature is slated for removal in `libc` 1.0. The intention is that no-std users of
|
||||||
|
//! `libc` should use their own `#[link]` attributes, `rustc-link-lib` build script directives,
|
||||||
|
//! or `-l` arguments for only the system libraries they need to link, rather than `libc`
|
||||||
|
//! possibly linking more than is needed or available. If you are using `libc` without the `std`
|
||||||
|
//! feature, consider starting to add link directives now for a smoother 1.0 transition.
|
||||||
|
//!
|
||||||
|
//! - `extra_traits`: all types in `libc` implement `Clone`, `Copy`, and `Debug`. The
|
||||||
|
//! `extra_traits` feature adds `Eq`, `Hash`, and `PartialEq`.
|
||||||
|
//!
|
||||||
|
//! This feature is expected to be removed in libc 1.0. Libraries should instead hash or check
|
||||||
|
//! equality of only needed fields.
|
||||||
|
//!
|
||||||
|
//! - The features `const-extern-fn`, `align`, and `use_std` are all deprecated and do nothing.
|
||||||
|
//!
|
||||||
|
//! # Stability Expectations
|
||||||
|
//!
|
||||||
|
//! Due to `libc`'s position in the ecosystem, it can effectively never publish semver-breaking
|
||||||
|
//! releases. However, the API that `libc` binds changes _all the time_; sometimes in ways that
|
||||||
|
//! are harmless, sometimes in ways that are technically API-breaking for all users but unlikely
|
||||||
|
//! to be noticed (e.g. removing deprecated API), and sometimes in ways that are nonbreaking in
|
||||||
|
//! C but translate to breaking changes in Rust (e.g. changing the type of an integer). `libc`
|
||||||
|
//! tries to strike a balance but all of this means that unfortunately, `libc` must occasionally
|
||||||
|
//! ship changes within a semver-compatible release that are technically semver-breaking.
|
||||||
|
//!
|
||||||
|
//! The following are examples of changes that fall into this category:
|
||||||
|
//!
|
||||||
|
//! - Fields are added to a struct that is otherwise exhaustive.
|
||||||
|
//! - Fields with names such as `padding` or `reserved` change type or are removed.
|
||||||
|
//! - The length of an array type changes.
|
||||||
|
//! - A struct field (with available padding) is changed from `int` to `long`.
|
||||||
|
//!
|
||||||
|
//! In general, `libc` aims to follow platform API changes, even when this means changes that are
|
||||||
|
//! user-visible in Rust. There are a few guidelines used here:
|
||||||
|
//!
|
||||||
|
//! - Adding struct fields is not considered breaking, nor is changing fields named `reserved`,
|
||||||
|
//! `padding`, or similar. This is because users are expected to use field-by-field
|
||||||
|
//! initialization.
|
||||||
|
//! - Changing type aliases, values of constants, or array lengths is not considered breaking.
|
||||||
|
//! - If the platform libc has accepted breakage on the C side (typically in the form of removing
|
||||||
|
//! old API), the `libc` crate will follow suit.
|
||||||
|
//! - Where possible, `#[deprecated(...)]` will be used to warn about changes before applying them.
|
||||||
|
//! Alternative mitigations may be considered.
|
||||||
|
//! - Potentially breaking changes will be well-identified in release notes.
|
||||||
|
//! - Beyond this, public API is not expected to change on Tier 1 targets. Tier 2 targets have
|
||||||
|
//! relaxed API stability requirements, and API stability is not enforced on tier 3 targets.
|
||||||
|
//!
|
||||||
|
//! While this section seems scary, keep in mind that it is meant to cover worst-case scenarios. In
|
||||||
|
//! practice, breakage is rare and following the above-discussed [Usage Guidelines](#usage-guidelines)
|
||||||
|
//! means that most `libc` users will never encounter a problem.
|
||||||
|
|
||||||
|
// Make it a bit easier to build without Cargo
|
||||||
|
#![crate_name = "libc"]
|
||||||
|
#![crate_type = "rlib"]
|
||||||
|
// Pretty much all C API doesn't match Rust conventions.
|
||||||
|
#![allow(nonstandard_style)]
|
||||||
|
// Not all macros and all patterns are used on all targets.
|
||||||
|
#![allow(unused_macros)]
|
||||||
|
#![allow(unused_macro_rules)]
|
||||||
|
// All traits should be `Copy` and `Debug`.
|
||||||
|
#![warn(missing_copy_implementations)]
|
||||||
|
#![warn(missing_debug_implementations)]
|
||||||
|
// Downgrade deny to a warning.
|
||||||
|
#![warn(overflowing_literals)]
|
||||||
|
// Prepare for a future upgrade.
|
||||||
|
#![warn(rust_2024_compatibility)]
|
||||||
|
// Things missing for 2024 that are blocked on MSRV or breakage.
|
||||||
|
#![allow(missing_unsafe_on_extern)]
|
||||||
|
#![allow(edition_2024_expr_fragment_specifier)]
|
||||||
|
// Allowed globally, the warning is enabled in individual modules as we work through them
|
||||||
|
#![allow(unsafe_op_in_unsafe_fn)]
|
||||||
|
#![cfg_attr(libc_deny_warnings, deny(warnings))]
|
||||||
|
// Attributes needed when building as part of the standard library
|
||||||
|
#![cfg_attr(feature = "rustc-dep-of-std", feature(link_cfg, no_core))]
|
||||||
|
#![cfg_attr(feature = "rustc-dep-of-std", allow(internal_features))]
|
||||||
|
// Some targets don't need `link_cfg` and emit a warning.
|
||||||
|
#![cfg_attr(feature = "rustc-dep-of-std", allow(unused_features))]
|
||||||
|
// DIFF(1.0): The thread local references that raise this lint were removed in 1.0
|
||||||
|
#![cfg_attr(feature = "rustc-dep-of-std", allow(static_mut_refs))]
|
||||||
|
#![cfg_attr(not(feature = "rustc-dep-of-std"), no_std)]
|
||||||
|
#![cfg_attr(feature = "rustc-dep-of-std", no_core)]
|
||||||
|
|
||||||
|
#[macro_use]
|
||||||
|
mod macros;
|
||||||
|
mod new;
|
||||||
|
|
||||||
|
cfg_if! {
|
||||||
|
if #[cfg(feature = "rustc-dep-of-std")] {
|
||||||
|
extern crate rustc_std_workspace_core as core;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub use core::ffi::c_void;
|
||||||
|
|
||||||
|
#[allow(unused_imports)] // needed while the module is empty on some platforms
|
||||||
|
pub use new::*;
|
||||||
|
|
||||||
|
cfg_if! {
|
||||||
|
if #[cfg(windows)] {
|
||||||
|
mod primitives;
|
||||||
|
pub use crate::primitives::*;
|
||||||
|
|
||||||
|
mod windows;
|
||||||
|
pub use crate::windows::*;
|
||||||
|
|
||||||
|
prelude!();
|
||||||
|
} else if #[cfg(target_os = "fuchsia")] {
|
||||||
|
mod primitives;
|
||||||
|
pub use crate::primitives::*;
|
||||||
|
|
||||||
|
mod fuchsia;
|
||||||
|
pub use crate::fuchsia::*;
|
||||||
|
|
||||||
|
prelude!();
|
||||||
|
} else if #[cfg(target_os = "switch")] {
|
||||||
|
mod primitives;
|
||||||
|
pub use primitives::*;
|
||||||
|
|
||||||
|
mod switch;
|
||||||
|
pub use switch::*;
|
||||||
|
|
||||||
|
prelude!();
|
||||||
|
} else if #[cfg(target_os = "psp")] {
|
||||||
|
mod primitives;
|
||||||
|
pub use primitives::*;
|
||||||
|
|
||||||
|
mod psp;
|
||||||
|
pub use crate::psp::*;
|
||||||
|
|
||||||
|
prelude!();
|
||||||
|
} else if #[cfg(target_os = "vxworks")] {
|
||||||
|
mod primitives;
|
||||||
|
pub use crate::primitives::*;
|
||||||
|
|
||||||
|
mod vxworks;
|
||||||
|
pub use crate::vxworks::*;
|
||||||
|
|
||||||
|
prelude!();
|
||||||
|
} else if #[cfg(target_os = "qurt")] {
|
||||||
|
mod primitives;
|
||||||
|
pub use crate::primitives::*;
|
||||||
|
|
||||||
|
mod qurt;
|
||||||
|
pub use crate::qurt::*;
|
||||||
|
|
||||||
|
prelude!();
|
||||||
|
} else if #[cfg(target_os = "solid_asp3")] {
|
||||||
|
mod primitives;
|
||||||
|
pub use crate::primitives::*;
|
||||||
|
|
||||||
|
mod solid;
|
||||||
|
pub use crate::solid::*;
|
||||||
|
|
||||||
|
prelude!();
|
||||||
|
} else if #[cfg(unix)] {
|
||||||
|
mod primitives;
|
||||||
|
pub use crate::primitives::*;
|
||||||
|
|
||||||
|
mod unix;
|
||||||
|
pub use crate::unix::*;
|
||||||
|
|
||||||
|
prelude!();
|
||||||
|
} else if #[cfg(target_os = "hermit")] {
|
||||||
|
mod primitives;
|
||||||
|
pub use crate::primitives::*;
|
||||||
|
|
||||||
|
mod hermit;
|
||||||
|
pub use crate::hermit::*;
|
||||||
|
|
||||||
|
prelude!();
|
||||||
|
} else if #[cfg(target_os = "teeos")] {
|
||||||
|
mod primitives;
|
||||||
|
pub use primitives::*;
|
||||||
|
|
||||||
|
mod teeos;
|
||||||
|
pub use teeos::*;
|
||||||
|
|
||||||
|
prelude!();
|
||||||
|
} else if #[cfg(target_os = "trusty")] {
|
||||||
|
mod primitives;
|
||||||
|
pub use crate::primitives::*;
|
||||||
|
|
||||||
|
mod trusty;
|
||||||
|
pub use crate::trusty::*;
|
||||||
|
|
||||||
|
prelude!();
|
||||||
|
} else if #[cfg(all(target_env = "sgx", target_vendor = "fortanix"))] {
|
||||||
|
mod primitives;
|
||||||
|
pub use crate::primitives::*;
|
||||||
|
|
||||||
|
mod sgx;
|
||||||
|
pub use crate::sgx::*;
|
||||||
|
|
||||||
|
prelude!();
|
||||||
|
} else if #[cfg(any(target_env = "wasi", target_os = "wasi"))] {
|
||||||
|
mod primitives;
|
||||||
|
pub use crate::primitives::*;
|
||||||
|
|
||||||
|
mod wasi;
|
||||||
|
pub use crate::wasi::*;
|
||||||
|
|
||||||
|
prelude!();
|
||||||
|
} else if #[cfg(target_os = "xous")] {
|
||||||
|
mod primitives;
|
||||||
|
pub use crate::primitives::*;
|
||||||
|
|
||||||
|
mod xous;
|
||||||
|
pub use crate::xous::*;
|
||||||
|
|
||||||
|
prelude!();
|
||||||
|
} else {
|
||||||
|
// non-supported targets: empty...
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,700 @@
|
||||||
|
/// A macro for defining #[cfg] if-else statements.
|
||||||
|
///
|
||||||
|
/// This is similar to the `if/elif` C preprocessor macro by allowing definition
|
||||||
|
/// of a cascade of `#[cfg]` cases, emitting the implementation which matches
|
||||||
|
/// first.
|
||||||
|
///
|
||||||
|
/// This allows you to conveniently provide a long list #[cfg]'d blocks of code
|
||||||
|
/// without having to rewrite each clause multiple times.
|
||||||
|
macro_rules! cfg_if {
|
||||||
|
// match if/else chains with a final `else`
|
||||||
|
($(
|
||||||
|
if #[cfg($($meta:meta),*)] { $($it:item)* }
|
||||||
|
) else * else {
|
||||||
|
$($it2:item)*
|
||||||
|
}) => {
|
||||||
|
cfg_if! {
|
||||||
|
@__items
|
||||||
|
() ;
|
||||||
|
$( ( ($($meta),*) ($($it)*) ), )*
|
||||||
|
( () ($($it2)*) ),
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// match if/else chains lacking a final `else`
|
||||||
|
(
|
||||||
|
if #[cfg($($i_met:meta),*)] { $($i_it:item)* }
|
||||||
|
$(
|
||||||
|
else if #[cfg($($e_met:meta),*)] { $($e_it:item)* }
|
||||||
|
)*
|
||||||
|
) => {
|
||||||
|
cfg_if! {
|
||||||
|
@__items
|
||||||
|
() ;
|
||||||
|
( ($($i_met),*) ($($i_it)*) ),
|
||||||
|
$( ( ($($e_met),*) ($($e_it)*) ), )*
|
||||||
|
( () () ),
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Internal and recursive macro to emit all the items
|
||||||
|
//
|
||||||
|
// Collects all the negated `cfg`s in a list at the beginning and after the
|
||||||
|
// semicolon is all the remaining items
|
||||||
|
(@__items ($($not:meta,)*) ; ) => {};
|
||||||
|
(@__items ($($not:meta,)*) ; ( ($($m:meta),*) ($($it:item)*) ),
|
||||||
|
$($rest:tt)*) => {
|
||||||
|
// Emit all items within one block, applying an appropriate #[cfg]. The
|
||||||
|
// #[cfg] will require all `$m` matchers specified and must also negate
|
||||||
|
// all previous matchers.
|
||||||
|
cfg_if! { @__apply cfg(all($($m,)* not(any($($not),*)))), $($it)* }
|
||||||
|
|
||||||
|
// Recurse to emit all other items in `$rest`, and when we do so add all
|
||||||
|
// our `$m` matchers to the list of `$not` matchers as future emissions
|
||||||
|
// will have to negate everything we just matched as well.
|
||||||
|
cfg_if! { @__items ($($not,)* $($m,)*) ; $($rest)* }
|
||||||
|
};
|
||||||
|
|
||||||
|
// Internal macro to Apply a cfg attribute to a list of items
|
||||||
|
(@__apply $m:meta, $($it:item)*) => {
|
||||||
|
$(#[$m] $it)*
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Create an internal crate prelude with `core` reexports and common types.
|
||||||
|
macro_rules! prelude {
|
||||||
|
() => {
|
||||||
|
mod types;
|
||||||
|
|
||||||
|
/// Frequently-used types that are available on all platforms
|
||||||
|
///
|
||||||
|
/// We need to reexport the core types so this works with `rust-dep-of-std`.
|
||||||
|
mod prelude {
|
||||||
|
// Exports from `core`
|
||||||
|
#[allow(unused_imports)]
|
||||||
|
pub(crate) use core::clone::Clone;
|
||||||
|
#[allow(unused_imports)]
|
||||||
|
pub(crate) use core::default::Default;
|
||||||
|
#[allow(unused_imports)]
|
||||||
|
pub(crate) use core::marker::{
|
||||||
|
Copy,
|
||||||
|
Send,
|
||||||
|
Sync,
|
||||||
|
};
|
||||||
|
#[allow(unused_imports)]
|
||||||
|
pub(crate) use core::option::Option;
|
||||||
|
#[allow(unused_imports)]
|
||||||
|
pub(crate) use core::prelude::v1::derive;
|
||||||
|
#[allow(unused_imports)]
|
||||||
|
pub(crate) use core::{
|
||||||
|
assert,
|
||||||
|
cfg,
|
||||||
|
debug_assert,
|
||||||
|
fmt,
|
||||||
|
hash,
|
||||||
|
iter,
|
||||||
|
mem,
|
||||||
|
ptr,
|
||||||
|
};
|
||||||
|
|
||||||
|
#[allow(unused_imports)]
|
||||||
|
pub(crate) use fmt::Debug;
|
||||||
|
#[allow(unused_imports)]
|
||||||
|
pub(crate) use mem::{
|
||||||
|
align_of,
|
||||||
|
align_of_val,
|
||||||
|
size_of,
|
||||||
|
size_of_val,
|
||||||
|
};
|
||||||
|
|
||||||
|
#[allow(unused_imports)]
|
||||||
|
#[cfg(any(target_os = "linux", target_os = "android", target_os = "l4re"))]
|
||||||
|
pub(crate) use crate::types::u32_cast_ioctl;
|
||||||
|
#[allow(unused_imports)]
|
||||||
|
pub(crate) use crate::types::{
|
||||||
|
replace_array_items,
|
||||||
|
u16_cast_short,
|
||||||
|
u32_cast_int,
|
||||||
|
u32_cast_long,
|
||||||
|
u8_slice_cast_char_slice,
|
||||||
|
ulong_cast_int,
|
||||||
|
ulong_cast_uint,
|
||||||
|
CEnumRepr,
|
||||||
|
Padding,
|
||||||
|
};
|
||||||
|
// Commonly used types defined in this crate
|
||||||
|
#[allow(unused_imports)]
|
||||||
|
pub(crate) use crate::{
|
||||||
|
c_char,
|
||||||
|
c_double,
|
||||||
|
c_float,
|
||||||
|
c_int,
|
||||||
|
c_long,
|
||||||
|
c_longlong,
|
||||||
|
c_short,
|
||||||
|
c_uchar,
|
||||||
|
c_uint,
|
||||||
|
c_ulong,
|
||||||
|
c_ulonglong,
|
||||||
|
c_ushort,
|
||||||
|
c_void,
|
||||||
|
intptr_t,
|
||||||
|
size_t,
|
||||||
|
ssize_t,
|
||||||
|
uintptr_t,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Implement `Clone`, `Copy`, and `Debug` for one or more structs, as well as `PartialEq`, `Eq`,
|
||||||
|
/// and `Hash` if the `extra_traits` feature is enabled.
|
||||||
|
///
|
||||||
|
/// Also mark the type with `repr(C)`.
|
||||||
|
///
|
||||||
|
/// Use [`s_no_extra_traits`] for structs where the `extra_traits` feature does not
|
||||||
|
/// make sense, and for unions.
|
||||||
|
macro_rules! s {
|
||||||
|
($(
|
||||||
|
$(#[$attr:meta])*
|
||||||
|
$pub:vis $t:ident $i:ident { $($field:tt)* }
|
||||||
|
)*) => ($(
|
||||||
|
s!(it: $(#[$attr])* $pub $t $i { $($field)* });
|
||||||
|
)*);
|
||||||
|
|
||||||
|
(it: $(#[$attr:meta])* $pub:vis union $i:ident { $($field:tt)* }) => (
|
||||||
|
compile_error!("unions cannot derive extra traits, use s_no_extra_traits instead");
|
||||||
|
);
|
||||||
|
|
||||||
|
(it: $(#[$attr:meta])* $pub:vis struct $i:ident { $($field:tt)* }) => (
|
||||||
|
#[repr(C)]
|
||||||
|
#[::core::prelude::v1::derive(
|
||||||
|
::core::clone::Clone,
|
||||||
|
::core::marker::Copy,
|
||||||
|
::core::fmt::Debug,
|
||||||
|
)]
|
||||||
|
#[cfg_attr(
|
||||||
|
feature = "extra_traits",
|
||||||
|
::core::prelude::v1::derive(PartialEq, Eq, Hash)
|
||||||
|
)]
|
||||||
|
#[allow(deprecated)]
|
||||||
|
$(#[$attr])*
|
||||||
|
$pub struct $i { $($field)* }
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Implement `Clone`, `Copy`, and `Debug` for a tuple struct, as well as `PartialEq`, `Eq`,
|
||||||
|
/// and `Hash` if the `extra_traits` feature is enabled.
|
||||||
|
///
|
||||||
|
/// Unlike `s!`, this does *not* mark the type with `repr(C)`. Users should provide their own
|
||||||
|
/// `repr` attribute via `$attr` as necessary.
|
||||||
|
macro_rules! s_paren {
|
||||||
|
($(
|
||||||
|
$(#[$attr:meta])*
|
||||||
|
$pub:vis struct $i:ident ( $($field:tt)* );
|
||||||
|
)*) => ($(
|
||||||
|
#[::core::prelude::v1::derive(
|
||||||
|
::core::clone::Clone,
|
||||||
|
::core::marker::Copy,
|
||||||
|
::core::fmt::Debug,
|
||||||
|
)]
|
||||||
|
#[cfg_attr(
|
||||||
|
feature = "extra_traits",
|
||||||
|
::core::prelude::v1::derive(PartialEq, Eq, Hash)
|
||||||
|
)]
|
||||||
|
$(#[$attr])*
|
||||||
|
$pub struct $i ( $($field)* );
|
||||||
|
)*);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Implement `Clone`, `Copy`, and `Debug` for one or more structs/unions, but exclude `PartialEq`,
|
||||||
|
/// `Eq`, and `Hash`.
|
||||||
|
///
|
||||||
|
/// Also mark the type with `repr(C)`.
|
||||||
|
///
|
||||||
|
/// Most structs will prefer to use [`s`].
|
||||||
|
macro_rules! s_no_extra_traits {
|
||||||
|
($(
|
||||||
|
$(#[$attr:meta])*
|
||||||
|
$pub:vis $t:ident $i:ident { $($field:tt)* }
|
||||||
|
)*) => ($(
|
||||||
|
s_no_extra_traits!(it: $(#[$attr])* $pub $t $i { $($field)* });
|
||||||
|
)*);
|
||||||
|
|
||||||
|
(it: $(#[$attr:meta])* $pub:vis union $i:ident { $($field:tt)* }) => (
|
||||||
|
#[repr(C)]
|
||||||
|
#[::core::prelude::v1::derive(
|
||||||
|
::core::clone::Clone,
|
||||||
|
::core::marker::Copy,
|
||||||
|
)]
|
||||||
|
$(#[$attr])*
|
||||||
|
$pub union $i { $($field)* }
|
||||||
|
|
||||||
|
impl ::core::fmt::Debug for $i {
|
||||||
|
fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result {
|
||||||
|
f.debug_struct(::core::stringify!($i)).finish_non_exhaustive()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
(it: $(#[$attr:meta])* $pub:vis struct $i:ident { $($field:tt)* }) => (
|
||||||
|
#[repr(C)]
|
||||||
|
#[::core::prelude::v1::derive(
|
||||||
|
::core::clone::Clone,
|
||||||
|
::core::marker::Copy,
|
||||||
|
::core::fmt::Debug,
|
||||||
|
)]
|
||||||
|
$(#[$attr])*
|
||||||
|
$pub struct $i { $($field)* }
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Create an uninhabited type that can't be constructed. It implements `Debug`, `Clone`,
|
||||||
|
/// and `Copy`, but these aren't meaningful for extern types so they should eventually
|
||||||
|
/// be removed.
|
||||||
|
///
|
||||||
|
/// Really what we want here is something that also can't be named without indirection (in
|
||||||
|
/// ADTs or function signatures), but this doesn't exist.
|
||||||
|
macro_rules! extern_ty {
|
||||||
|
($(
|
||||||
|
$(#[$attr:meta])*
|
||||||
|
$vis:vis type $i:ident;
|
||||||
|
)*) => ($(
|
||||||
|
$(#[$attr])*
|
||||||
|
/// This is an extern type ("opaque" or "incomplete" type in C).
|
||||||
|
///
|
||||||
|
/// <div class="warning">
|
||||||
|
/// This type's current representation allows inspecting some properties, such as via
|
||||||
|
/// <code>size_of</code>, and it is technically possible to construct the type within
|
||||||
|
/// <code>MaybeUninit</code>, However, this <strong>MUST NOT</strong> be relied upon
|
||||||
|
/// because a future version of <code>libc</code> may switch to a proper
|
||||||
|
/// <a href="https://rust-lang.github.io/rfcs/1861-extern-types.html">extern type</a>
|
||||||
|
/// representation when available.
|
||||||
|
/// </div>
|
||||||
|
// ^ unfortunately warning blocks currently don't render markdown so we need to
|
||||||
|
// use raw HTML.
|
||||||
|
//
|
||||||
|
// Representation based on the Nomicon:
|
||||||
|
// <https://doc.rust-lang.org/nomicon/ffi.html#representing-opaque-structs>.
|
||||||
|
//
|
||||||
|
// FIXME(1.0): These traits are unreachable and should be removed.
|
||||||
|
#[::core::prelude::v1::derive(
|
||||||
|
::core::clone::Clone,
|
||||||
|
::core::marker::Copy,
|
||||||
|
::core::fmt::Debug,
|
||||||
|
)]
|
||||||
|
#[repr(C)]
|
||||||
|
$vis struct $i {
|
||||||
|
_data: (),
|
||||||
|
_marker: ::core::marker::PhantomData<(*mut u8, ::core::marker::PhantomPinned)>,
|
||||||
|
}
|
||||||
|
)*);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Implement `Clone` and `Copy` for an enum, as well as `Debug`, `Eq`, `Hash`, and
|
||||||
|
/// `PartialEq` if the `extra_traits` feature is enabled.
|
||||||
|
// FIXME(#4419): Replace all uses of `e!` with `c_enum!`
|
||||||
|
macro_rules! e {
|
||||||
|
($(
|
||||||
|
$(#[$attr:meta])*
|
||||||
|
pub enum $i:ident { $($field:tt)* }
|
||||||
|
)*) => ($(
|
||||||
|
#[cfg_attr(
|
||||||
|
feature = "extra_traits",
|
||||||
|
::core::prelude::v1::derive(Eq, Hash, PartialEq)
|
||||||
|
)]
|
||||||
|
#[::core::prelude::v1::derive(
|
||||||
|
::core::clone::Clone,
|
||||||
|
::core::marker::Copy,
|
||||||
|
::core::fmt::Debug,
|
||||||
|
)]
|
||||||
|
$(#[$attr])*
|
||||||
|
pub enum $i { $($field)* }
|
||||||
|
)*);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Represent a C enum as Rust constants and a type.
|
||||||
|
///
|
||||||
|
/// C enums can't soundly be mapped to Rust enums since C enums are allowed to have duplicates or
|
||||||
|
/// unlisted values, but this is UB in Rust. This enum doesn't implement any traits, its main
|
||||||
|
/// purpose is to calculate the correct enum values.
|
||||||
|
///
|
||||||
|
/// Use the magic name `#anon` if the C enum doesn't create a type.
|
||||||
|
///
|
||||||
|
/// See <https://github.com/rust-lang/libc/issues/4419> for more.
|
||||||
|
macro_rules! c_enum {
|
||||||
|
// Matcher for multiple enums
|
||||||
|
($(
|
||||||
|
$(#[repr($repr:ty)])?
|
||||||
|
$vis:vis enum $($ty_name:ident)? $(#$anon:ident)? {
|
||||||
|
$($field_vis:vis $variant:ident $(= $value:expr)?,)+
|
||||||
|
}
|
||||||
|
)+) => {
|
||||||
|
$(c_enum!(@single;
|
||||||
|
$(#[repr($repr)])?
|
||||||
|
$vis enum $($ty_name)? $(#$anon)? {
|
||||||
|
$($field_vis $variant $(= $value)?,)+
|
||||||
|
}
|
||||||
|
);)+
|
||||||
|
};
|
||||||
|
|
||||||
|
// Matcher for a single enum
|
||||||
|
(@single;
|
||||||
|
$(#[repr($repr:ty)])?
|
||||||
|
$vis:vis enum $ty_name:ident {
|
||||||
|
$($field_vis:vis $variant:ident $(= $value:expr)?,)+
|
||||||
|
}
|
||||||
|
) => {
|
||||||
|
$vis type $ty_name = c_enum!(@ty $($repr)?);
|
||||||
|
c_enum! {
|
||||||
|
@variant;
|
||||||
|
ty: $ty_name;
|
||||||
|
default: 0;
|
||||||
|
variants: [$($field_vis $variant $(= $value)?,)+]
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Matcher for a single anonymous enum
|
||||||
|
(@single;
|
||||||
|
$(#[repr($repr:ty)])?
|
||||||
|
$vis:vis enum #anon {
|
||||||
|
$($field_vis:vis $variant:ident $(= $value:expr)?,)+
|
||||||
|
}
|
||||||
|
) => {
|
||||||
|
c_enum! {
|
||||||
|
@variant;
|
||||||
|
ty: c_enum!(@ty $($repr)?);
|
||||||
|
default: 0;
|
||||||
|
variants: [$($field_vis $variant $(= $value)?,)+]
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Matcher for variants: eats a single variant then recurses with the rest
|
||||||
|
(@variant; ty: $_ty_name:ty; default: $_idx:expr; variants: []) => { /* end of the chain */ };
|
||||||
|
(
|
||||||
|
@variant;
|
||||||
|
ty: $ty_name:ty;
|
||||||
|
default: $default_val:expr;
|
||||||
|
variants: [
|
||||||
|
$field_vis:vis $variant:ident $(= $value:expr)?,
|
||||||
|
$($tail:tt)*
|
||||||
|
]
|
||||||
|
) => {
|
||||||
|
$field_vis const $variant: $ty_name = {
|
||||||
|
#[allow(unused_variables)]
|
||||||
|
let r = $default_val;
|
||||||
|
$(let r = $value;)?
|
||||||
|
r
|
||||||
|
};
|
||||||
|
|
||||||
|
// The next value is always one more than the previous value, unless
|
||||||
|
// set explicitly.
|
||||||
|
c_enum! {
|
||||||
|
@variant;
|
||||||
|
ty: $ty_name;
|
||||||
|
default: $variant + 1;
|
||||||
|
variants: [$($tail)*]
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Use a specific type if provided, otherwise default to `CEnumRepr`
|
||||||
|
(@ty $repr:ty) => { $repr };
|
||||||
|
(@ty) => { $crate::prelude::CEnumRepr };
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Define a `unsafe` function.
|
||||||
|
macro_rules! f {
|
||||||
|
($(
|
||||||
|
$(#[$attr:meta])*
|
||||||
|
pub $(const $($const_dummy:literal)?)? unsafe
|
||||||
|
fn $i:ident ($($arg:ident: $argty:ty),* $(,)?) -> $ret:ty
|
||||||
|
$body:block
|
||||||
|
)+) => {$(
|
||||||
|
#[inline]
|
||||||
|
$(#[$attr])*
|
||||||
|
pub $(const $($const_dummy)?)? unsafe extern "C"
|
||||||
|
fn $i ($($arg: $argty),*) -> $ret
|
||||||
|
$body
|
||||||
|
)+};
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Define a safe function.
|
||||||
|
macro_rules! safe_f {
|
||||||
|
($(
|
||||||
|
$(#[$attr:meta])*
|
||||||
|
pub $(const $($const_dummy:literal)?)? safe
|
||||||
|
fn $i:ident ($($arg:ident: $argty:ty),* $(,)?) -> $ret:ty
|
||||||
|
$body:block
|
||||||
|
)+) => {$(
|
||||||
|
#[inline]
|
||||||
|
$(#[$attr])*
|
||||||
|
pub $(const $($const_dummy)?)? extern "C"
|
||||||
|
fn $i ($($arg: $argty),*) -> $ret
|
||||||
|
$body
|
||||||
|
)+};
|
||||||
|
}
|
||||||
|
|
||||||
|
// This macro is used to deprecate items that should be accessed via the mach2 crate
|
||||||
|
macro_rules! deprecated_mach {
|
||||||
|
(pub const $id:ident: $ty:ty = $expr:expr;) => {
|
||||||
|
#[deprecated(
|
||||||
|
since = "0.2.55",
|
||||||
|
note = "Use the `mach2` crate instead",
|
||||||
|
)]
|
||||||
|
#[allow(deprecated)]
|
||||||
|
pub const $id: $ty = $expr;
|
||||||
|
};
|
||||||
|
($(pub const $id:ident: $ty:ty = $expr:expr;)*) => {
|
||||||
|
$(
|
||||||
|
deprecated_mach!(
|
||||||
|
pub const $id: $ty = $expr;
|
||||||
|
);
|
||||||
|
)*
|
||||||
|
};
|
||||||
|
(pub type $id:ident = $ty:ty;) => {
|
||||||
|
#[deprecated(
|
||||||
|
since = "0.2.55",
|
||||||
|
note = "Use the `mach2` crate instead",
|
||||||
|
)]
|
||||||
|
#[allow(deprecated)]
|
||||||
|
pub type $id = $ty;
|
||||||
|
};
|
||||||
|
($(pub type $id:ident = $ty:ty;)*) => {
|
||||||
|
$(
|
||||||
|
deprecated_mach!(
|
||||||
|
pub type $id = $ty;
|
||||||
|
);
|
||||||
|
)*
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Polyfill for std's `offset_of`.
|
||||||
|
// FIXME(msrv): stabilized in std in 1.77
|
||||||
|
macro_rules! offset_of {
|
||||||
|
($Ty:path, $field:ident) => {{
|
||||||
|
// Taken from bytemuck, avoids accidentally calling on deref
|
||||||
|
#[allow(clippy::unneeded_wildcard_pattern)]
|
||||||
|
let $Ty { $field: _, .. };
|
||||||
|
let data = core::mem::MaybeUninit::<$Ty>::uninit();
|
||||||
|
let ptr = data.as_ptr();
|
||||||
|
// nested unsafe, see f!
|
||||||
|
#[allow(unused_unsafe)]
|
||||||
|
// SAFETY: computed address is inbounds since we have a stack alloc for T
|
||||||
|
let fptr = unsafe { core::ptr::addr_of!((*ptr).$field) };
|
||||||
|
let off = (fptr as usize).checked_sub(ptr as usize).unwrap();
|
||||||
|
core::assert!(off <= core::mem::size_of::<$Ty>());
|
||||||
|
off
|
||||||
|
}};
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use core::any::TypeId;
|
||||||
|
|
||||||
|
use crate::types::CEnumRepr;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn c_enum_basic() {
|
||||||
|
// By default, variants get sequential values.
|
||||||
|
c_enum! {
|
||||||
|
pub enum e {
|
||||||
|
VAR0,
|
||||||
|
VAR1,
|
||||||
|
VAR2,
|
||||||
|
}
|
||||||
|
|
||||||
|
// Also check enums that don't create a type.
|
||||||
|
pub enum #anon {
|
||||||
|
ANON0,
|
||||||
|
ANON1,
|
||||||
|
ANON2,
|
||||||
|
}
|
||||||
|
|
||||||
|
// No visibility required.
|
||||||
|
enum #anon {
|
||||||
|
ANON3,
|
||||||
|
ANON4,
|
||||||
|
ANON5,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
assert_eq!(TypeId::of::<e>(), TypeId::of::<CEnumRepr>());
|
||||||
|
assert_eq!(VAR0, 0 as CEnumRepr);
|
||||||
|
assert_eq!(VAR1, 1 as CEnumRepr);
|
||||||
|
assert_eq!(VAR2, 2 as CEnumRepr);
|
||||||
|
|
||||||
|
assert_eq!(type_id_of_val(&ANON0), TypeId::of::<CEnumRepr>());
|
||||||
|
assert_eq!(ANON0, 0 as CEnumRepr);
|
||||||
|
assert_eq!(ANON1, 1 as CEnumRepr);
|
||||||
|
assert_eq!(ANON2, 2 as CEnumRepr);
|
||||||
|
|
||||||
|
assert_eq!(type_id_of_val(&ANON3), TypeId::of::<CEnumRepr>());
|
||||||
|
assert_eq!(ANON3, 0 as CEnumRepr);
|
||||||
|
assert_eq!(ANON4, 1 as CEnumRepr);
|
||||||
|
assert_eq!(ANON5, 2 as CEnumRepr);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn c_enum_repr() {
|
||||||
|
// Check specifying the integer representation
|
||||||
|
c_enum! {
|
||||||
|
#[repr(u16)]
|
||||||
|
pub enum e {
|
||||||
|
VAR0,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[repr(u16)]
|
||||||
|
pub enum #anon {
|
||||||
|
ANON0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
assert_eq!(TypeId::of::<e>(), TypeId::of::<u16>());
|
||||||
|
assert_eq!(VAR0, 0_u16);
|
||||||
|
|
||||||
|
assert_eq!(type_id_of_val(&ANON0), TypeId::of::<u16>());
|
||||||
|
assert_eq!(ANON0, 0_u16);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn c_enum_set_value() {
|
||||||
|
// Setting an explicit value resets the count.
|
||||||
|
c_enum! {
|
||||||
|
pub enum e {
|
||||||
|
VAR2 = 2,
|
||||||
|
VAR3,
|
||||||
|
VAR4,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
assert_eq!(VAR2, 2 as CEnumRepr);
|
||||||
|
assert_eq!(VAR3, 3 as CEnumRepr);
|
||||||
|
assert_eq!(VAR4, 4 as CEnumRepr);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn c_enum_multiple_set_value() {
|
||||||
|
// C enums always take one more than the previous value, unless set to a specific
|
||||||
|
// value. Duplicates are allowed.
|
||||||
|
c_enum! {
|
||||||
|
pub enum e {
|
||||||
|
VAR0,
|
||||||
|
VAR2_0 = 2,
|
||||||
|
VAR3_0,
|
||||||
|
VAR4_0,
|
||||||
|
VAR2_1 = 2,
|
||||||
|
VAR3_1,
|
||||||
|
VAR4_1,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
assert_eq!(VAR0, 0 as CEnumRepr);
|
||||||
|
assert_eq!(VAR2_0, 2 as CEnumRepr);
|
||||||
|
assert_eq!(VAR3_0, 3 as CEnumRepr);
|
||||||
|
assert_eq!(VAR4_0, 4 as CEnumRepr);
|
||||||
|
assert_eq!(VAR2_1, 2 as CEnumRepr);
|
||||||
|
assert_eq!(VAR3_1, 3 as CEnumRepr);
|
||||||
|
assert_eq!(VAR4_1, 4 as CEnumRepr);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn c_enum_vis() {
|
||||||
|
mod priv1 {
|
||||||
|
c_enum! {
|
||||||
|
#[repr(u8)]
|
||||||
|
pub enum e1 {
|
||||||
|
PRIV_ON_1 = 10,
|
||||||
|
// Variant should still be usable within its visibility
|
||||||
|
pub PUB1 = PRIV_ON_1 * 2,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
mod priv2 {
|
||||||
|
c_enum! {
|
||||||
|
#[repr(u16)]
|
||||||
|
pub enum e2 {
|
||||||
|
pub PRIV_ON_1 = 42,
|
||||||
|
pub PUB2 = PRIV_ON_1 * 2,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
use priv1::*;
|
||||||
|
use priv2::*;
|
||||||
|
|
||||||
|
assert_eq!(TypeId::of::<e1>(), TypeId::of::<u8>());
|
||||||
|
assert_eq!(TypeId::of::<e2>(), TypeId::of::<u16>());
|
||||||
|
assert_eq!(PUB1, 10u8 * 2);
|
||||||
|
assert_eq!(PUB2, 42u16 * 2);
|
||||||
|
// Verify that the default is private. If `PRIV_ON_1` was actually public in `priv1`, this
|
||||||
|
// would be an ambiguous import and/or type mismatch error.
|
||||||
|
assert_eq!(PRIV_ON_1, 42u16);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn type_id_of_val<T: 'static>(_: &T) -> TypeId {
|
||||||
|
TypeId::of::<T>()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_offset_of() {
|
||||||
|
#[repr(C)]
|
||||||
|
struct Off1 {
|
||||||
|
a: u8,
|
||||||
|
b: u32,
|
||||||
|
c: Off2,
|
||||||
|
d: u64,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[repr(C)]
|
||||||
|
#[repr(align(128))]
|
||||||
|
struct Off2 {}
|
||||||
|
|
||||||
|
assert_eq!(core::mem::offset_of!(Off1, a), offset_of!(Off1, a));
|
||||||
|
assert_eq!(core::mem::offset_of!(Off1, b), offset_of!(Off1, b));
|
||||||
|
assert_eq!(core::mem::offset_of!(Off1, c), offset_of!(Off1, c));
|
||||||
|
assert_eq!(core::mem::offset_of!(Off1, d), offset_of!(Off1, d));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
#[allow(unused)]
|
||||||
|
mod macro_checks {
|
||||||
|
s! {
|
||||||
|
pub struct S1 {
|
||||||
|
pub a: u32,
|
||||||
|
b: u32,
|
||||||
|
}
|
||||||
|
|
||||||
|
struct S1Priv {
|
||||||
|
pub a: u32,
|
||||||
|
b: u32,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
s_no_extra_traits! {
|
||||||
|
pub struct S2 {
|
||||||
|
pub a: u32,
|
||||||
|
b: u32,
|
||||||
|
}
|
||||||
|
|
||||||
|
struct S2Priv {
|
||||||
|
pub a: u32,
|
||||||
|
b: u32,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub union U2 {
|
||||||
|
pub a: u32,
|
||||||
|
b: f32,
|
||||||
|
}
|
||||||
|
|
||||||
|
union U2Priv {
|
||||||
|
pub a: u32,
|
||||||
|
b: f32,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extern_ty! {
|
||||||
|
type Foo;
|
||||||
|
pub type Bar;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,6 @@
|
||||||
|
//! IBM AIX libc.
|
||||||
|
//!
|
||||||
|
//! * Headers are not public
|
||||||
|
//! * Manual pages: <https://www.ibm.com/docs/en/aix> (under "Technical reference" for that version)
|
||||||
|
|
||||||
|
pub(crate) mod unistd;
|
||||||
|
|
@ -0,0 +1,7 @@
|
||||||
|
//! Header: `unistd.h`
|
||||||
|
|
||||||
|
pub use crate::new::common::posix::unistd::{
|
||||||
|
STDERR_FILENO,
|
||||||
|
STDIN_FILENO,
|
||||||
|
STDOUT_FILENO,
|
||||||
|
};
|
||||||
|
|
@ -0,0 +1,5 @@
|
||||||
|
//! Header: `signal.h`
|
||||||
|
//!
|
||||||
|
//! <https://github.com/apple-oss-distributions/Libc/blob/main/include/signal.h>
|
||||||
|
|
||||||
|
pub use crate::sys::signal::*;
|
||||||
|
|
@ -0,0 +1,7 @@
|
||||||
|
//! Header: `unistd.h`
|
||||||
|
|
||||||
|
pub use crate::new::common::posix::unistd::{
|
||||||
|
STDERR_FILENO,
|
||||||
|
STDIN_FILENO,
|
||||||
|
STDOUT_FILENO,
|
||||||
|
};
|
||||||
|
|
@ -0,0 +1,20 @@
|
||||||
|
//! Source from libpthread <https://github.com/apple-oss-distributions/libpthread/tree/main>
|
||||||
|
|
||||||
|
/// Directory: `pthread/`
|
||||||
|
///
|
||||||
|
/// Note that this module has a trailing underscore to avoid conflicting with its child `pthread`
|
||||||
|
/// module.
|
||||||
|
///
|
||||||
|
/// <https://github.com/apple-oss-distributions/libpthread/tree/main/include/pthread>
|
||||||
|
pub(crate) mod pthread_ {
|
||||||
|
pub(crate) mod introspection;
|
||||||
|
pub(crate) mod pthread;
|
||||||
|
pub(crate) mod pthread_impl;
|
||||||
|
pub(crate) mod pthread_spis;
|
||||||
|
pub(crate) mod qos;
|
||||||
|
pub(crate) mod sched;
|
||||||
|
pub(crate) mod spawn;
|
||||||
|
pub(crate) mod stack_np;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) mod sys;
|
||||||
|
|
@ -0,0 +1,36 @@
|
||||||
|
//! Header: `pthread/introspection.h`
|
||||||
|
//!
|
||||||
|
//! <https://github.com/apple-oss-distributions/libpthread/blob/main/include/pthread/introspection.h>
|
||||||
|
|
||||||
|
use crate::prelude::*;
|
||||||
|
pub use crate::pthread_::pthread::*;
|
||||||
|
|
||||||
|
c_enum! {
|
||||||
|
#[repr(c_uint)]
|
||||||
|
pub enum #anon {
|
||||||
|
pub PTHREAD_INTROSPECTION_THREAD_CREATE = 1,
|
||||||
|
pub PTHREAD_INTROSPECTION_THREAD_START,
|
||||||
|
pub PTHREAD_INTROSPECTION_THREAD_TERMINATE,
|
||||||
|
pub PTHREAD_INTROSPECTION_THREAD_DESTROY,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub type pthread_introspection_hook_t =
|
||||||
|
extern "C" fn(event: c_uint, thread: pthread_t, addr: *mut c_void, size: size_t);
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
// Available from Big Sur
|
||||||
|
pub fn pthread_introspection_hook_install(
|
||||||
|
hook: pthread_introspection_hook_t,
|
||||||
|
) -> pthread_introspection_hook_t;
|
||||||
|
pub fn pthread_introspection_setspecific_np(
|
||||||
|
thread: pthread_t,
|
||||||
|
key: pthread_key_t,
|
||||||
|
value: *const c_void,
|
||||||
|
) -> c_int;
|
||||||
|
|
||||||
|
pub fn pthread_introspection_getspecific_np(
|
||||||
|
thread: pthread_t,
|
||||||
|
key: pthread_key_t,
|
||||||
|
) -> *mut c_void;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,76 @@
|
||||||
|
//! Header: `pthread.h` or `pthread/pthread.h`
|
||||||
|
//!
|
||||||
|
//! <https://github.com/apple-oss-distributions/libpthread/blob/main/include/pthread/pthread.h>
|
||||||
|
|
||||||
|
use crate::prelude::*;
|
||||||
|
pub use crate::pthread_::qos::*;
|
||||||
|
pub use crate::pthread_::sched::*;
|
||||||
|
// No need to import from the `_pthread_attr_t` and similar modules since `_pthread_types` has
|
||||||
|
// everything we need.
|
||||||
|
pub use crate::sys::_pthread::_pthread_types::*;
|
||||||
|
|
||||||
|
pub const PTHREAD_CREATE_JOINABLE: c_int = 1;
|
||||||
|
pub const PTHREAD_CREATE_DETACHED: c_int = 2;
|
||||||
|
|
||||||
|
pub const PTHREAD_INHERIT_SCHED: c_int = 1;
|
||||||
|
pub const PTHREAD_EXPLICIT_SCHED: c_int = 2;
|
||||||
|
|
||||||
|
pub const PTHREAD_CANCEL_ENABLE: c_int = 0x01;
|
||||||
|
pub const PTHREAD_CANCEL_DISABLE: c_int = 0x00;
|
||||||
|
pub const PTHREAD_CANCEL_DEFERRED: c_int = 0x02;
|
||||||
|
pub const PTHREAD_CANCEL_ASYNCHRONOUS: c_int = 0x00;
|
||||||
|
|
||||||
|
pub const PTHREAD_CANCELED: *mut c_void = 1 as *mut c_void;
|
||||||
|
|
||||||
|
pub const PTHREAD_SCOPE_SYSTEM: c_int = 1;
|
||||||
|
pub const PTHREAD_SCOPE_PROCESS: c_int = 2;
|
||||||
|
|
||||||
|
pub const PTHREAD_PROCESS_SHARED: c_int = 1;
|
||||||
|
pub const PTHREAD_PROCESS_PRIVATE: c_int = 2;
|
||||||
|
|
||||||
|
pub const PTHREAD_PRIO_NONE: c_int = 0;
|
||||||
|
pub const PTHREAD_PRIO_INHERIT: c_int = 1;
|
||||||
|
pub const PTHREAD_PRIO_PROTECT: c_int = 2;
|
||||||
|
|
||||||
|
pub const PTHREAD_MUTEX_NORMAL: c_int = 0;
|
||||||
|
pub const PTHREAD_MUTEX_ERRORCHECK: c_int = 1;
|
||||||
|
pub const PTHREAD_MUTEX_RECURSIVE: c_int = 2;
|
||||||
|
pub const PTHREAD_MUTEX_DEFAULT: c_int = PTHREAD_MUTEX_NORMAL;
|
||||||
|
|
||||||
|
pub const PTHREAD_RWLOCK_INITIALIZER: pthread_rwlock_t = pthread_rwlock_t {
|
||||||
|
__sig: _PTHREAD_RWLOCK_SIG_init,
|
||||||
|
__opaque: [0; __PTHREAD_RWLOCK_SIZE__],
|
||||||
|
};
|
||||||
|
|
||||||
|
pub const PTHREAD_MUTEX_INITIALIZER: pthread_mutex_t = pthread_mutex_t {
|
||||||
|
__sig: _PTHREAD_MUTEX_SIG_init,
|
||||||
|
__opaque: [0; __PTHREAD_MUTEX_SIZE__],
|
||||||
|
};
|
||||||
|
|
||||||
|
pub const PTHREAD_COND_INITIALIZER: pthread_cond_t = pthread_cond_t {
|
||||||
|
__sig: _PTHREAD_COND_SIG_init,
|
||||||
|
__opaque: [0; __PTHREAD_COND_SIZE__],
|
||||||
|
};
|
||||||
|
|
||||||
|
pub const PTHREAD_ONCE_INIT: crate::pthread_once_t = crate::pthread_once_t {
|
||||||
|
__sig: _PTHREAD_ONCE_SIG_INIT,
|
||||||
|
__opaque: [0; __PTHREAD_ONCE_SIZE__],
|
||||||
|
};
|
||||||
|
|
||||||
|
pub use crate::new::common::posix::pthread::{
|
||||||
|
pthread_attr_getinheritsched,
|
||||||
|
pthread_attr_getschedparam,
|
||||||
|
pthread_attr_getschedpolicy,
|
||||||
|
pthread_attr_setinheritsched,
|
||||||
|
pthread_attr_setschedparam,
|
||||||
|
pthread_attr_setschedpolicy,
|
||||||
|
pthread_condattr_getpshared,
|
||||||
|
pthread_condattr_setpshared,
|
||||||
|
pthread_getschedparam,
|
||||||
|
pthread_mutexattr_getpshared,
|
||||||
|
pthread_mutexattr_setpshared,
|
||||||
|
pthread_once,
|
||||||
|
pthread_rwlockattr_getpshared,
|
||||||
|
pthread_rwlockattr_setpshared,
|
||||||
|
pthread_setschedparam,
|
||||||
|
};
|
||||||
|
|
@ -0,0 +1,12 @@
|
||||||
|
use crate::prelude::*;
|
||||||
|
|
||||||
|
// FIXME(apple): these should all be `pub(crate)`
|
||||||
|
pub const _PTHREAD_MUTEX_SIG_init: c_long = 0x32AAABA7;
|
||||||
|
|
||||||
|
pub const _PTHREAD_COND_SIG_init: c_long = 0x3CB0B1BB;
|
||||||
|
pub(crate) const _PTHREAD_ONCE_SIG_INIT: c_long = 0x30B1BCBA;
|
||||||
|
pub const _PTHREAD_RWLOCK_SIG_init: c_long = 0x2DA8B3B4;
|
||||||
|
|
||||||
|
pub const SCHED_OTHER: c_int = 1;
|
||||||
|
pub const SCHED_FIFO: c_int = 4;
|
||||||
|
pub const SCHED_RR: c_int = 2;
|
||||||
|
|
@ -0,0 +1,14 @@
|
||||||
|
//! Header: `pthread/pthread_spis.h`
|
||||||
|
//!
|
||||||
|
//! <https://github.com/apple-oss-distributions/libpthread/blob/main/include/pthread/pthread_spis.h>
|
||||||
|
|
||||||
|
use crate::prelude::*;
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
pub fn pthread_create_from_mach_thread(
|
||||||
|
thread: *mut crate::pthread_t,
|
||||||
|
attr: *const crate::pthread_attr_t,
|
||||||
|
f: extern "C" fn(*mut c_void) -> *mut c_void,
|
||||||
|
value: *mut c_void,
|
||||||
|
) -> c_int;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,25 @@
|
||||||
|
//! Header: `pthread/qos.h`
|
||||||
|
//!
|
||||||
|
//! <https://github.com/apple-oss-distributions/libpthread/blob/main/include/pthread/qos.h>
|
||||||
|
|
||||||
|
use crate::prelude::*;
|
||||||
|
pub use crate::sys::qos::*;
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
pub fn pthread_attr_set_qos_class_np(
|
||||||
|
attr: *mut crate::pthread_attr_t,
|
||||||
|
class: qos_class_t,
|
||||||
|
priority: c_int,
|
||||||
|
) -> c_int;
|
||||||
|
pub fn pthread_attr_get_qos_class_np(
|
||||||
|
attr: *mut crate::pthread_attr_t,
|
||||||
|
class: *mut qos_class_t,
|
||||||
|
priority: *mut c_int,
|
||||||
|
) -> c_int;
|
||||||
|
pub fn pthread_set_qos_class_self_np(class: qos_class_t, priority: c_int) -> c_int;
|
||||||
|
pub fn pthread_get_qos_class_np(
|
||||||
|
thread: crate::pthread_t,
|
||||||
|
class: *mut qos_class_t,
|
||||||
|
priority: *mut c_int,
|
||||||
|
) -> c_int;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,9 @@
|
||||||
|
pub use crate::new::pthread_::pthread_impl::*;
|
||||||
|
use crate::prelude::*;
|
||||||
|
|
||||||
|
s! {
|
||||||
|
pub struct sched_param {
|
||||||
|
pub sched_priority: c_int,
|
||||||
|
__opaque: [c_char; 4],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,16 @@
|
||||||
|
//! Header: `pthread/spawn.h`
|
||||||
|
//!
|
||||||
|
//! <https://github.com/apple-oss-distributions/libpthread/blob/main/include/pthread/spawn.h>
|
||||||
|
|
||||||
|
use crate::prelude::*;
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
pub fn posix_spawnattr_set_qos_class_np(
|
||||||
|
attr: *mut crate::posix_spawnattr_t,
|
||||||
|
qos_class: crate::qos_class_t,
|
||||||
|
) -> c_int;
|
||||||
|
pub fn posix_spawnattr_get_qos_class_np(
|
||||||
|
attr: *const crate::posix_spawnattr_t,
|
||||||
|
qos_class: *mut crate::qos_class_t,
|
||||||
|
) -> c_int;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,12 @@
|
||||||
|
//! Header: `pthread/stack_np.h`
|
||||||
|
//!
|
||||||
|
//! <https://github.com/apple-oss-distributions/libpthread/blob/main/include/pthread/stack_np.h>
|
||||||
|
|
||||||
|
use crate::prelude::*;
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
pub fn pthread_stack_frame_decode_np(
|
||||||
|
frame_addr: uintptr_t,
|
||||||
|
return_addr: *mut uintptr_t,
|
||||||
|
) -> uintptr_t;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,79 @@
|
||||||
|
//! Header: `sys/_pthread/_pthread_types.h`
|
||||||
|
//!
|
||||||
|
//! <https://github.com/apple-oss-distributions/libpthread/blob/main/include/sys/_pthread/_pthread_types.h>
|
||||||
|
//!
|
||||||
|
//! Note that the actual header defines `_opaque_pthread_*` structs which are typedefed to
|
||||||
|
//! `__darwin_pthread*` structs, and typedefed again in separate `_pthread_*.h` files to their final
|
||||||
|
//! `pthread_` name. This isn't useful for us so we simplify a bit and just define everything here.
|
||||||
|
|
||||||
|
use crate::prelude::*;
|
||||||
|
|
||||||
|
cfg_if! {
|
||||||
|
if #[cfg(target_pointer_width = "64")] {
|
||||||
|
pub const __PTHREAD_SIZE__: usize = 8176;
|
||||||
|
pub const __PTHREAD_ATTR_SIZE__: usize = 56;
|
||||||
|
pub const __PTHREAD_MUTEXATTR_SIZE__: usize = 8;
|
||||||
|
pub const __PTHREAD_MUTEX_SIZE__: usize = 56;
|
||||||
|
pub const __PTHREAD_CONDATTR_SIZE__: usize = 8;
|
||||||
|
pub const __PTHREAD_COND_SIZE__: usize = 40;
|
||||||
|
pub const __PTHREAD_ONCE_SIZE__: usize = 8;
|
||||||
|
pub const __PTHREAD_RWLOCK_SIZE__: usize = 192;
|
||||||
|
pub const __PTHREAD_RWLOCKATTR_SIZE__: usize = 16;
|
||||||
|
} else {
|
||||||
|
pub const __PTHREAD_SIZE__: usize = 4088;
|
||||||
|
pub const __PTHREAD_ATTR_SIZE__: usize = 36;
|
||||||
|
pub const __PTHREAD_MUTEXATTR_SIZE__: usize = 8;
|
||||||
|
pub const __PTHREAD_MUTEX_SIZE__: usize = 40;
|
||||||
|
pub const __PTHREAD_CONDATTR_SIZE__: usize = 4;
|
||||||
|
pub const __PTHREAD_COND_SIZE__: usize = 24;
|
||||||
|
pub const __PTHREAD_ONCE_SIZE__: usize = 4;
|
||||||
|
pub const __PTHREAD_RWLOCK_SIZE__: usize = 124;
|
||||||
|
pub const __PTHREAD_RWLOCKATTR_SIZE__: usize = 12;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
s! {
|
||||||
|
pub struct pthread_attr_t {
|
||||||
|
pub(crate) __sig: c_long,
|
||||||
|
pub(crate) __opaque: [c_char; __PTHREAD_ATTR_SIZE__],
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct pthread_cond_t {
|
||||||
|
pub(crate) __sig: c_long,
|
||||||
|
pub(crate) __opaque: [u8; __PTHREAD_COND_SIZE__],
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct pthread_condattr_t {
|
||||||
|
pub(crate) __sig: c_long,
|
||||||
|
pub(crate) __opaque: [u8; __PTHREAD_CONDATTR_SIZE__],
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct pthread_mutex_t {
|
||||||
|
pub(crate) __sig: c_long,
|
||||||
|
pub(crate) __opaque: [u8; __PTHREAD_MUTEX_SIZE__],
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct pthread_mutexattr_t {
|
||||||
|
pub(crate) __sig: c_long,
|
||||||
|
pub(crate) __opaque: [u8; __PTHREAD_MUTEXATTR_SIZE__],
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct pthread_once_t {
|
||||||
|
pub(crate) __sig: c_long,
|
||||||
|
pub(crate) __opaque: [c_char; __PTHREAD_ONCE_SIZE__],
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct pthread_rwlock_t {
|
||||||
|
pub(crate) __sig: c_long,
|
||||||
|
pub(crate) __opaque: [u8; __PTHREAD_RWLOCK_SIZE__],
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct pthread_rwlockattr_t {
|
||||||
|
pub(crate) __sig: c_long,
|
||||||
|
pub(crate) __opaque: [u8; __PTHREAD_RWLOCKATTR_SIZE__],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub type pthread_key_t = c_ulong;
|
||||||
|
|
||||||
|
pub use crate::pthread_t;
|
||||||
|
|
@ -0,0 +1,14 @@
|
||||||
|
//! Directory: `sys/`
|
||||||
|
//!
|
||||||
|
//! <https://github.com/apple-oss-distributions/libpthread/tree/main/include/sys/_pthread>
|
||||||
|
|
||||||
|
/// Directory: `sys/_pthread/`
|
||||||
|
///
|
||||||
|
/// <https://github.com/apple-oss-distributions/libpthread/tree/main/include/sys>
|
||||||
|
pub(crate) mod _pthread {
|
||||||
|
// We don't have the `_pthread_attr_t` and similar modules to match `_pthread_attr_t.h`,
|
||||||
|
// everything is defined in `_pthread_types`.
|
||||||
|
pub(crate) mod _pthread_types;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) mod qos;
|
||||||
|
|
@ -0,0 +1,22 @@
|
||||||
|
//! Header: `sys/qos.h`
|
||||||
|
//!
|
||||||
|
//! <https://github.com/apple-oss-distributions/libpthread/blob/main/include/sys/qos.h>
|
||||||
|
|
||||||
|
use crate::prelude::*;
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
#[repr(u32)]
|
||||||
|
pub enum qos_class_t {
|
||||||
|
QOS_CLASS_USER_INTERACTIVE = 0x21,
|
||||||
|
QOS_CLASS_USER_INITIATED = 0x19,
|
||||||
|
QOS_CLASS_DEFAULT = 0x15,
|
||||||
|
QOS_CLASS_UTILITY = 0x11,
|
||||||
|
QOS_CLASS_BACKGROUND = 0x09,
|
||||||
|
QOS_CLASS_UNSPECIFIED = 0x00,
|
||||||
|
}
|
||||||
|
impl Copy for qos_class_t {}
|
||||||
|
impl Clone for qos_class_t {
|
||||||
|
fn clone(&self) -> qos_class_t {
|
||||||
|
*self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,19 @@
|
||||||
|
//! Apple interfaces.
|
||||||
|
//!
|
||||||
|
//! The Xcode SDK includes interfaces that are split across a couple of different libraries. Most
|
||||||
|
//! of these are available at <https://github.com/apple-oss-distributions>.
|
||||||
|
|
||||||
|
/// Entrypoint for Apple headers, usually found as part of the Xcode SDK.
|
||||||
|
///
|
||||||
|
/// <https://github.com/apple-oss-distributions/Libc/tree/main/include>
|
||||||
|
mod libc {
|
||||||
|
pub(crate) mod signal;
|
||||||
|
pub(crate) mod unistd;
|
||||||
|
}
|
||||||
|
|
||||||
|
mod libpthread;
|
||||||
|
mod xnu;
|
||||||
|
|
||||||
|
pub(crate) use libc::*;
|
||||||
|
pub(crate) use libpthread::pthread_;
|
||||||
|
pub(crate) use xnu::*;
|
||||||
|
|
@ -0,0 +1,15 @@
|
||||||
|
//! Header: `arm/_mcontext.h`
|
||||||
|
//!
|
||||||
|
//! <https://github.com/apple-oss-distributions/xnu/blob/main/bsd/arm/_mcontext.h>
|
||||||
|
|
||||||
|
pub use crate::mach::machine::_structs::*;
|
||||||
|
|
||||||
|
s! {
|
||||||
|
pub struct __darwin_mcontext64 {
|
||||||
|
pub __es: __darwin_arm_exception_state64,
|
||||||
|
pub __ss: __darwin_arm_thread_state64,
|
||||||
|
pub __ns: __darwin_arm_neon_state64,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub type mcontext_t = *mut __darwin_mcontext64;
|
||||||
|
|
@ -0,0 +1,15 @@
|
||||||
|
//! Header: `i386/_mcontext.h`
|
||||||
|
//!
|
||||||
|
//! <https://github.com/apple-oss-distributions/xnu/blob/main/bsd/i386/_mcontext.h>
|
||||||
|
|
||||||
|
pub use crate::mach::machine::_structs::*;
|
||||||
|
|
||||||
|
s! {
|
||||||
|
pub struct __darwin_mcontext64 {
|
||||||
|
pub __es: __darwin_x86_exception_state64,
|
||||||
|
pub __ss: __darwin_x86_thread_state64,
|
||||||
|
pub __fs: __darwin_x86_float_state64,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub type mcontext_t = *mut __darwin_mcontext64;
|
||||||
|
|
@ -0,0 +1,37 @@
|
||||||
|
//! Header: `arm/_structs.h`
|
||||||
|
//!
|
||||||
|
//! <https://github.com/apple-oss-distributions/xnu/blob/main/osfmk/mach/arm/_structs.h>
|
||||||
|
|
||||||
|
#[cfg(target_arch = "arm")]
|
||||||
|
use crate::prelude::*;
|
||||||
|
|
||||||
|
s! {
|
||||||
|
pub struct __darwin_arm_exception_state64 {
|
||||||
|
pub __far: u64,
|
||||||
|
pub __esr: u32,
|
||||||
|
pub __exception: u32,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct __darwin_arm_thread_state64 {
|
||||||
|
pub __x: [u64; 29],
|
||||||
|
pub __fp: u64,
|
||||||
|
pub __lr: u64,
|
||||||
|
pub __sp: u64,
|
||||||
|
pub __pc: u64,
|
||||||
|
pub __cpsr: u32,
|
||||||
|
pub __pad: u32,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(target_arch = "aarch64")]
|
||||||
|
pub struct __darwin_arm_neon_state64 {
|
||||||
|
pub __v: [u128; 32],
|
||||||
|
pub __fpsr: u32,
|
||||||
|
pub __fpcr: u32,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(target_arch = "arm")]
|
||||||
|
#[repr(align(16))]
|
||||||
|
pub struct __darwin_arm_neon_state64 {
|
||||||
|
opaque: [c_char; (32 * 16) + (2 * size_of::<u32>())],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,92 @@
|
||||||
|
//! Header: `i386/_structs.h`
|
||||||
|
//!
|
||||||
|
//! <https://github.com/apple-oss-distributions/xnu/blob/main/osfmk/mach/i386/_structs.h>
|
||||||
|
|
||||||
|
use crate::prelude::*;
|
||||||
|
|
||||||
|
s! {
|
||||||
|
pub struct __darwin_mmst_reg {
|
||||||
|
pub __mmst_reg: [c_char; 10],
|
||||||
|
pub __mmst_rsrv: [c_char; 6],
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct __darwin_xmm_reg {
|
||||||
|
pub __xmm_reg: [c_char; 16],
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct __darwin_x86_thread_state64 {
|
||||||
|
pub __rax: u64,
|
||||||
|
pub __rbx: u64,
|
||||||
|
pub __rcx: u64,
|
||||||
|
pub __rdx: u64,
|
||||||
|
pub __rdi: u64,
|
||||||
|
pub __rsi: u64,
|
||||||
|
pub __rbp: u64,
|
||||||
|
pub __rsp: u64,
|
||||||
|
pub __r8: u64,
|
||||||
|
pub __r9: u64,
|
||||||
|
pub __r10: u64,
|
||||||
|
pub __r11: u64,
|
||||||
|
pub __r12: u64,
|
||||||
|
pub __r13: u64,
|
||||||
|
pub __r14: u64,
|
||||||
|
pub __r15: u64,
|
||||||
|
pub __rip: u64,
|
||||||
|
pub __rflags: u64,
|
||||||
|
pub __cs: u64,
|
||||||
|
pub __fs: u64,
|
||||||
|
pub __gs: u64,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct __darwin_x86_exception_state64 {
|
||||||
|
pub __trapno: u16,
|
||||||
|
pub __cpu: u16,
|
||||||
|
pub __err: u32,
|
||||||
|
pub __faultvaddr: u64,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct __darwin_x86_float_state64 {
|
||||||
|
pub __fpu_reserved: [c_int; 2],
|
||||||
|
__fpu_fcw: c_short,
|
||||||
|
__fpu_fsw: c_short,
|
||||||
|
pub __fpu_ftw: u8,
|
||||||
|
pub __fpu_rsrv1: u8,
|
||||||
|
pub __fpu_fop: u16,
|
||||||
|
pub __fpu_ip: u32,
|
||||||
|
pub __fpu_cs: u16,
|
||||||
|
pub __fpu_rsrv2: u16,
|
||||||
|
pub __fpu_dp: u32,
|
||||||
|
pub __fpu_ds: u16,
|
||||||
|
pub __fpu_rsrv3: u16,
|
||||||
|
pub __fpu_mxcsr: u32,
|
||||||
|
pub __fpu_mxcsrmask: u32,
|
||||||
|
pub __fpu_stmm0: __darwin_mmst_reg,
|
||||||
|
pub __fpu_stmm1: __darwin_mmst_reg,
|
||||||
|
pub __fpu_stmm2: __darwin_mmst_reg,
|
||||||
|
pub __fpu_stmm3: __darwin_mmst_reg,
|
||||||
|
pub __fpu_stmm4: __darwin_mmst_reg,
|
||||||
|
pub __fpu_stmm5: __darwin_mmst_reg,
|
||||||
|
pub __fpu_stmm6: __darwin_mmst_reg,
|
||||||
|
pub __fpu_stmm7: __darwin_mmst_reg,
|
||||||
|
pub __fpu_xmm0: __darwin_xmm_reg,
|
||||||
|
pub __fpu_xmm1: __darwin_xmm_reg,
|
||||||
|
pub __fpu_xmm2: __darwin_xmm_reg,
|
||||||
|
pub __fpu_xmm3: __darwin_xmm_reg,
|
||||||
|
pub __fpu_xmm4: __darwin_xmm_reg,
|
||||||
|
pub __fpu_xmm5: __darwin_xmm_reg,
|
||||||
|
pub __fpu_xmm6: __darwin_xmm_reg,
|
||||||
|
pub __fpu_xmm7: __darwin_xmm_reg,
|
||||||
|
pub __fpu_xmm8: __darwin_xmm_reg,
|
||||||
|
pub __fpu_xmm9: __darwin_xmm_reg,
|
||||||
|
pub __fpu_xmm10: __darwin_xmm_reg,
|
||||||
|
pub __fpu_xmm11: __darwin_xmm_reg,
|
||||||
|
pub __fpu_xmm12: __darwin_xmm_reg,
|
||||||
|
pub __fpu_xmm13: __darwin_xmm_reg,
|
||||||
|
pub __fpu_xmm14: __darwin_xmm_reg,
|
||||||
|
pub __fpu_xmm15: __darwin_xmm_reg,
|
||||||
|
// FIXME(apple): this field is actually [u8; 96], but defining it with a bigger type allows
|
||||||
|
// us to auto-implement traits for it since the length of the array is less than 32
|
||||||
|
__fpu_rsrv4: [u32; 24],
|
||||||
|
pub __fpu_reserved1: c_int,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,13 @@
|
||||||
|
//! Header: `mach/machine/_structs.h`
|
||||||
|
//!
|
||||||
|
//! <https://github.com/apple-oss-distributions/xnu/blob/main/osfmk/mach/machine/_structs.h>
|
||||||
|
|
||||||
|
cfg_if! {
|
||||||
|
if #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] {
|
||||||
|
pub use crate::mach::i386::_structs::*;
|
||||||
|
} else if #[cfg(any(target_arch = "arm", target_arch = "aarch64"))] {
|
||||||
|
pub use crate::mach::arm::_structs::*;
|
||||||
|
} else {
|
||||||
|
// Unsupported arch
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,20 @@
|
||||||
|
//! Directory: `mach/`
|
||||||
|
//!
|
||||||
|
//! <https://github.com/apple-oss-distributions/xnu/tree/main/osfmk/mach>
|
||||||
|
|
||||||
|
/// Directory: `mach/arm`
|
||||||
|
#[cfg(any(target_arch = "arm", target_arch = "aarch64"))]
|
||||||
|
pub(crate) mod arm {
|
||||||
|
pub(crate) mod _structs;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Directory: `mach/i386`
|
||||||
|
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
|
||||||
|
pub(crate) mod i386 {
|
||||||
|
pub(crate) mod _structs;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Directory: `mach/machine`
|
||||||
|
pub(crate) mod machine {
|
||||||
|
pub(crate) mod _structs;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,11 @@
|
||||||
|
//! Header: `machine/_mcontext.h`
|
||||||
|
|
||||||
|
cfg_if! {
|
||||||
|
if #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] {
|
||||||
|
pub use crate::i386::_mcontext::*;
|
||||||
|
} else if #[cfg(any(target_arch = "arm", target_arch = "aarch64"))] {
|
||||||
|
pub use crate::arm::_mcontext::*;
|
||||||
|
} else {
|
||||||
|
// Unsupported arch
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,34 @@
|
||||||
|
//! Source from XNU <https://github.com/apple-oss-distributions/xnu/tree/main>
|
||||||
|
//!
|
||||||
|
//! We omit nesting for the `bsd` module since most items of interest are in there.
|
||||||
|
|
||||||
|
/// Directory: `arm/`
|
||||||
|
///
|
||||||
|
/// https://github.com/apple-oss-distributions/xnu/tree/main/bsd/arm
|
||||||
|
#[cfg(any(target_arch = "arm", target_arch = "aarch64"))]
|
||||||
|
pub(crate) mod arm {
|
||||||
|
pub(crate) mod _mcontext;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Directory: `i386/`
|
||||||
|
///
|
||||||
|
/// https://github.com/apple-oss-distributions/xnu/tree/main/bsd/i386
|
||||||
|
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
|
||||||
|
pub(crate) mod i386 {
|
||||||
|
pub(crate) mod _mcontext;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) mod mach;
|
||||||
|
|
||||||
|
/// Directory: `machine/`
|
||||||
|
///
|
||||||
|
/// https://github.com/apple-oss-distributions/xnu/tree/main/bsd/machine
|
||||||
|
pub(crate) mod machine {
|
||||||
|
pub(crate) mod _mcontext;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) mod net;
|
||||||
|
|
||||||
|
pub(crate) mod netinet6;
|
||||||
|
|
||||||
|
pub(crate) mod sys;
|
||||||
|
|
@ -0,0 +1,57 @@
|
||||||
|
//! Header: `net/bpf.h`
|
||||||
|
//!
|
||||||
|
//! <https://github.com/apple-oss-distributions/xnu/blob/main/bsd/net/bpf.h>
|
||||||
|
|
||||||
|
use crate::prelude::*;
|
||||||
|
use crate::sys::ioccom::*;
|
||||||
|
|
||||||
|
s! {
|
||||||
|
pub struct bpf_insn {
|
||||||
|
pub code: c_ushort,
|
||||||
|
pub jt: c_uchar,
|
||||||
|
pub jf: c_uchar,
|
||||||
|
pub k: u32,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct bpf_program {
|
||||||
|
pub bf_len: c_uint,
|
||||||
|
pub bf_insns: *mut bpf_insn,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
s_no_extra_traits! {
|
||||||
|
#[repr(packed(4))]
|
||||||
|
pub struct bpf_dltlist {
|
||||||
|
pub bfl_len: u32,
|
||||||
|
pub bfl_u: __c_anonymous_bfl_u,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub union __c_anonymous_bfl_u {
|
||||||
|
pub bflu_list: *mut u32,
|
||||||
|
pub bflu_pad: u64,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub const DLT_NULL: c_uint = 0; // no link-layer encapsulation
|
||||||
|
pub const DLT_EN10MB: c_uint = 1; // Ethernet (10Mb)
|
||||||
|
pub const DLT_EN3MB: c_uint = 2; // Experimental Ethernet (3Mb)
|
||||||
|
pub const DLT_AX25: c_uint = 3; // Amateur Radio AX.25
|
||||||
|
pub const DLT_PRONET: c_uint = 4; // Proteon ProNET Token Ring
|
||||||
|
pub const DLT_CHAOS: c_uint = 5; // Chaos
|
||||||
|
pub const DLT_IEEE802: c_uint = 6; // IEEE 802 Networks
|
||||||
|
pub const DLT_ARCNET: c_uint = 7; // ARCNET
|
||||||
|
pub const DLT_SLIP: c_uint = 8; // Serial Line IP
|
||||||
|
pub const DLT_PPP: c_uint = 9; // Point-to-point Protocol
|
||||||
|
pub const DLT_FDDI: c_uint = 10; // FDDI
|
||||||
|
pub const DLT_ATM_RFC1483: c_uint = 11; // LLC/SNAP encapsulated atm
|
||||||
|
pub const DLT_RAW: c_uint = 12; // raw IP
|
||||||
|
pub const DLT_LOOP: c_uint = 108;
|
||||||
|
|
||||||
|
pub const BPF_ALIGNMENT: c_int = size_of::<i32>() as c_int;
|
||||||
|
|
||||||
|
pub const BIOCGRSIG: c_ulong = _IOR::<c_uint>('B' as c_ulong, 114);
|
||||||
|
pub const BIOCSRSIG: c_ulong = _IOW::<c_uint>('B' as c_ulong, 115);
|
||||||
|
pub const BIOCGSEESENT: c_ulong = _IOR::<c_uint>('B' as c_ulong, 118);
|
||||||
|
pub const BIOCSSEESENT: c_ulong = _IOW::<c_uint>('B' as c_ulong, 119);
|
||||||
|
pub const BIOCSDLT: c_ulong = _IOW::<c_uint>('B' as c_ulong, 120);
|
||||||
|
pub const BIOCGDLTLIST: c_ulong = _IOWR::<bpf_dltlist>('B' as c_ulong, 121);
|
||||||
|
|
@ -0,0 +1,5 @@
|
||||||
|
//! Directory: `net/`
|
||||||
|
//!
|
||||||
|
//! <https://github.com/apple-oss-distributions/xnu/tree/main/bsd/net>
|
||||||
|
|
||||||
|
pub(crate) mod bpf;
|
||||||
|
|
@ -0,0 +1,22 @@
|
||||||
|
//! Header: `netinet6/in6_var.h`
|
||||||
|
//!
|
||||||
|
//! <https://github.com/apple-oss-distributions/xnu/blob/main/bsd/netinet6/in6_var.h>
|
||||||
|
|
||||||
|
use crate::prelude::*;
|
||||||
|
use crate::sys::ioccom::*;
|
||||||
|
|
||||||
|
pub const IN6_IFF_ANYCAST: c_int = 0x0001;
|
||||||
|
pub const IN6_IFF_TENTATIVE: c_int = 0x0002;
|
||||||
|
pub const IN6_IFF_DUPLICATED: c_int = 0x0004;
|
||||||
|
pub const IN6_IFF_DETACHED: c_int = 0x0008;
|
||||||
|
pub const IN6_IFF_DEPRECATED: c_int = 0x0010;
|
||||||
|
pub const IN6_IFF_NODAD: c_int = 0x0020;
|
||||||
|
pub const IN6_IFF_AUTOCONF: c_int = 0x0040;
|
||||||
|
pub const IN6_IFF_TEMPORARY: c_int = 0x0080;
|
||||||
|
pub const IN6_IFF_DYNAMIC: c_int = 0x0100;
|
||||||
|
pub const IN6_IFF_OPTIMISTIC: c_int = 0x0200;
|
||||||
|
pub const IN6_IFF_SECURED: c_int = 0x0400;
|
||||||
|
pub const IN6_IFF_CLAT46: c_int = 0x1000;
|
||||||
|
pub const IN6_IFF_NOPFX: c_int = 0x8000;
|
||||||
|
|
||||||
|
pub const SIOCGIFAFLAG_IN6: c_ulong = _IOWR::<crate::in6_ifreq>('i' as c_ulong, 73);
|
||||||
|
|
@ -0,0 +1,5 @@
|
||||||
|
//! Directory: `netinet6/`
|
||||||
|
//!
|
||||||
|
//! <https://github.com/apple-oss-distributions/xnu/tree/main/bsd/netinet6>
|
||||||
|
|
||||||
|
pub(crate) mod in6_var;
|
||||||
|
|
@ -0,0 +1,17 @@
|
||||||
|
//! Header: `sys/_types/_ucontext.h`
|
||||||
|
|
||||||
|
pub use crate::machine::_mcontext::*;
|
||||||
|
use crate::prelude::*;
|
||||||
|
|
||||||
|
s! {
|
||||||
|
pub struct __darwin_ucontext {
|
||||||
|
pub uc_onstack: c_int,
|
||||||
|
pub uc_sigmask: crate::sigset_t,
|
||||||
|
pub uc_stack: crate::stack_t,
|
||||||
|
pub uc_link: *mut ucontext_t,
|
||||||
|
pub uc_mcsize: usize,
|
||||||
|
pub uc_mcontext: mcontext_t,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub type ucontext_t = __darwin_ucontext;
|
||||||
|
|
@ -0,0 +1,49 @@
|
||||||
|
//! Header: `sys/ioccom.h`
|
||||||
|
//!
|
||||||
|
//! <https://github.com/apple-oss-distributions/xnu/blob/main/bsd/sys/ioccom.h>
|
||||||
|
|
||||||
|
use crate::prelude::*;
|
||||||
|
|
||||||
|
const IOCPARM_MASK: c_ulong = 0x1fff;
|
||||||
|
|
||||||
|
const IOCPARM_MAX: c_ulong = IOCPARM_MASK + 1;
|
||||||
|
|
||||||
|
// These are u32 in source but would probably be more practical as c_ulong if we ever need
|
||||||
|
// to make them public.
|
||||||
|
pub(crate) const IOC_VOID: u32 = 0x20000000;
|
||||||
|
pub(crate) const IOC_OUT: u32 = 0x40000000;
|
||||||
|
pub(crate) const IOC_IN: u32 = 0x80000000;
|
||||||
|
pub(crate) const IOC_INOUT: u32 = IOC_IN | IOC_OUT;
|
||||||
|
pub(crate) const IOC_DIRMASK: u32 = 0xe0000000;
|
||||||
|
|
||||||
|
// Only pub(crate) for the above reason.
|
||||||
|
pub(crate) const fn _IOC(inout: u32, group: c_ulong, num: c_ulong, len: c_ulong) -> c_ulong {
|
||||||
|
debug_assert!(inout <= IOC_DIRMASK);
|
||||||
|
debug_assert!(group <= 0xff);
|
||||||
|
debug_assert!(num <= 0xff);
|
||||||
|
debug_assert!(len <= IOCPARM_MAX);
|
||||||
|
|
||||||
|
// Sanity check the cast
|
||||||
|
assert!(size_of::<u32>() <= size_of::<c_ulong>());
|
||||||
|
|
||||||
|
(inout as c_ulong) | ((len & IOCPARM_MASK) << 16) | (group << 8) | num
|
||||||
|
}
|
||||||
|
|
||||||
|
pub const fn _IO(g: c_ulong, n: c_ulong) -> c_ulong {
|
||||||
|
_IOC(IOC_VOID, g, n, 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Build an ioctl number for an read-only ioctl.
|
||||||
|
pub const fn _IOR<T>(g: c_ulong, n: c_ulong) -> c_ulong {
|
||||||
|
_IOC(IOC_OUT, g, n, mem::size_of::<T>() as c_ulong)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Build an ioctl number for an write-only ioctl.
|
||||||
|
pub const fn _IOW<T>(g: c_ulong, n: c_ulong) -> c_ulong {
|
||||||
|
_IOC(IOC_IN, g, n, mem::size_of::<T>() as c_ulong)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Build an ioctl number for a read-write ioctl.
|
||||||
|
pub const fn _IOWR<T>(g: c_ulong, n: c_ulong) -> c_ulong {
|
||||||
|
_IOC(IOC_INOUT, g, n, mem::size_of::<T>() as c_ulong)
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,18 @@
|
||||||
|
//! Directory: `sys/`
|
||||||
|
//!
|
||||||
|
//! <https://github.com/apple-oss-distributions/xnu/tree/main/bsd/sys>
|
||||||
|
|
||||||
|
pub(crate) mod ioccom;
|
||||||
|
pub(crate) mod signal;
|
||||||
|
pub(crate) mod sockio;
|
||||||
|
pub(crate) mod ttycom;
|
||||||
|
|
||||||
|
/// Directory: `sys/_types`
|
||||||
|
///
|
||||||
|
/// https://github.com/apple-oss-distributions/xnu/tree/main/bsd/sys/_types
|
||||||
|
pub(crate) mod _types {
|
||||||
|
pub(crate) mod _ucontext;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Bit of a hack since the directories get merged and we can't have >1 sys module.
|
||||||
|
pub(crate) use crate::new::apple::libpthread::sys::*;
|
||||||
|
|
@ -0,0 +1,6 @@
|
||||||
|
//! Header: `sys/signal.h`
|
||||||
|
//!
|
||||||
|
//! <https://github.com/apple-oss-distributions/xnu/blob/main/bsd/sys/signal.h>
|
||||||
|
|
||||||
|
pub use crate::machine::_mcontext::*;
|
||||||
|
pub use crate::sys::_types::_ucontext::*;
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue