lexical-util-1.0.6/.cargo_vcs_info.json0000644000000001520000000000100134320ustar { "git": { "sha1": "9317490bffb694a1501d11fb74c97ae883bee572" }, "path_in_vcs": "lexical-util" }lexical-util-1.0.6/CODE_OF_CONDUCT.md000064400000000000000000000230251046102023000150250ustar 00000000000000# Code of Conduct ## When Something Happens If you see a Code of Conduct violation, follow these steps: 1. Let the person know that what they did is not appropriate and ask them to stop and/or edit their message(s) or commits. 2. That person should immediately stop the behavior and correct the issue. 3. If this doesn’t happen, or if you're uncomfortable speaking up, [contact the maintainers](#contacting-maintainers). 4. As soon as available, a maintainer will look into the issue, and take [further action (see below)](#further-enforcement), starting with a warning, then temporary block, then long-term repo or organization ban. When reporting, please include any relevant details, links, screenshots, context, or other information that may be used to better understand and resolve the situation. **The maintainer team will prioritize the well-being and comfort of the recipients of the violation over the comfort of the violator.** See [some examples below](#enforcement-examples). ## Our Pledge In the interest of fostering an open and welcoming environment, we as contributors and maintainers of this project pledge to making participation in our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, technical preferences, nationality, personal appearance, race, religion, or sexual identity and orientation. ## Our Standards Examples of behavior that contributes to creating a positive environment include: - Using welcoming and inclusive language. - Being respectful of differing viewpoints and experiences. - Gracefully accepting constructive feedback. - Focusing on what is best for the community. - Showing empathy and kindness towards other community members. - Encouraging and raising up your peers in the project so you can all bask in hacks and glory. Examples of unacceptable behavior by participants include: - The use of sexualized language or imagery and unwelcome sexual attention or advances, including when simulated online. The only exception to sexual topics is channels/spaces specifically for topics of sexual identity. - Casual mention of slavery or indentured servitude and/or false comparisons of one's occupation or situation to slavery. Please consider using or asking about alternate terminology when referring to such metaphors in technology. - Making light of/making mocking comments about trigger warnings and content warnings. - Trolling, insulting/derogatory comments, and personal or political attacks. - Public or private harassment, deliberate intimidation, or threats. - Publishing others' private information, such as a physical or electronic address, without explicit permission. This includes any sort of "outing" of any aspect of someone's identity without their consent. - Publishing private screenshots or quotes of interactions in the context of this project without all quoted users' *explicit* consent. - Publishing of private communication that doesn't have to do with reporting harrassment. - Any of the above even when [presented as "ironic" or "joking"](https://en.wikipedia.org/wiki/Hipster_racism). - Any attempt to present "reverse-ism" versions of the above as violations. Examples of reverse-isms are "reverse racism", "reverse sexism", "heterophobia", and "cisphobia". - Unsolicited explanations under the assumption that someone doesn't already know it. Ask before you teach! Don't assume what people's knowledge gaps are. - [Feigning or exaggerating surprise](https://www.recurse.com/manual#no-feigned-surprise) when someone admits to not knowing something. - "[Well-actuallies](https://www.recurse.com/manual#no-well-actuallys)" - Other conduct which could reasonably be considered inappropriate in a professional or community setting. ## Scope This Code of Conduct applies both within spaces involving this project and in other spaces involving community members. This includes the repository, its Pull Requests and Issue tracker, private email communications in the context of the project, and any events where members of the project are participating, as well as adjacent communities and venues affecting the project's members. Depending on the violation, the maintainers may decide that violations of this code of conduct that have happened outside of the scope of the community may deem an individual unwelcome, and take appropriate action to maintain the comfort and safety of its members. ### Other Community Standards As a project on GitHub, this project is additionally covered by the [GitHub Community Guidelines](https://help.github.com/articles/github-community-guidelines/). Enforcement of those guidelines after violations overlapping with the above are the responsibility of the entities, and enforcement may happen in any or all of the services/communities. ## Maintainer Enforcement Process Once the maintainers get involved, they will follow a documented series of steps and do their best to preserve the well-being of project members. This section covers actual concrete steps. ### Contacting Maintainers You may get in touch with the maintainer team through any of the following methods: Through email: ahuszagh@gmail.com (Alex Huszagh) ### Further Enforcement If you've already followed the [initial enforcement steps](#maintainer-enforcement-process), these are the steps maintainers will take for further enforcement, as needed: 1. Repeat the request to stop. 2. If the person doubles down, they will have offending messages removed or edited by a maintainers given an official warning. The PR or Issue may be locked. 3. If the behavior continues or is repeated later, the person will be blocked from participating for 24 hours. 4. If the behavior continues or is repeated after the temporary block, a long-term (6-12mo) ban will be used. On top of this, maintainers may remove any offending messages, images, contributions, etc, as they deem necessary. Maintainers reserve full rights to skip any of these steps, at their discretion, if the violation is considered to be a serious and/or immediate threat to the health and well-being of members of the community. These include any threats, serious physical or verbal attacks, and other such behavior that would be completely unacceptable in any social setting that puts our members at risk. Members expelled from events or venues with any sort of paid attendance will not be refunded. ### Who Watches the Watchers? Maintainers and other leaders who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership. These may include anything from removal from the maintainer team to a permanent ban from the community. Additionally, as a project hosted on both GitHub and npm, [their own Codes of Conducts may be applied against maintainers of this project](#other-community-standards), externally of this project's procedures. ### Enforcement Examples #### The Best Case The vast majority of situations work out like this. This interaction is common, and generally positive. > Alex: "Yeah I used X and it was really crazy!" > Patt (not a maintainer): "Hey, could you not use that word? What about 'ridiculous' instead?" > Alex: "oh sorry, sure." -> edits old comment to say "it was really confusing!" #### The Maintainer Case Sometimes, though, you need to get maintainers involved. Maintainers will do their best to resolve conflicts, but people who were harmed by something **will take priority**. > Patt: "Honestly, sometimes I just really hate using $library and anyone who uses it probably sucks at their job." > Alex: "Whoa there, could you dial it back a bit? There's a CoC thing about attacking folks' tech use like that." > Patt: "I'm not attacking anyone, what's your problem?" > Alex: "@maintainers hey uh. Can someone look at this issue? Patt is getting a bit aggro. I tried to nudge them about it, but nope." > KeeperOfCommitBits: (on issue) "Hey Patt, maintainer here. Could you tone it down? This sort of attack is really not okay in this space." > Patt: "Leave me alone I haven't said anything bad wtf is wrong with you." > KeeperOfCommitBits: (deletes user's comment), "@patt I mean it. Please refer to the CoC over at (URL to this CoC) if you have questions, but you can consider this an actual warning. I'd appreciate it if you reworded your messages in this thread, since they made folks there uncomfortable. Let's try and be kind, yeah?" > Patt: "@keeperofbits Okay sorry. I'm just frustrated and I'm kinda burnt out and I guess I got carried away. I'll DM Alex a note apologizing and edit my messages. Sorry for the trouble." > KeeperOfCommitBits: "@patt Thanks for that. I hear you on the stress. Burnout sucks :/. Have a good one!" #### The Nope Case > PepeTheFrog🐸: "Hi, I am a literal actual nazi and I think white supremacists are quite fashionable." > Patt: "NOOOOPE. OH NOPE NOPE." > Alex: "JFC NO. NOPE. @keeperofbits NOPE NOPE LOOK HERE" > KeeperOfCommitBits: "👀 Nope. NOPE NOPE NOPE. 🔥" > PepeTheFrog🐸 has been banned from all organization or user repositories belonging to KeeperOfCommitBits. ## Attribution This Code of Conduct was generated using [WeAllJS Code of Conduct Generator](https://npm.im/weallbehave), which is based on the [WeAllJS Code of Conduct](https://wealljs.org/code-of-conduct), which is itself based on [Contributor Covenant](http://contributor-covenant.org), version 1.4, available at [http://contributor-covenant.org/version/1/4](http://contributor-covenant.org/version/1/4), and the LGBTQ in Technology Slack [Code of Conduct](http://lgbtq.technology/coc.html). lexical-util-1.0.6/Cargo.toml0000644000000053200000000000100114320ustar # 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.63.0" name = "lexical-util" version = "1.0.6" authors = ["Alex Huszagh "] build = false exclude = [ "assets/*", "docs/*", "etc/*", "cargo-timing*.html", ] autobins = false autoexamples = false autotests = false autobenches = false description = "Shared utilities for lexical creates." readme = "README.md" keywords = ["no_std"] categories = [ "value-formatting", "encoding", "no-std", ] license = "MIT/Apache-2.0" repository = "https://github.com/Alexhuszagh/rust-lexical" [package.metadata.docs.rs] features = [ "radix", "format", "write-integers", "write-floats", "parse-integers", "parse-floats", ] [lib] name = "lexical_util" path = "src/lib.rs" [[test]] name = "algorithm_tests" path = "tests/algorithm_tests.rs" [[test]] name = "ascii_tests" path = "tests/ascii_tests.rs" [[test]] name = "bf16_tests" path = "tests/bf16_tests.rs" [[test]] name = "digit_tests" path = "tests/digit_tests.rs" [[test]] name = "div128_tests" path = "tests/div128_tests.rs" [[test]] name = "f16_tests" path = "tests/f16_tests.rs" [[test]] name = "feature_format_tests" path = "tests/feature_format_tests.rs" [[test]] name = "format_builder_tests" path = "tests/format_builder_tests.rs" [[test]] name = "format_flags_tests" path = "tests/format_flags_tests.rs" [[test]] name = "iterator_tests" path = "tests/iterator_tests.rs" [[test]] name = "mul_tests" path = "tests/mul_tests.rs" [[test]] name = "not_feature_format_tests" path = "tests/not_feature_format_tests.rs" [[test]] name = "num_tests" path = "tests/num_tests.rs" [[test]] name = "skip_tests" path = "tests/skip_tests.rs" [[test]] name = "util" path = "tests/util.rs" [dependencies.static_assertions] version = "1" [dev-dependencies.proptest] version = ">=1.5.0" [features] compact = [] default = ["std"] f128 = [ "parse-floats", "write-floats", ] f16 = [ "parse-floats", "write-floats", ] floats = [] format = [] integers = [] lint = [] parse = [] parse-floats = [ "parse", "floats", ] parse-integers = [ "parse", "integers", ] power-of-two = [] radix = ["power-of-two"] std = [] write = [] write-floats = [ "write", "floats", ] write-integers = [ "write", "integers", ] lexical-util-1.0.6/Cargo.toml.orig000064400000000000000000000051761046102023000151240ustar 00000000000000[package] authors = ["Alex Huszagh "] autobenches = false categories = ["value-formatting", "encoding", "no-std"] description = "Shared utilities for lexical creates." edition = "2021" keywords = ["no_std"] license = "MIT/Apache-2.0" name = "lexical-util" readme = "README.md" repository = "https://github.com/Alexhuszagh/rust-lexical" version = "1.0.6" rust-version = "1.63.0" exclude = [ "assets/*", "docs/*", "etc/*", "cargo-timing*.html" ] [dependencies] static_assertions = "1" [dev-dependencies] # FIXME: Replace back to "1.0.4" once the PR is merged. # There's an issue in quickcheck due to an infinitely repeating shrinker. # Issue: https://github.com/BurntSushi/quickcheck/issues/295 # Fix: https://github.com/BurntSushi/quickcheck/pull/296 quickcheck = { git = "https://github.com/Alexhuszagh/quickcheck/", branch = "i32min-shrink-bound-legacy" } proptest = ">=1.5.0" # FEATURES # -------- # In order to improve compile times, we have separate support # for each numeric conversion. Since these features are additive, # if more features are added, separate crates can add support # for more features without requiring re-compilation of lexical. [features] default = ["std"] # Use the standard library. std = [] # Add support for numerical conversions with power-of-two strings. power-of-two = [] # Add support for numerical conversions with non-decimal strings. radix = ["power-of-two"] # Add support for parsing custom numerical formats. format = [] # Add support for writing integers. write-integers = ["write", "integers"] # Add support for writing floats. write-floats = ["write", "floats"] # Add support for parsing integers. parse-integers = ["parse", "integers"] # Add support for parsing floats. parse-floats = ["parse", "floats"] # Reduce code size at the cost of performance. compact = [] # Add support for the `f16` and `b16` half-point floating point numbers. f16 = ["parse-floats", "write-floats"] # Internal only features. # Enable the lint checks. lint = [] # Add support for writing numbers. write = [] # Add support for parsing numbers. parse = [] # Add support for conversions to or from integers. integers = [] # Add support for conversions to or from floats. floats = [] # UNSUPPORTED # ----------- # Currently unsupported features. # Enable support for 128-bit floats. Unsupported and unlikely to ever be. # https://github.com/Alexhuszagh/rust-lexical/issues/46 # Enable support for 16-bit floats. # Enable support for 128-bit floats. f128 = ["parse-floats", "write-floats"] [package.metadata.docs.rs] features = ["radix", "format", "write-integers", "write-floats", "parse-integers", "parse-floats"] lexical-util-1.0.6/LICENSE-APACHE000064400000000000000000000251421046102023000141540ustar 00000000000000 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. lexical-util-1.0.6/LICENSE-MIT000064400000000000000000000017771046102023000136740ustar 00000000000000Permission 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. lexical-util-1.0.6/README.md000064400000000000000000000523741046102023000135160ustar 00000000000000# lexical High-performance numeric conversion routines for use in a `no_std` environment. This does not depend on any standard library features, nor a system allocator. Comprehensive benchmarks can be found at [lexical-benchmarks](https://github.com/Alexhuszagh/lexical-benchmarks). **Similar Projects** If you want a minimal, performant float parser, recent versions of the Rust standard library should be [sufficient](https://github.com/rust-lang/rust/pull/86761). For high-performance integer formatters, look at [itoa](https://docs.rs/itoa/latest/itoa/). The [metrics](#metrics) section contains a detailed comparison of various crates and their performance in comparison to lexical. Lexical is the currently fastest Rust number formatter and parser, and is tested against: - [itoa](https://crates.io/crates/itoa) - [dtoa](https://crates.io/crates/dtoa) - [ryu](https://crates.io/crates/ryu) - Rust core library **Table of Contents** - [Getting Started](#getting-started) - [Partial/Complete Parsers](#partialcomplete-parsers) - [no_std](#no_std) - [Features](#features) - [Customization](#customization) - [Number Format API](#number-format-api) - [Options API](#options-api) - [Documentation](#documentation) - [Validation](#validation) - [Metrics](#metrics) - [Safety](#safety) - [Platform Support](#platform-support) - [Versioning and Version Support](#versioning-and-version-support) - [Changelog](#changelog) - [License](#license) - [Contributing](#contributing) ## Getting Started Add lexical to your `Cargo.toml`: ```toml [dependencies] lexical-core = "^1.0" ``` And get started using lexical: ```rust // Number to string use lexical_core::BUFFER_SIZE; let mut buffer = [b'0'; BUFFER_SIZE]; lexical_core::write(3.0, &mut buffer); // "3.0", always has a fraction suffix, lexical_core::write(3, &mut buffer); // "3" // String to number. let i: i32 = lexical_core::parse("3")?; // Ok(3), auto-type deduction. let f: f32 = lexical_core::parse("3.5")?; // Ok(3.5) let d: f64 = lexical_core::parse("3.5")?; // Ok(3.5), error checking parse. let d: f64 = lexical_core::parse("3a")?; // Err(Error(_)), failed to parse. ``` In order to use lexical in generic code, the trait bounds `FromLexical` (for `parse`) and `ToLexical` (for `to_string`) are provided. ```rust /// Multiply a value in a string by multiplier, and serialize to string. fn mul_2(value: &str, multiplier: T) -> Result where T: lexical_core::ToLexical + lexical_core::FromLexical, { let value: T = lexical_core::parse(value.as_bytes())?; let mut buffer = [b'0'; lexical_core::BUFFER_SIZE]; let bytes = lexical_core::write(value * multiplier, &mut buffer); Ok(std::str::from_utf8(bytes).unwrap()) } ``` ## Partial/Complete Parsers Lexical has both partial and complete parsers: the complete parsers ensure the entire buffer is used while parsing, without ignoring trailing characters, while the partial parsers parse as many characters as possible, returning both the parsed value and the number of parsed digits. Upon encountering an error, lexical will return an error indicating both the error type and the index at which the error occurred inside the buffer. **Complete Parsers** ```rust // This will return Err(Error::InvalidDigit(3)), indicating // the first invalid character occurred at the index 3 in the input // string (the space character). let x: i32 = lexical_core::parse(b"123 456")?; ``` **Partial Parsers** ```rust // This will return Ok((123, 3)), indicating that 3 digits were successfully // parsed, and that the returned value is `123`. let (x, count): (i32, usize) = lexical_core::parse_partial(b"123 456")?; ``` ## no_std `lexical-core` does not depend on a standard library, nor a system allocator. To use `lexical-core` in a `no_std` environment, add the following to `Cargo.toml`: ```toml [dependencies.lexical-core] version = "1.0.0" default-features = false # Can select only desired parsing/writing features. features = ["write-integers", "write-floats", "parse-integers", "parse-floats"] ``` And get started using lexical: ```rust // A constant for the maximum number of bytes a formatter will write. use lexical_core::BUFFER_SIZE; let mut buffer = [b'0'; BUFFER_SIZE]; // Number to string. The underlying buffer must be a slice of bytes. let count = lexical_core::write(3.0, &mut buffer); assert_eq!(buffer[..count], b"3.0"); let count = lexical_core::write(3i32, &mut buffer); assert_eq!(buffer[..count], b"3"); // String to number. The input must be a slice of bytes. let i: i32 = lexical_core::parse(b"3")?; // Ok(3), auto-type deduction. let f: f32 = lexical_core::parse(b"3.5")?; // Ok(3.5) let d: f64 = lexical_core::parse(b"3.5")?; // Ok(3.5), error checking parse. let d: f64 = lexical_core::parse(b"3a")?; // Err(Error(_)), failed to parse. ``` ## Features Lexical feature-gates each numeric conversion routine, resulting in faster compile times if certain numeric conversions. These features can be enabled/disabled for both `lexical-core` (which does not require a system allocator) and `lexical`. By default, all conversions are enabled. - **parse-floats**:   Enable string-to-float conversions. - **parse-integers**:   Enable string-to-integer conversions. - **write-floats**:   Enable float-to-string conversions. - **write-integers**:   Enable integer-to-string conversions. Lexical is highly customizable, and contains numerous other optional features: - **std**:   Enable use of the Rust standard library (enabled by default). - **power-of-two**:   Enable conversions to and from non-decimal strings.
With power_of_two enabled, the radixes {2, 4, 8, 10, 16, and 32} are valid, otherwise, only 10 is valid. This enables common conversions to/from hexadecimal integers/floats, without requiring large pre-computed tables for other radixes.
- **radix**:   Allow conversions to and from non-decimal strings.
With radix enabled, any radix from 2 to 36 (inclusive) is valid, otherwise, only 10 is valid.
- **format**:   Customize acceptable number formats for number parsing and writing.
With format enabled, the number format is dictated through bitflags and masks packed into a u128. These dictate the valid syntax of parsed and written numbers, including enabling digit separators, requiring integer or fraction digits, and toggling case-sensitive exponent characters.
- **compact**:   Optimize for binary size at the expense of performance.
This minimizes the use of pre-computed tables, producing significantly smaller binaries.
- **f16**:   Add support for numeric conversions to-and-from 16-bit floats.
Adds f16, a half-precision IEEE-754 floating-point type, and bf16, the Brain Float 16 type, and numeric conversions to-and-from these floats. Note that since these are storage formats, and therefore do not have native arithmetic operations, all conversions are done using an intermediate f32.
To ensure memory safety, we extensively fuzz the all numeric conversion routines. See the [Safety](#safety) section below for more information. Lexical also places a heavy focus on code bloat: with algorithms both optimized for performance and size. By default, this focuses on performance, however, using the `compact` feature, you can also opt-in to reduced code size at the cost of performance. The compact algorithms minimize the use of pre-computed tables and other optimizations at a major cost to performance. ## Customization Lexical is extensively customizable to support parsing numbers from a wide variety of programming languages, such as `1_2_3`. However, lexical takes the concept of "you don't pay for what you don't use" seriously: enabling the `format` feature does not affect the performance of parsing regular numbers: only those with digit separators. > ⚠ **WARNING:** When changing the number of significant digits written, disabling the use of exponent notation, or changing exponent notation thresholds, `BUFFER_SIZE` may be insufficient to hold the resulting output. `WriteOptions::buffer_size` will provide a correct upper bound on the number of bytes written. If a buffer of insufficient length is provided, lexical-core will panic. Every language has competing specifications for valid numerical input, meaning a number parser for Rust will incorrectly accept or reject input for different programming or data languages. For example: ```rust // Valid in Rust strings. // Not valid in JSON. let f: f64 = lexical_core::parse(b"3.e7")?; // 3e7 // Let's only accept JSON floats. const JSON: u128 = lexical_core::format::JSON; let options = ParseFloatOptions::new(); let f: f64 = lexical_core::parse_with_options::(b"3.0e7", &options)?; // 3e7 let f: f64 = lexical_core::parse_with_options::(b"3.e7", &options)?; // Errors! ``` Due the high variability in the syntax of numbers in different programming and data languages, we provide 2 different APIs to simplify converting numbers with different syntax requirements. - Number Format API (feature-gated via `format` or `power-of-two`).
This is a packed struct contained flags to specify compile-time syntax rules for number parsing or writing. This includes features such as the radix of the numeric string, digit separators, case-sensitive exponent characters, optional base prefixes/suffixes, and more.
- Options API.
This contains run-time rules for parsing and writing numbers. This includes exponent break points, rounding modes, the exponent and decimal point characters, and the string representation of NaN and Infinity.
A limited subset of functionality is documented in examples below, however, the complete specification can be found in the API reference documentation ([parse-float](https://docs.rs/lexical-parse-float/latest/lexical_parse_float/struct.Options.html), [parse-integer](https://docs.rs/lexical-parse-integer/latest/lexical_parse_integer/struct.Options.html), and [write-float](https://docs.rs/lexical-write-float/latest/lexical_write_float/struct.Options.html)). ### Number Format API The number format class provides numerous flags to specify number syntax when parsing or writing. When the `power-of-two` feature is enabled, additional flags are added: - The radix for the significant digits (default `10`). - The radix for the exponent base (default `10`). - The radix for the exponent digits (default `10`). When the `format` feature is enabled, numerous other syntax and digit separator flags are enabled, including: - A digit separator character, to group digits for increased legibility. - Whether leading, trailing, internal, and consecutive digit separators are allowed. - Toggling required float components, such as digits before the decimal point. - Toggling whether special floats are allowed or are case-sensitive. Many pre-defined constants therefore exist to simplify common use-cases, including: - JSON, XML, TOML, YAML, SQLite, and many more. - Rust, Python, C#, FORTRAN, COBOL literals and strings, and many more. An example of building a custom number format is as follows: ```rust const FORMAT: u128 = lexical_core::NumberFormatBuilder::new() // Disable exponent notation. .no_exponent_notation(true) // Disable all special numbers, such as Nan and Inf. .no_special(true) .build(); // Due to use in a `const fn`, we can't panic or expect users to unwrap invalid // formats, so it's up to the caller to verify the format. If an invalid format // is provided to a parser or writer, the function will error or panic, respectively. debug_assert!(lexical_core::format_is_valid::()); ``` ### Options API The options API allows customizing number parsing and writing at run-time, such as specifying the maximum number of significant digits, exponent characters, and more. An example of building a custom options struct is as follows: ```rust use std::num; let options = lexical_core::WriteFloatOptions::builder() // Only write up to 5 significant digits, IE, `1.23456` becomes `1.2345`. .max_significant_digits(num::NonZeroUsize::new(5)) // Never write less than 5 significant digits, `1.1` becomes `1.1000`. .min_significant_digits(num::NonZeroUsize::new(5)) // Trim the trailing `.0` from integral float strings. .trim_floats(true) // Use a European-style decimal point. .decimal_point(b',') // Panic if we try to write NaN as a string. .nan_string(None) // Write infinity as "Infinity". .inf_string(Some(b"Infinity")) .build() .unwrap(); ``` ## Documentation Lexical's API reference can be found on [docs.rs](https://docs.rs/lexical), as can [lexical-core's](lexical-core). Detailed descriptions of the algorithms used can be found here: - [Parsing Integers](https://github.com/Alexhuszagh/rust-lexical/blob/main/lexical-parse-integer/docs/Algorithm.md) - [Parsing Floats](https://github.com/Alexhuszagh/rust-lexical/blob/main/lexical-parse-float/docs/Algorithm.md) - [Writing Integers](https://github.com/Alexhuszagh/rust-lexical/blob/main/lexical-write-integer/docs/Algorithm.md) - [Writing Floats](https://github.com/Alexhuszagh/rust-lexical/blob/main/lexical-write-float/docs/Algorithm.md) In addition, descriptions of how lexical handles [digit separators](https://github.com/Alexhuszagh/rust-lexical/blob/main/docs/DigitSeparators.md) and implements [big-integer arithmetic](https://github.com/Alexhuszagh/rust-lexical/blob/main/lexical-parse-float/docs/BigInteger.md) are also documented. ## Validation **Float-Parsing** Float parsing is difficult to do correctly, and major bugs have been found in implementations from [libstdc++'s strtod](https://www.exploringbinary.com/glibc-strtod-incorrectly-converts-2-to-the-negative-1075/) to [Python](https://bugs.python.org/issue7632). In order to validate the accuracy of the lexical, we employ the following external tests: 1. Hrvoje Abraham's [strtod](https://github.com/ahrvoje/numerics/tree/master/strtod) test cases. 2. Rust's [test-float-parse](https://github.com/rust-lang/rust/tree/64185f205dcbd8db255ad6674e43c63423f2369a/src/etc/test-float-parse) unittests. 3. Testbase's [stress tests](https://www.icir.org/vern/papers/testbase-report.pdf) for converting from decimal to binary. 4. Nigel Tao's [tests](https://github.com/nigeltao/parse-number-fxx-test-data) extracted from test suites for Freetype, Google's double-conversion library, IBM's IEEE-754R compliance test, as well as numerous other curated examples. 5. [Various](https://www.exploringbinary.com/glibc-strtod-incorrectly-converts-2-to-the-negative-1075/) [difficult](https://www.exploringbinary.com/how-glibc-strtod-works/) [cases](https://www.exploringbinary.com/how-strtod-works-and-sometimes-doesnt/) reported on blogs. Lexical is extensively used in production, the same float parsing algorithm has been adopted by Golang's and Rust's standard libraries, and is unlikely to have correctness issues. ## Metrics Various benchmarks, binary sizes, and compile times are shown here. All the benchmarks can be found on [lexical-benchmarks](https://github.com/Alexhuszagh/lexical-benchmarks?tab=readme-ov-file#latest-results). All benchmarks used a black box to avoid optimizing out the result and leading to misleading metrics. **Build Timings** The compile-times when building with all numeric conversions enabled. For a more fine-tuned breakdown, see [build timings](https://github.com/Alexhuszagh/rust-lexical/blob/main/docs/BuildTimings.md). ![Build Timings](https://raw.githubusercontent.com/Alexhuszagh/rust-lexical/main/assets/timings_all_posix.svg) **Binary Size** The binary sizes of stripped binaries compiled at optimization level "2". For a more fine-tuned breakdown, see [binary sizes](https://github.com/Alexhuszagh/rust-lexical/blob/main/docs/BinarySize.md). ![Parse Stripped - Optimization Level "2"](https://raw.githubusercontent.com/Alexhuszagh/rust-lexical/main/assets/size_parse_stripped_opt2_posix.svg) ![Write Stripped - Optimization Level "2"](https://raw.githubusercontent.com/Alexhuszagh/rust-lexical/main/assets/size_write_stripped_opt2_posix.svg) ### Benchmarks — Parse Integer **Random** A benchmark on randomly-generated integers uniformly distributed over the entire range. ![Uniform Random Data](https://github.com/Alexhuszagh/lexical-benchmarks/raw/main/results/edceaca/plot/json_random%20-%20parse%20int%20-%20core,lexical.png) **Simple** A benchmark on randomly-generated integers from 1-1000. ![Simple Random Data](https://github.com/Alexhuszagh/lexical-benchmarks/raw/main/results/edceaca/plot/json_simple%20-%20parse%20int%20-%20core,lexical.png) ### Benchmarks — Parse Float **Real-World Datasets** A benchmark on parsing floats from various real-world data sets, including Canada, Mesh, and astronomical data (earth). ![Canada](https://github.com/Alexhuszagh/lexical-benchmarks/raw/main/results/edceaca/plot/canada%20-%20parse%20float%20-%20core,lexical.png) ![Earth](https://github.com/Alexhuszagh/lexical-benchmarks/raw/main/results/edceaca/plot/earth%20-%20parse%20float%20-%20core,lexical.png) ![Mesh](https://github.com/Alexhuszagh/lexical-benchmarks/raw/main/results/edceaca/plot/mesh%20-%20parse%20float%20-%20core,lexical.png) **Random** A benchmark on randomly-generated integers uniformly distributed over the entire range. ![Random Big Integer](https://github.com/Alexhuszagh/lexical-benchmarks/raw/main/results/edceaca/plot/random_big_ints%20-%20parse%20float%20-%20core,lexical.png) **Simple** A benchmark on randomly-generated integers from 1-1000. ![Random Simple](https://github.com/Alexhuszagh/lexical-benchmarks/raw/main/results/edceaca/plot/random_simple_int64%20-%20parse%20float%20-%20core,lexical.png) ### Benchmarks — Write Integer **Random** A benchmark on randomly-generated integers uniformly distributed over the entire range. ![Random Uniform](https://github.com/Alexhuszagh/lexical-benchmarks/raw/main/results/edceaca/plot/json_chain_random%20-%20write%20int%20-%20fmt,itoa,lexical.png) **Simple** ![Random Simple](https://github.com/Alexhuszagh/lexical-benchmarks/raw/main/results/edceaca/plot/json_simple%20-%20write%20int%20-%20fmt,itoa,lexical.png) **Large** ![Random Large](https://github.com/Alexhuszagh/lexical-benchmarks/raw/main/results/edceaca/plot/random_large%20-%20write%20int%20-%20fmt,itoa,lexical.png) ### Benchmarks — Write Float **Big Integer** A benchmarks for values with a large integers. ![Big Integers](https://github.com/Alexhuszagh/lexical-benchmarks/raw/main/results/edceaca/plot/random_big_ints%20-%20write%20float%20-%20dtoa,fmt,lexical,ryu.png) **Simple 64-Bit Inteers** ![Simple Int64](https://github.com/Alexhuszagh/lexical-benchmarks/raw/main/results/edceaca/plot/random_simple_int64%20-%20write%20float%20-%20dtoa,fmt,lexical,ryu.png) **Random** ![Random](https://github.com/Alexhuszagh/lexical-benchmarks/raw/main/results/edceaca/plot/json%20-%20write%20float%20-%20dtoa,fmt,lexical,ryu.png) ## Safety Due to the use of memory unsafe code in the library, we extensively fuzz our float writers and parsers. The fuzz harnesses may be found under [fuzz](https://github.com/Alexhuszagh/rust-lexical/tree/main/fuzz), and are run continuously. So far, we've parsed and written over 72 billion floats. ## Platform Support lexical-core is tested on a wide variety of platforms, including big and small-endian systems, to ensure portable code. Supported architectures include: - x86_64 Linux, Windows, macOS, Android, iOS, FreeBSD, and NetBSD. - x86 Linux, macOS, Android, iOS, and FreeBSD. - aarch64 (ARM8v8-A) Linux, Android, and iOS. - armv7 (ARMv7-A) Linux, Android, and iOS. - arm (ARMv6) Linux, and Android. - powerpc (PowerPC) Linux. - powerpc64 (PPC64) Linux. - powerpc64le (PPC64LE) Linux. - s390x (IBM Z) Linux. lexical-core should also work on a wide variety of other architectures and ISAs. If you have any issue compiling lexical-core on any architecture, please file a bug report. ## Versioning and Version Support **Version Support** The currently supported versions are: - v1.0.x Due to security considerations, all other versions are not supported and security advisories exist for them.. **Rustc Compatibility** - v1.0.x supports 1.63+, including stable, beta, and nightly. Please report any errors compiling a supported lexical-core version on a compatible Rustc version. **Versioning** lexical uses [semantic versioning](https://semver.org/). Removing support for Rustc versions newer than the latest stable Debian or Ubuntu version is considered an incompatible API change, requiring a major version change. ## Changelog All changes are documented in [CHANGELOG](https://github.com/Alexhuszagh/rust-lexical/blob/main/CHANGELOG). ## License Lexical is dual licensed under the Apache 2.0 license as well as the MIT license. See the [LICENSE.md](LICENSE.md) file for full license details. ## Contributing Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in lexical by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions. Contributing to the repository means abiding by the [code of conduct](https://github.com/Alexhuszagh/rust-lexical/blob/main/CODE_OF_CONDUCT.md). For the process on how to contribute to lexical, see the [development](https://github.com/Alexhuszagh/rust-lexical/blob/main/docs/Development.md) quick-start guide. lexical-util-1.0.6/src/algorithm.rs000064400000000000000000000024671046102023000153600ustar 00000000000000//! Simple, shared algorithms for slices and iterators. use crate::num::Integer; /// Copy bytes from source to destination. /// /// This is only used in our compact and radix integer formatted, so /// performance isn't the highest consideration here. #[inline(always)] #[cfg(feature = "write")] pub fn copy_to_dst>(dst: &mut [T], src: Bytes) -> usize { let src = src.as_ref(); dst[..src.len()].copy_from_slice(src); src.len() } /// Count the number of trailing characters equal to a given value. #[inline(always)] #[cfg(feature = "write")] pub fn rtrim_char_count(slc: &[u8], c: u8) -> usize { slc.iter().rev().take_while(|&&si| si == c).count() } /// Count the number of leading characters equal to a given value. #[inline(always)] #[cfg(feature = "write")] pub fn ltrim_char_count(slc: &[u8], c: u8) -> usize { slc.iter().take_while(|&&si| si == c).count() } /// Check to see if parsing the float cannot possible overflow. /// /// This allows major optimizations for those types, since we can skip checked /// arithmetic. /// /// Adapted from the rust [corelib](core). /// /// core: #[inline(always)] pub fn cannot_overflow(length: usize, radix: u32) -> bool { length <= T::overflow_digits(radix) } lexical-util-1.0.6/src/api.rs000064400000000000000000000243061046102023000141370ustar 00000000000000//! Implement string conversion routines in a single trait. // NOTE: // We use macros to define the traits, rather than implement here // since we can't define traits for types when both are defined outside // the current crate, including in workspaces. // FROM LEXICAL /// Define `FromLexical` trait. #[macro_export] #[cfg(feature = "parse")] macro_rules! from_lexical { () => { /// Trait for numerical types that can be parsed from bytes. pub trait FromLexical: lexical_util::num::Number { /// Checked parser for a string-to-number conversion. /// /// This method parses the entire string, returning an error if /// any invalid digits are found during parsing. Returns a `Result` /// containing either the parsed value, or an error containing /// any errors that occurred during parsing. /// /// * `bytes` - Slice containing a numeric string. fn from_lexical(bytes: &[u8]) -> lexical_util::result::Result; /// Checked parser for a string-to-number conversion. /// /// This method parses until an invalid digit is found (or the end /// of the string), returning the number of processed digits /// and the parsed value until that point. Returns a `Result` /// containing either the parsed value and the number of processed /// digits, or an error containing any errors that occurred during /// parsing. /// /// * `bytes` - Slice containing a numeric string. fn from_lexical_partial(bytes: &[u8]) -> lexical_util::result::Result<(Self, usize)>; } }; } /// Define `FromLexicalWithOptions` trait. #[macro_export] #[cfg(feature = "parse")] macro_rules! from_lexical_with_options { () => { /// Trait for numerical types that can be parsed from bytes with custom options. /// /// The `Options` type specifies the configurable options to provide. pub trait FromLexicalWithOptions: lexical_util::num::Number { /// Custom formatting options for parsing a number. type Options: lexical_util::options::ParseOptions; /// Checked parser for a string-to-number conversion. /// /// This method parses the entire string, returning an error if /// any invalid digits are found during parsing. The parsing /// is dictated by the options, which specifies special /// float strings, required float components, digit separators, /// exponent characters, and more. Returns a `Result` containing /// either the parsed value, or an error containing any errors /// that occurred during parsing. /// /// * `FORMAT` - Flags and characters designating the number grammar. /// * `bytes` - Slice containing a numeric string. /// * `options` - Options to dictate number parsing. /// /// The `FORMAT` packed struct is built using [`NumberFormatBuilder`]. /// Any invalid number format will prevent parsing, returning /// the appropriate format error. If you are unsure which format /// to use, use [`STANDARD`]. /// /// [`NumberFormatBuilder`]: lexical_util::format::NumberFormatBuilder /// [`STANDARD`]: lexical_util::format::STANDARD fn from_lexical_with_options( bytes: &[u8], options: &Self::Options, ) -> lexical_util::result::Result; /// Checked parser for a string-to-number conversion. /// /// This method parses until an invalid digit is found (or the end /// of the string), returning the number of processed digits /// and the parsed value until that point. Returns a `Result` /// containing either the parsed value and the number of /// processed digits, or an error containing any errors that /// occurred during parsing. /// /// * `FORMAT` - Flags and characters designating the number grammar. /// * `bytes` - Slice containing a numeric string. /// * `options` - Options to dictate number parsing. /// /// The `FORMAT` packed struct is built using [`NumberFormatBuilder`]. /// Any invalid number format will prevent parsing, returning /// the appropriate format error. If you are unsure which format /// to use, use [`STANDARD`]. /// /// [`NumberFormatBuilder`]: lexical_util::format::NumberFormatBuilder /// [`STANDARD`]: lexical_util::format::STANDARD fn from_lexical_partial_with_options( bytes: &[u8], options: &Self::Options, ) -> lexical_util::result::Result<(Self, usize)>; } }; } // TO LEXICAL /// Define `ToLexical` trait. #[macro_export] #[cfg(feature = "write")] macro_rules! to_lexical { () => { /// Trait for numerical types that can be serialized to bytes. /// /// To determine the number of bytes required to serialize a value to /// string, check the associated constants from a required trait: /// - [`FORMATTED_SIZE`] /// - [`FORMATTED_SIZE_DECIMAL`] /// /// [`FORMATTED_SIZE`]: lexical_util::constants::FormattedSize::FORMATTED_SIZE /// [`FORMATTED_SIZE_DECIMAL`]: lexical_util::constants::FormattedSize::FORMATTED_SIZE_DECIMAL pub trait ToLexical: lexical_util::constants::FormattedSize + lexical_util::num::Number { /// Serializer for a number-to-string conversion. /// /// Returns a subslice of the input buffer containing the written bytes, /// starting from the same address in memory as the input slice. /// /// * `value` - Number to serialize. /// * `bytes` - Buffer to write number to. /// /// # Panics /// /// Panics if the buffer is not of sufficient size. The caller /// must provide a slice of sufficient size. In order to ensure /// the function will not panic, ensure the buffer has at least /// [`FORMATTED_SIZE_DECIMAL`] elements. /// /// [`FORMATTED_SIZE_DECIMAL`]: lexical_util::constants::FormattedSize::FORMATTED_SIZE_DECIMAL fn to_lexical<'a>(self, bytes: &'a mut [u8]) -> &'a mut [u8]; } }; } /// Define `ToLexicalWithOptions` trait. #[macro_export] #[cfg(feature = "write")] macro_rules! to_lexical_with_options { () => { /// Trait for numerical types that can be serialized to bytes with custom /// options. /// /// To determine the number of bytes required to serialize a value to /// string, check the associated constants from a required trait: /// - [`FORMATTED_SIZE`] /// - [`FORMATTED_SIZE_DECIMAL`] /// /// The `Options` type specifies the configurable options to provide. /// /// [`FORMATTED_SIZE`]: lexical_util::constants::FormattedSize::FORMATTED_SIZE /// [`FORMATTED_SIZE_DECIMAL`]: lexical_util::constants::FormattedSize::FORMATTED_SIZE_DECIMAL pub trait ToLexicalWithOptions: lexical_util::constants::FormattedSize + lexical_util::num::Number { /// Custom formatting options for writing a number. type Options: lexical_util::options::WriteOptions; /// Serializer for a number-to-string conversion. /// /// Returns a subslice of the input buffer containing the written bytes, /// starting from the same address in memory as the input slice. /// /// * `FORMAT` - Flags and characters designating the number grammar. /// * `value` - Number to serialize. /// * `bytes` - Buffer to write number to. /// * `options` - Options for number formatting. /// /// # Panics /// /// Panics if the buffer is not of sufficient size. The caller /// must provide a slice of sufficient size. In order to ensure /// the function will not panic, ensure the buffer has at least /// [`FORMATTED_SIZE`] elements. If you are changing the /// number significant digits written, the exponent break points, /// or disabling scientific notation, you will need a larger buffer /// than the one provided. An upper limit on the buffer size can /// then be determined using [`WriteOptions::buffer_size`]. If you /// are not using `min_significant_digits`, 1200 bytes is always /// enough to hold the the output for a custom radix, and `400` /// is always enough for decimal strings. /// /// **Floats Only** /// /// These panics are only when using uncommon features for float /// writing, represent configuration errors, so runtime error /// handling is not provided. /// /// Also panics if the provided number format is invalid, or /// if the mantissa radix is not equal to the exponent base /// and the mantissa radix/exponent base combinations are /// not in the following list: /// /// - `4, 2` /// - `8, 2` /// - `16, 2` /// - `32, 2` /// - `16, 4` /// /// Panics as well if the NaN or Inf string provided to the writer /// is disabled, but the value provided is NaN or Inf, respectively. /// /// [`WriteOptions::buffer_size`]: lexical_util::options::WriteOptions::buffer_size /// [`FORMATTED_SIZE`]: lexical_util::constants::FormattedSize::FORMATTED_SIZE fn to_lexical_with_options<'a, const FORMAT: u128>( self, bytes: &'a mut [u8], options: &Self::Options, ) -> &'a mut [u8]; } }; } lexical-util-1.0.6/src/ascii.rs000064400000000000000000000027001046102023000144500ustar 00000000000000//! Utilities for working with ASCII characters. /// Determine if a character is a valid ASCII character for float grammar. pub const fn is_valid_ascii(c: u8) -> bool { // Below 0x20 is mostly control characters, with no representation. // 0x7F is a control character, DEL, so don't include it. // We also want the few visual characters below 0x20: // 0x09 - Horizontal Tab // 0x0A - Newline // 0x0B - Vertical Tab (Deprecated) // 0x0C - Form Feed (Deprecated) // 0x0D - Carriage Return (c >= 0x09 && c <= 0x0d) || (c >= 0x20 && c < 0x7F) } /// Determine if a slice is all valid ASCII characters for float grammar. /// Modified to be used in a const fn, since for loops and iter don't work. pub const fn is_valid_ascii_slice(slc: &[u8]) -> bool { let mut index = 0; while index < slc.len() { if !is_valid_ascii(slc[index]) { return false; } index += 1; } true } /// Determine if a character is a valid ASCII letter. pub const fn is_valid_letter(c: u8) -> bool { (c >= 0x41 && c <= 0x5a) || (c >= 0x61 && c <= 0x7a) } /// Determine if a slice is all valid ASCII letters. /// Modified to be used in a const fn, since for loops and iter don't work. pub const fn is_valid_letter_slice(slc: &[u8]) -> bool { let mut index = 0; while index < slc.len() { if !is_valid_letter(slc[index]) { return false; } index += 1; } true } lexical-util-1.0.6/src/assert.rs000064400000000000000000000030361046102023000146640ustar 00000000000000//! Debugging assertions to check a radix is valid. #[cfg(feature = "write")] use crate::constants::FormattedSize; // RADIX /// Check radix is in range `[2, 36]` in debug builds. #[inline(always)] #[cfg(feature = "radix")] pub fn debug_assert_radix(radix: u32) { debug_assert!((2..=36).contains(&radix), "Numerical base must be from 2-36."); } /// Check radix is is 10 or a power of 2. #[inline(always)] #[cfg(all(feature = "power-of-two", not(feature = "radix")))] pub fn debug_assert_radix(radix: u32) { debug_assert!(matches!(radix, 2 | 4 | 8 | 10 | 16 | 32), "Numerical base must be from 2-36."); } /// Check radix is equal to 10. #[inline(always)] #[cfg(not(feature = "power-of-two"))] pub fn debug_assert_radix(radix: u32) { debug_assert!(radix == 10, "Numerical base must be 10."); } // BUFFER /// Assertion the buffer has sufficient room for the output. #[inline(always)] #[cfg(all(feature = "power-of-two", feature = "write"))] pub fn assert_buffer(radix: u32, len: usize) { assert!( match radix { 10 => len >= T::FORMATTED_SIZE_DECIMAL, _ => len >= T::FORMATTED_SIZE, }, "Buffer is too small: may overwrite buffer, panicking!" ); } /// Assertion the buffer has sufficient room for the output. #[inline(always)] #[cfg(all(not(feature = "power-of-two"), feature = "write"))] pub fn assert_buffer(_: u32, len: usize) { assert!( len >= T::FORMATTED_SIZE_DECIMAL, "Buffer is too small: may overwrite buffer, panicking!" ); } lexical-util-1.0.6/src/bf16.rs000064400000000000000000000747421046102023000141350ustar 00000000000000//! Brain Floating Point implementation, a 16-bit type used in machine learning. //! //! bf16 is meant as an interchange format, and therefore there may be //! rounding error in using it for fast-path algorithms. Since there //! are no native operations using `bf16`, this is of minimal concern. //! //! Most of this code has been implemented from [`half`], to enable simple //! conversions to and from f32. This is provided as standalone code //! to avoid any external dependencies and avoid the serialization logic //! for serde, etc. //! //! There is no unsafety in this module other than a manual implementation //! of sync/send for a primitive type. //! //! The documentation and implementation for other parts of this code is //! derived from the Rust standard library, as is some of the more complex //! functionality. //! //! [`half`] is dual licensed under an Apache 2.0 and MIT license. //! //! [`half`]: https://github.com/starkat99/half-rs #![cfg(feature = "f16")] #![doc(hidden)] use core::cmp::Ordering; use core::iter::{Product, Sum}; use core::num::FpCategory; use core::ops::*; use core::{fmt, mem, num, str}; use crate::num::Float; use crate::numtypes::*; /// Brain floating point type. /// /// This has the same representation as [`bf16`] from [`half`], and /// is guaranteed to be supported as a `u16` to/from C. /// /// [`bf16`]: https://docs.rs/half/latest/half/struct.bf16.html /// [`half`]: https://docs.rs/half/latest/half/ #[repr(C)] #[allow(non_camel_case_types)] #[derive(Default, Copy, Clone)] pub struct bf16(u16); // # SAFETY: bf16 is a trivial type internally represented by u16. unsafe impl Send for bf16 { } // # SAFETY: bf16 is a trivial type internally represented by u16. unsafe impl Sync for bf16 { } impl bf16 { /// The radix or base of the internal representation of `bf16`. pub const RADIX: u32 = 2; /// Number of significant digits in base 2. pub const MANTISSA_DIGITS: u32 = ::MANTISSA_SIZE as u32 + 1; /// Approximate number of significant digits in base 10. /// /// This is the maximum x such that any decimal number with x /// significant digits can be converted to `bf16` and back without loss. /// /// Equal to floor(log10 2[`MANTISSA_DIGITS`] & /// minus; 1). /// /// [`MANTISSA_DIGITS`]: bf16::MANTISSA_DIGITS pub const DIGITS: u32 = 2; /// [Machine epsilon] value for `bf16`. /// /// This is the difference between `1.0` and the next larger representable /// number. /// /// Equal to 21 − [`MANTISSA_DIGITS`]. /// /// [Machine epsilon]: https://en.wikipedia.org/wiki/Machine_epsilon /// [`MANTISSA_DIGITS`]: bf16::MANTISSA_DIGITS pub const EPSILON: Self = bf16(0x3C00u16); /// Smallest finite `bf16` value. /// /// Equal to −[`MAX`]. /// /// [`MAX`]: bf16::MAX pub const MIN: Self = ::MIN; /// Smallest positive normal `bf16` value. /// /// Equal to 2[`MIN_EXP`] − 1. /// /// [`MIN_EXP`]: bf16::MIN_EXP pub const MIN_POSITIVE: Self = Self(0x0080u16); /// Largest finite `bf16` value. /// /// Equal to /// (1 − 2−[`MANTISSA_DIGITS`])  /// 2[`MAX_EXP`]. /// /// [`MANTISSA_DIGITS`]: bf16::MANTISSA_DIGITS /// [`MAX_EXP`]: bf16::MAX_EXP pub const MAX: Self = ::MAX; /// Maximum possible power of 2 exponent. /// /// If x = `MAX_EXP`, then normal numbers /// < 1 × 2x. pub const MAX_EXP: i32 = Self::MAX_EXPONENT + Self::MANTISSA_SIZE; /// One greater than the minimum possible normal power of 2 exponent. /// /// If x = `MIN_EXP`, then normal numbers /// ≥ 0.5 × 2x. // NOTE: This is -MAX_EXP + 3 pub const MIN_EXP: i32 = -Self::MAX_EXP + 3; /// Minimum x for which 10x is normal. /// /// Equal to ceil(log10 [`MIN_POSITIVE`]). /// /// [`MIN_POSITIVE`]: bf16::MIN_POSITIVE pub const MIN_10_EXP: i32 = -37; /// Maximum x for which 10x is normal. /// /// Equal to floor(log10 [`MAX`]). /// /// [`MAX`]: bf16::MAX pub const MAX_10_EXP: i32 = 38; /// Not a Number (NaN). /// /// Note that IEEE 754 doesn't define just a single NaN value; /// a plethora of bit patterns are considered to be NaN. /// Furthermore, the standard makes a difference /// between a "signaling" and a "quiet" NaN, /// and allows inspecting its "payload" (the unspecified bits in the bit /// pattern). This constant isn't guaranteed to equal to any specific /// NaN bitpattern, and the stability of its representation over Rust /// versions and target platforms isn't guaranteed. pub const NAN: Self = ::NAN; /// Infinity (∞). pub const INFINITY: Self = ::INFINITY; /// Negative infinity (−∞). pub const NEG_INFINITY: Self = ::NEG_INFINITY; /// Sign bit pub const SIGN_MASK: u16 = ::SIGN_MASK; /// Exponent mask pub const EXP_MASK: u16 = ::EXPONENT_MASK; /// Mantissa mask pub const MAN_MASK: u16 = ::MANTISSA_MASK; /// Minimum representable positive value (min subnormal) pub const TINY_BITS: u16 = 0x1; /// Minimum representable negative value (min negative subnormal) pub const NEG_TINY_BITS: u16 = Self::TINY_BITS | Self::SIGN_MASK; /// Returns `true` if this value is NaN. #[must_use] #[inline(always)] pub const fn is_nan(self) -> bool { let bits = self.to_bits(); let is_special = bits & Self::EXPONENT_MASK == Self::EXPONENT_MASK; is_special && (bits & Self::MANTISSA_MASK) != 0 } /// Computes the absolute value of `self`. #[must_use] #[inline(always)] pub const fn abs(self) -> Self { Self(self.0 & !Self::SIGN_MASK) } /// Returns `true` if this value is positive infinity or negative infinity, /// and `false` otherwise. #[must_use] #[inline(always)] pub const fn is_infinite(self) -> bool { eq(self, Self::INFINITY) | eq(self, Self::NEG_INFINITY) } /// Returns `true` if this number is neither infinite nor NaN. #[must_use] #[inline(always)] pub const fn is_finite(self) -> bool { self.to_bits() & Self::EXPONENT_MASK != Self::EXPONENT_MASK } /// Returns `true` if the number is [subnormal]. /// /// [subnormal]: https://en.wikipedia.org/wiki/Denormal_number #[must_use] #[inline(always)] pub const fn is_subnormal(self) -> bool { matches!(self.classify(), FpCategory::Subnormal) } /// Returns `true` if the number is neither zero, infinite, /// [subnormal], or NaN. /// /// [subnormal]: https://en.wikipedia.org/wiki/Denormal_number #[must_use] #[inline(always)] pub const fn is_normal(self) -> bool { matches!(self.classify(), FpCategory::Normal) } /// Returns the floating point category of the number. If only one property /// is going to be tested, it is generally faster to use the specific /// predicate instead. #[inline(always)] pub const fn classify(self) -> FpCategory { let b = self.to_bits(); match (b & Self::MAN_MASK, b & Self::EXP_MASK) { (0, Self::EXP_MASK) => FpCategory::Infinite, (_, Self::EXP_MASK) => FpCategory::Nan, (0, 0) => FpCategory::Zero, (_, 0) => FpCategory::Subnormal, _ => FpCategory::Normal, } } /// Returns `true` if `self` has a positive sign, including `+0.0`, NaNs /// with positive sign bit and positive infinity. /// /// Note that IEEE 754 doesn't assign any meaning to the sign bit in case of /// a NaN, and as Rust doesn't guarantee that the bit pattern of NaNs are /// conserved over arithmetic operations, the result of `is_sign_positive` /// on a NaN might produce an unexpected or non-portable result. See the /// [specification of NaN bit patterns](f32#nan-bit-patterns) for more /// info. Use `self.signum() == 1.0` if you need fully portable behavior /// (will return `false` for all NaNs). #[inline(always)] pub const fn is_sign_positive(self) -> bool { self.to_bits() & Self::SIGN_MASK == 0 } /// Returns `true` if `self` has a negative sign, including `-0.0`, NaNs /// with negative sign bit and negative infinity. /// /// Note that IEEE 754 doesn't assign any meaning to the sign bit in case of /// a NaN, and as Rust doesn't guarantee that the bit pattern of NaNs are /// conserved over arithmetic operations, the result of `is_sign_negative` /// on a NaN might produce an unexpected or non-portable result. See the /// [specification of NaN bit patterns](f32#nan-bit-patterns) for more /// info. Use `self.signum() == -1.0` if you need fully portable /// behavior (will return `false` for all NaNs). #[inline(always)] pub const fn is_sign_negative(self) -> bool { !self.is_sign_positive() } /// Takes the reciprocal (inverse) of a number, `1/x`. #[must_use] #[inline(always)] pub fn recip(self) -> Self { Self::ONE / self } /// Converts radians to degrees. #[must_use] #[inline(always)] pub fn to_degrees(self) -> Self { self * Self::from_u16(180) / Self::PI } /// Converts degrees to radians. #[must_use] #[inline(always)] pub fn to_radians(self) -> Self { self * Self::PI / Self::from_u16(180) } /// Returns the maximum of the two numbers, ignoring NaN. /// /// If one of the arguments is NaN, then the other argument is returned. #[must_use] #[inline(always)] pub fn max(self, other: Self) -> Self { if other > self && !other.is_nan() { other } else { self } } /// Returns the minimum of the two numbers. /// /// If one of the arguments is NaN, then the other argument is returned. #[must_use] #[inline(always)] pub fn min(self, other: Self) -> Self { if other < self && !other.is_nan() { other } else { self } } /// Raw transmutation to `u16`. /// /// This is currently identical to `transmute::(self)` on all /// platforms. /// /// See [`from_bits`](Self::from_bits) for some discussion of the /// portability of this operation (there are almost no issues). /// /// Note that this function is distinct from `as` casting, which attempts to /// preserve the *numeric* value, and not the bitwise value. #[must_use] #[inline(always)] pub const fn to_bits(self) -> u16 { self.0 } /// Raw transmutation from `u16`. /// /// This is currently identical to `transmute::(v)` on all /// platforms. It turns out this is incredibly portable, for two /// reasons: /// /// * Floats and Ints have the same endianness on all supported platforms. /// * IEEE 754 very precisely specifies the bit layout of floats. /// /// However there is one caveat: prior to the 2008 version of IEEE 754, how /// to interpret the NaN signaling bit wasn't actually specified. Most /// platforms (notably x86 and ARM) picked the interpretation that was /// ultimately standardized in 2008, but some didn't (notably MIPS). As /// a result, all signaling NaNs on MIPS are quiet NaNs on x86, and /// vice-versa. /// /// Rather than trying to preserve signaling-ness cross-platform, this /// implementation favors preserving the exact bits. This means that /// any payloads encoded in NaNs will be preserved even if the result of /// this method is sent over the network from an x86 machine to a MIPS one. /// /// If the results of this method are only manipulated by the same /// architecture that produced them, then there is no portability concern. /// /// If the input isn't NaN, then there is no portability concern. /// /// If you don't care about signalingness (very likely), then there is no /// portability concern. /// /// Note that this function is distinct from `as` casting, which attempts to /// preserve the *numeric* value, and not the bitwise value. #[must_use] #[inline(always)] pub const fn from_bits(bits: u16) -> Self { Self(bits) } /// Returns the memory representation of this floating point number as a /// byte array in big-endian (network) byte order. /// /// See [`from_bits`](Self::from_bits) for some discussion of the /// portability of this operation (there are almost no issues). #[must_use] #[inline(always)] pub const fn to_be_bytes(self) -> [u8; 2] { self.to_bits().to_be_bytes() } /// Returns the memory representation of this floating point number as a /// byte array in little-endian byte order. /// /// See [`from_bits`](Self::from_bits) for some discussion of the /// portability of this operation (there are almost no issues). #[must_use] #[inline(always)] pub const fn to_le_bytes(self) -> [u8; 2] { self.to_bits().to_le_bytes() } /// Returns the memory representation of this floating point number as a /// byte array in native byte order. /// /// As the target platform's native endianness is used, portable code /// should use [`to_be_bytes`] or [`to_le_bytes`], as appropriate, instead. /// /// [`to_be_bytes`]: Self::to_be_bytes /// [`to_le_bytes`]: Self::to_le_bytes /// /// See [`from_bits`](Self::from_bits) for some discussion of the #[must_use] #[inline(always)] pub const fn to_ne_bytes(self) -> [u8; 2] { self.to_bits().to_ne_bytes() } /// Creates a floating point value from its representation as a byte array /// in big endian. /// /// See [`from_bits`](Self::from_bits) for some discussion of the /// portability of this operation (there are almost no issues). #[must_use] #[inline(always)] pub const fn from_be_bytes(bytes: [u8; 2]) -> Self { Self::from_bits(u16::from_be_bytes(bytes)) } /// Creates a floating point value from its representation as a byte array /// in little endian. /// /// See [`from_bits`](Self::from_bits) for some discussion of the /// portability of this operation (there are almost no issues). #[must_use] #[inline(always)] pub const fn from_le_bytes(bytes: [u8; 2]) -> Self { Self::from_bits(u16::from_le_bytes(bytes)) } /// Creates a floating point value from its representation as a byte array /// in native endian. /// /// As the target platform's native endianness is used, portable code /// likely wants to use [`from_be_bytes`] or [`from_le_bytes`], as /// appropriate instead. /// /// [`from_be_bytes`]: Self::from_be_bytes /// [`from_le_bytes`]: Self::from_le_bytes /// /// See [`from_bits`](Self::from_bits) for some discussion of the /// portability of this operation (there are almost no issues). #[must_use] #[inline(always)] pub const fn from_ne_bytes(bytes: [u8; 2]) -> Self { Self::from_bits(u16::from_ne_bytes(bytes)) } /// Returns the ordering between `self` and `other`. /// /// Unlike the standard partial comparison between floating point numbers, /// this comparison always produces an ordering in accordance to /// the `totalOrder` predicate as defined in the IEEE 754 (2008 revision) /// floating point standard. The values are ordered in the following /// sequence: /// /// - negative quiet NaN /// - negative signaling NaN /// - negative infinity /// - negative numbers /// - negative subnormal numbers /// - negative zero /// - positive zero /// - positive subnormal numbers /// - positive numbers /// - positive infinity /// - positive signaling NaN /// - positive quiet NaN. /// /// The ordering established by this function does not always agree with the /// [`PartialOrd`] and [`PartialEq`] implementations of `bf16`. For example, /// they consider negative and positive zero equal, while `total_cmp` /// doesn't. /// /// The interpretation of the signaling NaN bit follows the definition in /// the IEEE 754 standard, which may not match the interpretation by some of /// the older, non-conformant (e.g. MIPS) hardware implementations. /// /// # Examples /// ``` /// # use half::bf16; /// let mut v: Vec = vec![]; /// v.push(bf16::ONE); /// v.push(bf16::INFINITY); /// v.push(bf16::NEG_INFINITY); /// v.push(bf16::NAN); /// v.push(bf16::MAX_SUBNORMAL); /// v.push(-bf16::MAX_SUBNORMAL); /// v.push(bf16::ZERO); /// v.push(bf16::NEG_ZERO); /// v.push(bf16::NEG_ONE); /// v.push(bf16::MIN_POSITIVE); /// /// v.sort_by(|a, b| a.total_cmp(&b)); /// /// assert!(v /// .into_iter() /// .zip( /// [ /// bf16::NEG_INFINITY, /// bf16::NEG_ONE, /// -bf16::MAX_SUBNORMAL, /// bf16::NEG_ZERO, /// bf16::ZERO, /// bf16::MAX_SUBNORMAL, /// bf16::MIN_POSITIVE, /// bf16::ONE, /// bf16::INFINITY, /// bf16::NAN /// ] /// .iter() /// ) /// .all(|(a, b)| a.to_bits() == b.to_bits())); /// ``` // Implementation based on: https://doc.rust-lang.org/std/primitive.f32.html#method.total_cmp #[must_use] #[inline(always)] pub fn total_cmp(&self, other: &Self) -> Ordering { let mut left = self.to_bits() as i16; let mut right = other.to_bits() as i16; left ^= (((left >> 15) as u16) >> 1) as i16; right ^= (((right >> 15) as u16) >> 1) as i16; left.cmp(&right) } /// Restrict a value to a certain interval unless it is NaN. /// /// Returns `max` if `self` is greater than `max`, and `min` if `self` is /// less than `min`. Otherwise this returns `self`. /// /// Note that this function returns NaN if the initial value was NaN as /// well. /// /// # Panics /// Panics if `min > max`, `min` is NaN, or `max` is NaN. /// /// # Examples /// /// ``` /// # use half::prelude::*; /// assert!(bf16::from_f32(-3.0).clamp(bf16::from_f32(-2.0), bf16::from_f32(1.0)) == bf16::from_f32(-2.0)); /// assert!(bf16::from_f32(0.0).clamp(bf16::from_f32(-2.0), bf16::from_f32(1.0)) == bf16::from_f32(0.0)); /// assert!(bf16::from_f32(2.0).clamp(bf16::from_f32(-2.0), bf16::from_f32(1.0)) == bf16::from_f32(1.0)); /// assert!(bf16::NAN.clamp(bf16::from_f32(-2.0), bf16::from_f32(1.0)).is_nan()); /// ``` #[must_use] #[inline(always)] pub fn clamp(self, min: bf16, max: bf16) -> bf16 { assert!(min <= max); let mut x = self; if x < min { x = min; } if x > max { x = max; } x } } macro_rules! from_int_impl { ($t:ty, $func:ident) => { /// Create from the integral type, as if by an `as` cast. #[inline(always)] pub const fn $func(value: $t) -> Self { Self::from_f32(value as f32) } }; } // Non-standard extensions to simplify working with `f16`. impl bf16 { /// [`bf16`] 1 pub const ONE: bf16 = bf16(0x3F80u16); /// [`bf16`] 0 pub const ZERO: bf16 = bf16(0x0000u16); /// [`bf16`] -0 pub const NEG_ZERO: bf16 = bf16(0x8000u16); /// [`bf16`] -1 pub const NEG_ONE: bf16 = bf16(0xBF80u16); /// [`bf16`] Euler's number (ℯ) pub const E: bf16 = bf16(0x402Eu16); /// [`bf16`] Archimedes' constant (π) pub const PI: bf16 = bf16(0x4049u16); /// [`bf16`] 1/π pub const FRAC_1_PI: bf16 = bf16(0x3EA3u16); /// [`bf16`] 1/√2 pub const FRAC_1_SQRT_2: bf16 = bf16(0x3F35u16); /// [`bf16`] 2/π pub const FRAC_2_PI: bf16 = bf16(0x3F23u16); /// [`bf16`] 2/√π pub const FRAC_2_SQRT_PI: bf16 = bf16(0x3F90u16); /// [`bf16`] π/2 pub const FRAC_PI_2: bf16 = bf16(0x3FC9u16); /// [`bf16`] π/3 pub const FRAC_PI_3: bf16 = bf16(0x3F86u16); /// [`bf16`] π/4 pub const FRAC_PI_4: bf16 = bf16(0x3F49u16); /// [`bf16`] π/6 pub const FRAC_PI_6: bf16 = bf16(0x3F06u16); /// [`bf16`] π/8 pub const FRAC_PI_8: bf16 = bf16(0x3EC9u16); /// [`bf16`] 𝗅𝗇 10 pub const LN_10: bf16 = bf16(0x4013u16); /// [`bf16`] 𝗅𝗇 2 pub const LN_2: bf16 = bf16(0x3F31u16); /// [`bf16`] 𝗅𝗈𝗀₁₀ℯ pub const LOG10_E: bf16 = bf16(0x3EDEu16); /// [`bf16`] 𝗅𝗈𝗀₁₀2 pub const LOG10_2: bf16 = bf16(0x3E9Au16); /// [`bf16`] 𝗅𝗈𝗀₂ℯ pub const LOG2_E: bf16 = bf16(0x3FB9u16); /// [`bf16`] 𝗅𝗈𝗀₂10 pub const LOG2_10: bf16 = bf16(0x4055u16); /// [`bf16`] √2 pub const SQRT_2: bf16 = bf16(0x3FB5u16); #[inline(always)] pub const fn as_f32(self) -> f32 { // This is super easy, since we have the same exponent bits: // just need to shift left 16. f32_from_bits((self.0 as u32) << 16) } #[inline(always)] pub const fn from_f32(value: f32) -> Self { // Same number of exponent bits, less mantissa bits: simple conversion. // We want to round to the nearest float, so we'll check if it's odd // and above or equal to halfway. This also properly handled inf, denormal, // and NaN cases, since they're effectively the same. let bits = f32_to_bits(value); let truncated = bits as u16; let bf16_bits = (bits >> 16) as u16; let halfway = 1u16 << 15; let is_odd = bf16_bits % 2 == 1; let is_halfway = truncated == halfway; let is_above = truncated > halfway; let round_up = is_above || (is_halfway && is_odd); Self::from_bits(bf16_bits + round_up as u16) } from_int_impl!(u8, from_u8); from_int_impl!(u16, from_u16); from_int_impl!(u32, from_u32); from_int_impl!(u64, from_u64); from_int_impl!(u128, from_u128); from_int_impl!(i8, from_i8); from_int_impl!(i16, from_i16); from_int_impl!(i32, from_i32); from_int_impl!(i64, from_i64); from_int_impl!(i128, from_i128); from_int_impl!(f64, from_f64); } impl PartialEq for bf16 { #[inline(always)] fn eq(&self, other: &Self) -> bool { eq(*self, *other) } } impl PartialOrd for bf16 { #[inline(always)] fn partial_cmp(&self, other: &Self) -> Option { partial_cmp(*self, *other) } #[inline(always)] fn lt(&self, other: &bf16) -> bool { lt(*self, *other) } #[inline(always)] fn le(&self, other: &bf16) -> bool { le(*self, *other) } #[inline(always)] fn gt(&self, other: &bf16) -> bool { gt(*self, *other) } #[inline(always)] fn ge(&self, other: &bf16) -> bool { ge(*self, *other) } } impl Add for bf16 { type Output = Self; #[inline(always)] fn add(self, rhs: Self) -> Self::Output { Self::from_f32(self.as_f32() + rhs.as_f32()) } } op_impl!(bf16, Add, AddAssign, add, add_assign); impl Div for bf16 { type Output = Self; #[inline(always)] fn div(self, rhs: Self) -> Self::Output { Self::from_f32(self.as_f32() / rhs.as_f32()) } } op_impl!(bf16, Div, DivAssign, div, div_assign); impl Mul for bf16 { type Output = Self; #[inline(always)] fn mul(self, rhs: Self) -> Self::Output { Self::from_f32(self.as_f32() * rhs.as_f32()) } } op_impl!(bf16, Mul, MulAssign, mul, mul_assign); impl Sub for bf16 { type Output = Self; #[inline(always)] fn sub(self, rhs: Self) -> Self::Output { Self::from_f32(self.as_f32() - rhs.as_f32()) } } op_impl!(bf16, Sub, SubAssign, sub, sub_assign); impl Rem for bf16 { type Output = Self; #[inline(always)] fn rem(self, rhs: Self) -> Self::Output { Self::from_f32(self.as_f32() % rhs.as_f32()) } } op_impl!(bf16, Rem, RemAssign, rem, rem_assign); impl Neg for bf16 { type Output = Self; #[inline(always)] fn neg(self) -> Self::Output { Self::from_bits(self.0 ^ (1 << 15)) } } ref_impl!(bf16, Neg, neg); // NOTE: This is not optimized, and is optimized in `lexical`. impl str::FromStr for bf16 { type Err = num::ParseFloatError; fn from_str(src: &str) -> Result { f32::from_str(src).map(bf16::from_f32) } } impl fmt::Debug for bf16 { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> { fmt::Debug::fmt(&self.as_f32(), f) } } impl fmt::Display for bf16 { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> { fmt::Display::fmt(&self.as_f32(), f) } } impl fmt::LowerExp for bf16 { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> { write!(f, "{:e}", self.as_f32()) } } impl fmt::UpperExp for bf16 { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> { write!(f, "{:E}", self.as_f32()) } } impl fmt::Binary for bf16 { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> { write!(f, "{:b}", self.0) } } impl fmt::Octal for bf16 { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> { write!(f, "{:o}", self.0) } } impl fmt::LowerHex for bf16 { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> { write!(f, "{:x}", self.0) } } impl fmt::UpperHex for bf16 { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> { write!(f, "{:X}", self.0) } } impl Product for bf16 { #[inline(always)] fn product>(iter: I) -> Self { product_bf16(iter.map(|f| f.to_bits())) } } impl<'a> Product<&'a bf16> for bf16 { #[inline] fn product>(iter: I) -> Self { product_bf16(iter.map(|f| f.to_bits())) } } impl Sum for bf16 { #[inline] fn sum>(iter: I) -> Self { sum_bf16(iter.map(|f| f.to_bits())) } } impl<'a> Sum<&'a bf16> for bf16 { #[inline] fn sum>(iter: I) -> Self { sum_bf16(iter.map(|f| f.to_bits())) } } from_impl!(bf16, u8, from_u8); from_impl!(bf16, u16, from_u16); from_impl!(bf16, u32, from_u32); from_impl!(bf16, u64, from_u64); from_impl!(bf16, u128, from_u128); from_impl!(bf16, i8, from_i8); from_impl!(bf16, i16, from_i16); from_impl!(bf16, i32, from_i32); from_impl!(bf16, i64, from_i64); from_impl!(bf16, i128, from_i128); from_impl!(bf16, f64, from_f64); // Private functions for const expr. #[must_use] #[inline(always)] const fn eq(lhs: bf16, rhs: bf16) -> bool { // NOTE: This optimizes identically at opt levels 1+ to asm // https://godbolt.org/z/bW7s7o5M6 if lhs.is_nan() { false } else if lhs.to_bits() & !bf16::SIGN_MASK == 0 { rhs.to_bits() & !bf16::SIGN_MASK == 0 } else { lhs.to_bits() == rhs.to_bits() } } #[must_use] #[inline(always)] fn partial_cmp(lhs: bf16, rhs: bf16) -> Option { if lhs.is_nan() || rhs.is_nan() { None } else { let neg = lhs.0 & 0x8000u16 != 0; let rhs_neg = rhs.0 & 0x8000u16 != 0; match (neg, rhs_neg) { (false, false) => Some(lhs.0.cmp(&rhs.0)), (false, true) => { if (lhs.0 | rhs.0) & 0x7FFFu16 == 0 { Some(Ordering::Equal) } else { Some(Ordering::Greater) } }, (true, false) => { if (lhs.0 | rhs.0) & 0x7FFFu16 == 0 { Some(Ordering::Equal) } else { Some(Ordering::Less) } }, (true, true) => Some(rhs.0.cmp(&lhs.0)), } } } #[must_use] #[inline(always)] const fn lt(lhs: bf16, rhs: bf16) -> bool { if lhs.is_nan() || rhs.is_nan() { false } else { let neg = lhs.0 & 0x8000u16 != 0; let rhs_neg = rhs.0 & 0x8000u16 != 0; match (neg, rhs_neg) { (false, false) => lhs.0 < rhs.0, (false, true) => false, (true, false) => (lhs.0 | rhs.0) & 0x7FFFu16 != 0, (true, true) => lhs.0 > rhs.0, } } } #[must_use] #[inline(always)] const fn le(lhs: bf16, rhs: bf16) -> bool { if lhs.is_nan() || rhs.is_nan() { false } else { let neg = lhs.0 & 0x8000u16 != 0; let rhs_neg = rhs.0 & 0x8000u16 != 0; match (neg, rhs_neg) { (false, false) => lhs.0 <= rhs.0, (false, true) => (lhs.0 | rhs.0) & 0x7FFFu16 == 0, (true, false) => true, (true, true) => lhs.0 >= rhs.0, } } } #[must_use] #[inline(always)] const fn gt(lhs: bf16, rhs: bf16) -> bool { if lhs.is_nan() || rhs.is_nan() { false } else { let neg = lhs.0 & 0x8000u16 != 0; let rhs_neg = rhs.0 & 0x8000u16 != 0; match (neg, rhs_neg) { (false, false) => lhs.0 > rhs.0, (false, true) => (lhs.0 | rhs.0) & 0x7FFFu16 != 0, (true, false) => false, (true, true) => lhs.0 < rhs.0, } } } #[must_use] #[inline(always)] const fn ge(lhs: bf16, rhs: bf16) -> bool { if lhs.is_nan() || rhs.is_nan() { false } else { let neg = lhs.0 & 0x8000u16 != 0; let rhs_neg = rhs.0 & 0x8000u16 != 0; match (neg, rhs_neg) { (false, false) => lhs.0 >= rhs.0, (false, true) => true, (true, false) => (lhs.0 | rhs.0) & 0x7FFFu16 == 0, (true, true) => lhs.0 <= rhs.0, } } } // NOTE: taken from the core implementation. #[must_use] #[inline(always)] const fn f32_from_bits(v: u32) -> f32 { // SAFETY: The type is POD unsafe { mem::transmute(v) } } #[must_use] #[inline(always)] const fn f32_to_bits(v: f32) -> u32 { // SAFETY: The type is POD unsafe { mem::transmute(v) } } #[must_use] #[inline(always)] const fn u16_to_f32(v: u16) -> f32 { bf16(v).as_f32() } #[must_use] #[inline(always)] fn product_bf16>(iter: I) -> bf16 { bf16::from_f32(iter.map(u16_to_f32).product()) } #[must_use] #[inline(always)] fn sum_bf16>(iter: I) -> bf16 { bf16::from_f32(iter.map(u16_to_f32).sum()) } lexical-util-1.0.6/src/constants.rs000064400000000000000000000072471046102023000154070ustar 00000000000000//! Pre-defined constants for numeric types. #![cfg(feature = "write")] #[cfg(feature = "f16")] use crate::bf16::bf16; #[cfg(feature = "f16")] use crate::f16::f16; /// The size, in bytes, of formatted values. pub trait FormattedSize { /// Maximum number of bytes required to serialize a number to string. /// /// Note that this value may be insufficient if digit precision control, /// exponent break points, or disabling exponent notation is used. If /// you are changing the number significant digits written, the exponent /// break points, or disabling scientific notation, you will need a larger /// buffer than the one provided. An upper limit on the buffer size can /// then be determined using [`WriteOptions::buffer_size`]. /// /// [`WriteOptions::buffer_size`]: crate::options::WriteOptions::buffer_size /// [`lexical_write_float`]: https://github.com/Alexhuszagh/rust-lexical/tree/main/lexical-write-float const FORMATTED_SIZE: usize; /// Maximum number of bytes required to serialize a number to a decimal /// string. /// /// Note that this value may be insufficient if digit precision control, /// exponent break points, or disabling exponent notation is used. If /// you are changing the number significant digits written, the exponent /// break points, or disabling scientific notation, you will need a larger /// buffer than the one provided. An upper limit on the buffer size can /// then be determined using [`WriteOptions::buffer_size`]. /// /// [`WriteOptions::buffer_size`]: crate::options::WriteOptions::buffer_size /// [`lexical_write_float`]: https://github.com/Alexhuszagh/rust-lexical/tree/main/lexical-write-float const FORMATTED_SIZE_DECIMAL: usize; } macro_rules! formatted_size_impl { ($($t:tt $decimal:literal $radix:literal ; )*) => ($( impl FormattedSize for $t { #[cfg(feature = "power-of-two")] const FORMATTED_SIZE: usize = $radix; #[cfg(not(feature = "power-of-two"))] const FORMATTED_SIZE: usize = $decimal; const FORMATTED_SIZE_DECIMAL: usize = $decimal; } )*); } formatted_size_impl! { i8 4 16 ; i16 6 32 ; i32 11 64 ; i64 20 128 ; i128 40 256 ; u8 3 16 ; u16 5 32 ; u32 10 64 ; u64 20 128 ; u128 39 256 ; // The f64 buffer is actually a size of 60, but use 64 since it's a power of 2. // Use 256 for non-decimal values, actually, since we seem to have memory // issues with f64. Clearly not sufficient memory allocated for non-decimal // values. //bf16 64 256 ; //f16 64 256 ; f32 64 256 ; f64 64 256 ; //f128 128 512 ; //f256 256 1024 ; } #[cfg(feature = "f16")] formatted_size_impl! { f16 64 256 ; bf16 64 256 ; } #[cfg(target_pointer_width = "16")] formatted_size_impl! { isize 6 32 ; } #[cfg(target_pointer_width = "16")] formatted_size_impl! { usize 5 32 ; } #[cfg(target_pointer_width = "32")] formatted_size_impl! { isize 11 64 ; } #[cfg(target_pointer_width = "32")] formatted_size_impl! { usize 10 64 ; } #[cfg(target_pointer_width = "64")] formatted_size_impl! { isize 20 128 ; } #[cfg(target_pointer_width = "64")] formatted_size_impl! { usize 20 128 ; } /// Maximum number of bytes required to serialize any number to string. /// /// Note that this value may be insufficient if digit precision control, /// exponent break points, or disabling exponent notation is used. /// Please read the documentation in [`lexical_write_float`] for more /// information. /// /// [`lexical_write_float`]: https://github.com/Alexhuszagh/rust-lexical/tree/main/lexical-write-float pub const BUFFER_SIZE: usize = f64::FORMATTED_SIZE; lexical-util-1.0.6/src/digit.rs000064400000000000000000000067621046102023000144740ustar 00000000000000//! Utilities to process digits. //! //! This both contains routines to convert to and from digits, //! as well as iterate over digits while skipping digit separators. // CONST FNS // --------- // These are optimized functions for when the radix is known at compile-time, // which is **most** of our cases. There are cases where for code generation, // using a runtime algorithm is preferable. /// Unchecked, highly optimized algorithm to convert a char to a digit. /// This only works if the input character is known to be a valid digit. #[inline(always)] pub const fn char_to_valid_digit_const(c: u8, radix: u32) -> u32 { if radix <= 10 { // Optimize for small radixes. (c.wrapping_sub(b'0')) as u32 } else { // Fallback, still decently fast. let digit = match c { b'0'..=b'9' => c - b'0', b'A'..=b'Z' => c - b'A' + 10, b'a'..=b'z' => c - b'a' + 10, _ => 0xFF, }; digit as u32 } } /// Convert a character to a digit with a radix known at compile time. /// /// This optimizes for cases where radix is <= 10, and uses a decent, /// match-based fallback algorithm. #[inline(always)] pub const fn char_to_digit_const(c: u8, radix: u32) -> Option { let digit = char_to_valid_digit_const(c, radix); if digit < radix { Some(digit) } else { None } } /// Determine if a character is a digit with a radix known at compile time. #[inline(always)] pub const fn char_is_digit_const(c: u8, radix: u32) -> bool { char_to_digit_const(c, radix).is_some() } /// Convert a digit to a character with a radix known at compile time. /// /// This optimizes for cases where radix is <= 10, and uses a decent, /// match-based fallback algorithm. #[inline(always)] #[cfg(any(feature = "write", feature = "floats"))] pub const fn digit_to_char_const(digit: u32, radix: u32) -> u8 { if radix <= 10 || digit < 10 { // Can short-circuit if we know the radix is small at compile time. digit as u8 + b'0' } else { digit as u8 + b'A' - 10 } } // NON-CONST // --------- // These are less optimized functions for when the radix is not known at // compile-time, which is a few (but important) cases. These generally have // improved compiler optimization passes when generics are used more sparingly. /// Convert a character to a digit. #[inline(always)] #[cfg(feature = "parse")] pub const fn char_to_digit(c: u8, radix: u32) -> Option { // Fallback, still decently fast. let digit = match c { b'0'..=b'9' => c - b'0', b'A'..=b'Z' => c - b'A' + 10, b'a'..=b'z' => c - b'a' + 10, _ => 0xFF, } as u32; if digit < radix { Some(digit) } else { None } } /// Determine if a character is a digit. #[inline(always)] #[cfg(feature = "parse")] pub const fn char_is_digit(c: u8, radix: u32) -> bool { char_to_digit(c, radix).is_some() } /// Convert a digit to a character. This uses a pre-computed table to avoid /// branching. /// /// # Panics /// /// Panics if `digit >= 36`. #[inline(always)] #[cfg(feature = "write")] pub fn digit_to_char(digit: u32) -> u8 { const TABLE: [u8; 36] = [ b'0', b'1', b'2', b'3', b'4', b'5', b'6', b'7', b'8', b'9', b'A', b'B', b'C', b'D', b'E', b'F', b'G', b'H', b'I', b'J', b'K', b'L', b'M', b'N', b'O', b'P', b'Q', b'R', b'S', b'T', b'U', b'V', b'W', b'X', b'Y', b'Z', ]; debug_assert!(digit < 36, "digit_to_char() invalid character."); TABLE[digit as usize] } lexical-util-1.0.6/src/div128.rs000064400000000000000000000373451046102023000144120ustar 00000000000000//! Optimized division algorithms for u128. //! //! # Fast Algorithms //! //! The more optimized algorithms for calculating the divisor constants are //! based off of the paper "Division by Invariant Integers Using //! Multiplication", by T. Granlund and P. Montgomery, in "Proc. of the //! SIGPLAN94 Conference on Programming Language Design and Implementation", //! available online [here](https://gmplib.org/~tege/divcnst-pldi94.pdf). //! //! This approach is derived from the Rust algorithm for formatting 128-bit //! values, and therefore is similarly dual-licensed under MIT/Apache-2.0. //! //! # Fallback Algorithms //! //! The slower algorithms in this module are derived off of `dtolnay/itoa` //! and Rust's compiler-builtins crate. This copies a specific //! path of LLVM's `__udivmodti4` intrinsic, which does division/ //! modulus for u128 in a single step. Rust implements both division //! and modulus in terms of this intrinsic, but calls the intrinsic //! twice for subsequent division and modulus operations on the same //! dividend/divisor, leading to significant performance overhead. //! //! This module calculates the optimal divisors for each radix, //! and exports a general-purpose division algorithm for u128 where //! the divisor can fit in a u64. The moderate algorithm is derived from //! dtolnay/itoa, which can be found //! [here](https://github.com/dtolnay/itoa/blob/master/src/udiv128.rs), which //! in turn is derived from Rust's compiler-builtins crate, which can be found //! [here](https://github.com/rust-lang-nursery/compiler-builtins/blob/master/src/int/udiv.rs). //! //! Licensing for these routines is therefore subject to an MIT/Illinois //! dual license (a BSD-like license), while the rest of the module is //! subject to an MIT/Apache-2.0 dual-license. //! //! # Generation //! //! See [`etc/div128.py`] for the script to generate the divisors and the //! constants, and the division algorithm. //! //! [`etc/div128.py`]: https://github.com/Alexhuszagh/rust-lexical/blob/main/lexical-util/etc/div128.py #![cfg(not(feature = "compact"))] #![cfg(feature = "write")] use crate::assert::debug_assert_radix; use crate::mul::mulhi; /// Calculate a div/remainder algorithm optimized for power-of-two radixes. /// /// This is trivial: the number of digits we process is `64 / log2(radix)`. /// Therefore, the `shr` is `log2(radix) * digits`, and the mask is just the /// lower `shr` bits of the digits. #[inline(always)] #[allow(clippy::many_single_char_names)] // reason="mathematical names" pub const fn pow2_u128_divrem(n: u128, mask: u64, shr: u32) -> (u128, u64) { let quot = n >> shr; let rem = mask & n as u64; (quot, rem) } /// Fast division/remainder algorithm for u128, without a fast native /// approximation. #[inline(always)] #[allow(clippy::many_single_char_names)] // reason="mathematical names" pub fn fast_u128_divrem( n: u128, d: u64, fast: u128, fast_shr: u32, factor: u128, factor_shr: u32, ) -> (u128, u64) { let quot = if n < fast { ((n >> fast_shr) as u64 / (d >> fast_shr)) as u128 } else { mulhi::(n, factor) >> factor_shr }; let rem = (n - quot * d as u128) as u64; (quot, rem) } /// Fast division/remainder algorithm for u128, without a fast native /// approximation. #[inline(always)] #[allow(clippy::many_single_char_names)] // reason="mathematical names" pub fn moderate_u128_divrem(n: u128, d: u64, factor: u128, factor_shr: u32) -> (u128, u64) { let quot = mulhi::(n, factor) >> factor_shr; let rem = (n - quot * d as u128) as u64; (quot, rem) } /// Optimized fallback division/remainder algorithm for u128. /// /// This is because the code generation for u128 divrem is very inefficient /// in Rust, calling both `__udivmodti4` twice internally, rather than a single /// time. /// /// This is still a fair bit slower than the optimized algorithms described /// in the above paper, but this is a suitable fallback when we cannot use /// the faster algorithm. #[cfg_attr(not(feature = "compact"), inline(always))] #[allow(clippy::many_single_char_names)] // reason="mathematical names" pub fn slow_u128_divrem(n: u128, d: u64, d_ctlz: u32) -> (u128, u64) { // Ensure we have the correct number of leading zeros passed. debug_assert_eq!(d_ctlz, d.leading_zeros()); // Optimize if we can divide using u64 first. let high = (n >> 64) as u64; if high == 0 { let low = n as u64; return ((low / d) as u128, low % d); } // sr = 1 + u64::BITS + d.leading_zeros() - high.leading_zeros(); let sr = 65 + d_ctlz - high.leading_zeros(); // 1 <= sr <= u64::BITS - 1 let mut q: u128 = n << (128 - sr); let mut r: u128 = n >> sr; let mut carry: u64 = 0; // Don't use a range because they may generate references to memcpy in // unoptimized code Loop invariants: r < d; carry is 0 or 1 let mut i = 0; while i < sr { i += 1; // r:q = ((r:q) << 1) | carry r = (r << 1) | (q >> 127); q = (q << 1) | carry as u128; // carry = 0 // if r >= d { // r -= d; // carry = 1; // } let s = (d as u128).wrapping_sub(r).wrapping_sub(1) as i128 >> 127; carry = (s & 1) as u64; r -= (d as u128) & s as u128; } ((q << 1) | carry as u128, r as u64) } /// Calculate the div/remainder of a value based on the radix. /// /// This uses the largest divisor possible for the given size, /// and uses various fast-path approximations for different types. /// /// 1. Powers-of-two can be cleanly split into 2 64-bit products. /// 2. Division that can be simulated as if by multiplication by a constant. /// 3. Cases of 2. with a power-of-two divisor. /// 4. Fallback cases. /// /// This returns the quotient and the remainder. /// For the number of digits processed, see /// [`min_step`](crate::step::min_step). #[inline(always)] #[allow(clippy::needless_return)] // reason="required based on radix configuration" pub fn u128_divrem(n: u128, radix: u32) -> (u128, u64) { debug_assert_radix(radix); // NOTE: to avoid branching when w don't need it, we use the compile logic #[cfg(feature = "radix")] { return match radix { 2 => u128_divrem_2(n), 3 => u128_divrem_3(n), 4 => u128_divrem_4(n), 5 => u128_divrem_5(n), 6 => u128_divrem_6(n), 7 => u128_divrem_7(n), 8 => u128_divrem_8(n), 9 => u128_divrem_9(n), 10 => u128_divrem_10(n), 11 => u128_divrem_11(n), 12 => u128_divrem_12(n), 13 => u128_divrem_13(n), 14 => u128_divrem_14(n), 15 => u128_divrem_15(n), 16 => u128_divrem_16(n), 17 => u128_divrem_17(n), 18 => u128_divrem_18(n), 19 => u128_divrem_19(n), 20 => u128_divrem_20(n), 21 => u128_divrem_21(n), 22 => u128_divrem_22(n), 23 => u128_divrem_23(n), 24 => u128_divrem_24(n), 25 => u128_divrem_25(n), 26 => u128_divrem_26(n), 27 => u128_divrem_27(n), 28 => u128_divrem_28(n), 29 => u128_divrem_29(n), 30 => u128_divrem_30(n), 31 => u128_divrem_31(n), 32 => u128_divrem_32(n), 33 => u128_divrem_33(n), 34 => u128_divrem_34(n), 35 => u128_divrem_35(n), 36 => u128_divrem_36(n), _ => unreachable!(), }; } #[cfg(all(feature = "power-of-two", not(feature = "radix")))] { return match radix { 2 => u128_divrem_2(n), 4 => u128_divrem_4(n), 8 => u128_divrem_8(n), 10 => u128_divrem_10(n), 16 => u128_divrem_16(n), 32 => u128_divrem_32(n), _ => unreachable!(), }; } #[cfg(not(feature = "power-of-two"))] { return u128_divrem_10(n); } } // AUTO-GENERATED // These functions were auto-generated by `etc/div128.py`. // Do not edit them unless there is a good reason to. // Preferably, edit the source code to generate the constants. // // The seemingly magical values are all derived there, and are explained // in the function signatures of the functions they call. #[inline(always)] #[cfg_attr(not(feature = "power-of-two"), allow(dead_code))] const fn u128_divrem_2(n: u128) -> (u128, u64) { pow2_u128_divrem(n, 18446744073709551615, 64) } #[inline(always)] #[cfg_attr(not(feature = "radix"), allow(dead_code))] fn u128_divrem_3(n: u128) -> (u128, u64) { slow_u128_divrem(n, 12157665459056928801, 0) } #[inline(always)] #[cfg_attr(not(feature = "power-of-two"), allow(dead_code))] const fn u128_divrem_4(n: u128) -> (u128, u64) { pow2_u128_divrem(n, 18446744073709551615, 64) } #[inline(always)] #[cfg_attr(not(feature = "radix"), allow(dead_code))] fn u128_divrem_5(n: u128) -> (u128, u64) { moderate_u128_divrem(n, 7450580596923828125, 105312291668557186697918027683670432319, 61) } #[inline(always)] #[cfg_attr(not(feature = "radix"), allow(dead_code))] fn u128_divrem_6(n: u128) -> (u128, u64) { fast_u128_divrem( n, 4738381338321616896, 309485009821345068724781056, 24, 165591931273573223021296166324748699891, 61, ) } #[inline(always)] #[cfg_attr(not(feature = "radix"), allow(dead_code))] fn u128_divrem_7(n: u128) -> (u128, u64) { moderate_u128_divrem(n, 3909821048582988049, 200683792729517998822275406364627986707, 61) } #[inline(always)] #[cfg_attr(not(feature = "power-of-two"), allow(dead_code))] const fn u128_divrem_8(n: u128) -> (u128, u64) { pow2_u128_divrem(n, 9223372036854775807, 63) } #[inline(always)] #[cfg_attr(not(feature = "radix"), allow(dead_code))] fn u128_divrem_9(n: u128) -> (u128, u64) { slow_u128_divrem(n, 12157665459056928801, 0) } #[inline(always)] fn u128_divrem_10(n: u128) -> (u128, u64) { fast_u128_divrem( n, 10000000000000000000, 9671406556917033397649408, 19, 156927543384667019095894735580191660403, 62, ) } #[inline(always)] #[cfg_attr(not(feature = "radix"), allow(dead_code))] fn u128_divrem_11(n: u128) -> (u128, u64) { slow_u128_divrem(n, 5559917313492231481, 1) } #[inline(always)] #[cfg_attr(not(feature = "radix"), allow(dead_code))] fn u128_divrem_12(n: u128) -> (u128, u64) { slow_u128_divrem(n, 2218611106740436992, 3) } #[inline(always)] #[cfg_attr(not(feature = "radix"), allow(dead_code))] fn u128_divrem_13(n: u128) -> (u128, u64) { moderate_u128_divrem(n, 8650415919381337933, 181410402513790565292660635782582404765, 62) } #[inline(always)] #[cfg_attr(not(feature = "radix"), allow(dead_code))] fn u128_divrem_14(n: u128) -> (u128, u64) { fast_u128_divrem( n, 2177953337809371136, 1208925819614629174706176, 16, 1407280417134467544760816054546363235, 53, ) } #[inline(always)] #[cfg_attr(not(feature = "radix"), allow(dead_code))] fn u128_divrem_15(n: u128) -> (u128, u64) { moderate_u128_divrem(n, 6568408355712890625, 1866504587258795246613513364166764993, 55) } #[inline(always)] #[cfg_attr(not(feature = "power-of-two"), allow(dead_code))] const fn u128_divrem_16(n: u128) -> (u128, u64) { pow2_u128_divrem(n, 18446744073709551615, 64) } #[inline(always)] #[cfg_attr(not(feature = "radix"), allow(dead_code))] fn u128_divrem_17(n: u128) -> (u128, u64) { moderate_u128_divrem(n, 2862423051509815793, 68529153692836345537218837732158950089, 59) } #[inline(always)] #[cfg_attr(not(feature = "radix"), allow(dead_code))] fn u128_divrem_18(n: u128) -> (u128, u64) { fast_u128_divrem( n, 6746640616477458432, 604462909807314587353088, 15, 232601011830094623283686247347795155951, 62, ) } #[inline(always)] #[cfg_attr(not(feature = "radix"), allow(dead_code))] fn u128_divrem_19(n: u128) -> (u128, u64) { moderate_u128_divrem(n, 15181127029874798299, 25842538415601616733690423925257626679, 60) } #[inline(always)] #[cfg_attr(not(feature = "radix"), allow(dead_code))] fn u128_divrem_20(n: u128) -> (u128, u64) { fast_u128_divrem( n, 1638400000000000000, 4951760157141521099596496896, 28, 239452428260295134118491722992235809941, 60, ) } #[inline(always)] #[cfg_attr(not(feature = "radix"), allow(dead_code))] fn u128_divrem_21(n: u128) -> (u128, u64) { moderate_u128_divrem(n, 3243919932521508681, 120939747781233590383781714337497669585, 60) } #[inline(always)] #[cfg_attr(not(feature = "radix"), allow(dead_code))] fn u128_divrem_22(n: u128) -> (u128, u64) { slow_u128_divrem(n, 6221821273427820544, 1) } #[inline(always)] #[cfg_attr(not(feature = "radix"), allow(dead_code))] fn u128_divrem_23(n: u128) -> (u128, u64) { moderate_u128_divrem(n, 11592836324538749809, 270731922700393644432243678371210997949, 63) } #[inline(always)] #[cfg_attr(not(feature = "radix"), allow(dead_code))] fn u128_divrem_24(n: u128) -> (u128, u64) { fast_u128_divrem( n, 876488338465357824, 10141204801825835211973625643008, 39, 55950381945266105153185943557606235389, 57, ) } #[inline(always)] #[cfg_attr(not(feature = "radix"), allow(dead_code))] fn u128_divrem_25(n: u128) -> (u128, u64) { moderate_u128_divrem(n, 1490116119384765625, 131640364585696483372397534604588040399, 59) } #[inline(always)] #[cfg_attr(not(feature = "radix"), allow(dead_code))] fn u128_divrem_26(n: u128) -> (u128, u64) { fast_u128_divrem( n, 2481152873203736576, 151115727451828646838272, 13, 316239166637962178669658228673482425689, 61, ) } #[inline(always)] #[cfg_attr(not(feature = "radix"), allow(dead_code))] fn u128_divrem_27(n: u128) -> (u128, u64) { slow_u128_divrem(n, 4052555153018976267, 2) } #[inline(always)] #[cfg_attr(not(feature = "radix"), allow(dead_code))] fn u128_divrem_28(n: u128) -> (u128, u64) { fast_u128_divrem( n, 6502111422497947648, 1237940039285380274899124224, 26, 241348591538561183926479953354701294803, 62, ) } #[inline(always)] #[cfg_attr(not(feature = "radix"), allow(dead_code))] fn u128_divrem_29(n: u128) -> (u128, u64) { moderate_u128_divrem(n, 10260628712958602189, 152941450056053853841698190746050519297, 62) } #[inline(always)] #[cfg_attr(not(feature = "radix"), allow(dead_code))] fn u128_divrem_30(n: u128) -> (u128, u64) { slow_u128_divrem(n, 15943230000000000000, 0) } #[inline(always)] #[cfg_attr(not(feature = "radix"), allow(dead_code))] fn u128_divrem_31(n: u128) -> (u128, u64) { moderate_u128_divrem(n, 787662783788549761, 124519929891402176328714857711808162537, 58) } #[inline(always)] #[cfg_attr(not(feature = "power-of-two"), allow(dead_code))] const fn u128_divrem_32(n: u128) -> (u128, u64) { pow2_u128_divrem(n, 1152921504606846975, 60) } #[inline(always)] #[cfg_attr(not(feature = "radix"), allow(dead_code))] fn u128_divrem_33(n: u128) -> (u128, u64) { slow_u128_divrem(n, 1667889514952984961, 3) } #[inline(always)] #[cfg_attr(not(feature = "radix"), allow(dead_code))] fn u128_divrem_34(n: u128) -> (u128, u64) { fast_u128_divrem( n, 2386420683693101056, 75557863725914323419136, 12, 328792707121977505492535302517672775183, 61, ) } #[inline(always)] #[cfg_attr(not(feature = "radix"), allow(dead_code))] fn u128_divrem_35(n: u128) -> (u128, u64) { moderate_u128_divrem(n, 3379220508056640625, 116097442450503652080238494022501325491, 60) } #[inline(always)] #[cfg_attr(not(feature = "radix"), allow(dead_code))] fn u128_divrem_36(n: u128) -> (u128, u64) { fast_u128_divrem( n, 4738381338321616896, 309485009821345068724781056, 24, 165591931273573223021296166324748699891, 61, ) } lexical-util-1.0.6/src/error.rs000064400000000000000000000435551046102023000145260ustar 00000000000000//! Error type for numeric parsing functions. //! //! The error type is C-compatible, simplifying use external language //! bindings. use core::{fmt, mem}; #[cfg(feature = "std")] use std::error; use static_assertions::const_assert; /// Error code during parsing, indicating failure type. #[non_exhaustive] #[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd)] pub enum Error { // PARSE ERRORS /// Integral overflow occurred during numeric parsing. Overflow(usize), /// Integral underflow occurred during numeric parsing. Underflow(usize), /// Invalid digit found before string termination. InvalidDigit(usize), /// Empty byte array found. Empty(usize), /// Empty mantissa found. EmptyMantissa(usize), /// Empty exponent found. EmptyExponent(usize), /// Empty integer found. EmptyInteger(usize), /// Empty fraction found. EmptyFraction(usize), /// Invalid positive mantissa sign was found. InvalidPositiveMantissaSign(usize), /// Mantissa sign was required(usize), but not found. MissingMantissaSign(usize), /// Exponent was present but not allowed. InvalidExponent(usize), /// Invalid positive exponent sign was found. InvalidPositiveExponentSign(usize), /// Exponent sign was required(usize), but not found. MissingExponentSign(usize), /// Exponent was present without fraction component. ExponentWithoutFraction(usize), /// Integer or integer component of float had invalid leading zeros. InvalidLeadingZeros(usize), /// No exponent with required exponent notation. MissingExponent(usize), /// Integral sign was required(usize), but not found. MissingSign(usize), /// Invalid positive sign for an integer was found. InvalidPositiveSign(usize), /// Invalid negative sign for an unsigned type was found. InvalidNegativeSign(usize), // NUMBER FORMAT ERRORS /// Invalid radix for the mantissa (significant) digits. InvalidMantissaRadix, /// Invalid base for the exponent. InvalidExponentBase, /// Invalid radix for the exponent digits. InvalidExponentRadix, /// Invalid digit separator character. InvalidDigitSeparator, /// Invalid decimal point character. InvalidDecimalPoint, /// Invalid symbol to represent exponent notation. InvalidExponentSymbol, /// Invalid character for a base prefix. InvalidBasePrefix, /// Invalid character for a base suffix. InvalidBaseSuffix, /// Invalid punctuation characters: multiple symbols overlap. InvalidPunctuation, /// Optional exponent flags were set while disabling exponent notation. InvalidExponentFlags, /// Set no positive mantissa sign while requiring mantissa signs. InvalidMantissaSign, /// Set no positive exponent sign while requiring exponent signs. InvalidExponentSign, /// Set optional special float flags while disable special floats. InvalidSpecial, /// Invalid consecutive integer digit separator. InvalidConsecutiveIntegerDigitSeparator, /// Invalid consecutive fraction digit separator. InvalidConsecutiveFractionDigitSeparator, /// Invalid consecutive exponent digit separator. InvalidConsecutiveExponentDigitSeparator, /// Invalid flags were set without the format feature. InvalidFlags, // OPTION ERRORS /// Invalid NaN string: must start with an `n` character. InvalidNanString, /// NaN string is too long. NanStringTooLong, /// Invalid short infinity string: must start with an `i` character. InvalidInfString, /// Short infinity string is too long. InfStringTooLong, /// Invalid long infinity string: must start with an `i` character. InvalidInfinityString, /// Long infinity string is too long. InfinityStringTooLong, /// Long infinity string is too short: it must be as long as short infinity. InfinityStringTooShort, /// Invalid float parsing algorithm. InvalidFloatParseAlgorithm, /// Invalid radix for the significant digits. InvalidRadix, /// Invalid precision flags for writing floats. InvalidFloatPrecision, /// Invalid negative exponent break: break is above 0. InvalidNegativeExponentBreak, /// Invalid positive exponent break: break is below 0. InvalidPositiveExponentBreak, // NOT AN ERROR /// An error did not actually occur, and the result was successful. Success, } // Ensure we don't have extra padding on the structure. const_assert!(mem::size_of::() <= 2 * mem::size_of::()); macro_rules! is_error_type { ($name:ident, $type:ident$($t:tt)*) => ( /// const fn check to see if an error is of a specific type. pub const fn $name(&self) -> bool { // Note: enum equality is not a const fn, so use a let expression. if let Self::$type$($t)* = self { true } else { false } } ); } impl Error { /// Get the index for the parsing error. pub fn index(&self) -> Option<&usize> { match self { // PARSE ERRORS Self::Overflow(index) => Some(index), Self::Underflow(index) => Some(index), Self::InvalidDigit(index) => Some(index), Self::Empty(index) => Some(index), Self::EmptyMantissa(index) => Some(index), Self::EmptyExponent(index) => Some(index), Self::EmptyInteger(index) => Some(index), Self::EmptyFraction(index) => Some(index), Self::InvalidPositiveMantissaSign(index) => Some(index), Self::MissingMantissaSign(index) => Some(index), Self::InvalidExponent(index) => Some(index), Self::InvalidPositiveExponentSign(index) => Some(index), Self::MissingExponentSign(index) => Some(index), Self::ExponentWithoutFraction(index) => Some(index), Self::InvalidLeadingZeros(index) => Some(index), Self::MissingExponent(index) => Some(index), Self::MissingSign(index) => Some(index), Self::InvalidPositiveSign(index) => Some(index), Self::InvalidNegativeSign(index) => Some(index), // NUMBER FORMAT ERRORS Self::InvalidMantissaRadix => None, Self::InvalidExponentBase => None, Self::InvalidExponentRadix => None, Self::InvalidDigitSeparator => None, Self::InvalidDecimalPoint => None, Self::InvalidExponentSymbol => None, Self::InvalidBasePrefix => None, Self::InvalidBaseSuffix => None, Self::InvalidPunctuation => None, Self::InvalidExponentFlags => None, Self::InvalidMantissaSign => None, Self::InvalidExponentSign => None, Self::InvalidSpecial => None, Self::InvalidConsecutiveIntegerDigitSeparator => None, Self::InvalidConsecutiveFractionDigitSeparator => None, Self::InvalidConsecutiveExponentDigitSeparator => None, Self::InvalidFlags => None, // OPTION ERRORS Self::InvalidNanString => None, Self::NanStringTooLong => None, Self::InvalidInfString => None, Self::InfStringTooLong => None, Self::InvalidInfinityString => None, Self::InfinityStringTooLong => None, Self::InfinityStringTooShort => None, Self::InvalidFloatParseAlgorithm => None, Self::InvalidRadix => None, Self::InvalidFloatPrecision => None, Self::InvalidNegativeExponentBreak => None, Self::InvalidPositiveExponentBreak => None, // NOT AN ERROR Self::Success => None, } } is_error_type!(is_overflow, Overflow(_)); is_error_type!(is_underflow, Underflow(_)); is_error_type!(is_invalid_digit, InvalidDigit(_)); is_error_type!(is_empty, Empty(_)); is_error_type!(is_empty_mantissa, EmptyMantissa(_)); is_error_type!(is_empty_exponent, EmptyExponent(_)); is_error_type!(is_empty_integer, EmptyInteger(_)); is_error_type!(is_empty_fraction, EmptyFraction(_)); is_error_type!(is_invalid_positive_mantissa_sign, InvalidPositiveMantissaSign(_)); is_error_type!(is_missing_mantissa_sign, MissingMantissaSign(_)); is_error_type!(is_invalid_exponent, InvalidExponent(_)); is_error_type!(is_invalid_positive_exponent_sign, InvalidPositiveExponentSign(_)); is_error_type!(is_missing_exponent_sign, MissingExponentSign(_)); is_error_type!(is_exponent_without_fraction, ExponentWithoutFraction(_)); is_error_type!(is_invalid_leading_zeros, InvalidLeadingZeros(_)); is_error_type!(is_missing_exponent, MissingExponent(_)); is_error_type!(is_missing_sign, MissingSign(_)); is_error_type!(is_invalid_positive_sign, InvalidPositiveSign(_)); is_error_type!(is_invalid_negative_sign, InvalidNegativeSign(_)); is_error_type!(is_invalid_mantissa_radix, InvalidMantissaRadix); is_error_type!(is_invalid_exponent_base, InvalidExponentBase); is_error_type!(is_invalid_exponent_radix, InvalidExponentRadix); is_error_type!(is_invalid_digit_separator, InvalidDigitSeparator); is_error_type!(is_invalid_decimal_point, InvalidDecimalPoint); is_error_type!(is_invalid_exponent_symbol, InvalidExponentSymbol); is_error_type!(is_invalid_base_prefix, InvalidBasePrefix); is_error_type!(is_invalid_base_suffix, InvalidBaseSuffix); is_error_type!(is_invalid_punctuation, InvalidPunctuation); is_error_type!(is_invalid_exponent_flags, InvalidExponentFlags); is_error_type!(is_invalid_mantissa_sign, InvalidMantissaSign); is_error_type!(is_invalid_exponent_sign, InvalidExponentSign); is_error_type!(is_invalid_special, InvalidSpecial); is_error_type!( is_invalid_consecutive_integer_digit_separator, InvalidConsecutiveIntegerDigitSeparator ); is_error_type!( is_invalid_consecutive_fraction_digit_separator, InvalidConsecutiveFractionDigitSeparator ); is_error_type!( is_invalid_consecutive_exponent_digit_separator, InvalidConsecutiveExponentDigitSeparator ); is_error_type!(is_invalid_flags, InvalidFlags); is_error_type!(is_invalid_nan_string, InvalidNanString); is_error_type!(is_nan_string_too_long, NanStringTooLong); is_error_type!(is_invalid_inf_string, InvalidInfString); is_error_type!(is_inf_string_too_long, InfStringTooLong); is_error_type!(is_invalid_infinity_string, InvalidInfinityString); is_error_type!(is_infinity_string_too_long, InfinityStringTooLong); is_error_type!(is_infinity_string_too_short, InfinityStringTooShort); is_error_type!(is_invalid_float_parse_algorithm, InvalidFloatParseAlgorithm); is_error_type!(is_invalid_radix, InvalidRadix); is_error_type!(is_invalid_float_precision, InvalidFloatPrecision); is_error_type!(is_invalid_negative_exponent_break, InvalidNegativeExponentBreak); is_error_type!(is_invalid_positive_exponent_break, InvalidPositiveExponentBreak); is_error_type!(is_success, Success); } /// Add an error message for parsing errors. macro_rules! write_parse_error { ($formatter:ident, $message:literal, $index:ident) => { write!($formatter, "lexical parse error: {} at index {}", $message, $index) }; } /// Add an error message for number format errors. macro_rules! format_message { ($formatter:ident, $message:literal) => { write!($formatter, "lexical number format error: {}", $message) }; } /// Add an error message for options errors. macro_rules! options_message { ($formatter:ident, $message:literal) => { write!($formatter, "lexical options error: {}", $message) }; } impl fmt::Display for Error { fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { match self { // PARSE ERRORS Self::Overflow(index) => write_parse_error!(formatter, "'numeric overflow occurred'", index), Self::Underflow(index) => write_parse_error!(formatter, "'numeric underflow occurred'", index), Self::InvalidDigit(index) => write_parse_error!(formatter, "'invalid digit found'", index), Self::Empty(index) => write_parse_error!(formatter, "'the string to parse was empty'", index), Self::EmptyMantissa(index) => write_parse_error!(formatter, "'no significant digits found'", index), Self::EmptyExponent(index) => write_parse_error!(formatter, "'exponent notation found without an exponent'", index), Self::EmptyInteger(index) => write_parse_error!(formatter, "'invalid float with no integer digits'", index), Self::EmptyFraction(index) => write_parse_error!(formatter, "'invalid float with no fraction digits'", index), Self::InvalidPositiveMantissaSign(index) => write_parse_error!(formatter, "'invalid `+` sign before significant digits'", index), Self::MissingMantissaSign(index) => write_parse_error!(formatter, "'missing required `+/-` sign for significant digits'", index), Self::InvalidExponent(index) => write_parse_error!(formatter, "'exponent found but not allowed'", index), Self::InvalidPositiveExponentSign(index) => write_parse_error!(formatter, "'invalid `+` sign in exponent'", index), Self::MissingExponentSign(index) => write_parse_error!(formatter, "'missing required `+/-` sign for exponent'", index), Self::ExponentWithoutFraction(index) => write_parse_error!(formatter, "'invalid float containing exponent without fraction'", index), Self::InvalidLeadingZeros(index) => write_parse_error!(formatter, "'invalid number with leading zeros before digits'", index), Self::MissingExponent(index) => write_parse_error!(formatter, "'missing required exponent'", index), Self::MissingSign(index) => write_parse_error!(formatter, "'missing required `+/-` sign for integer'", index), Self::InvalidPositiveSign(index) => write_parse_error!(formatter, "'invalid `+` sign for an integer was found'", index), Self::InvalidNegativeSign(index) => write_parse_error!(formatter, "'invalid `-` sign for an unsigned type was found'", index), // NUMBER FORMAT ERRORS Self::InvalidMantissaRadix => format_message!(formatter, "'invalid radix for mantissa digits'"), Self::InvalidExponentBase => format_message!(formatter, "'invalid exponent base'"), Self::InvalidExponentRadix => format_message!(formatter, "'invalid radix for exponent digits'"), Self::InvalidDigitSeparator => format_message!(formatter, "'invalid digit separator: must be ASCII and not a digit or a `+/-` sign'"), Self::InvalidDecimalPoint => format_message!(formatter, "'invalid decimal point: must be ASCII and not a digit or a `+/-` sign'"), Self::InvalidExponentSymbol => format_message!(formatter, "'invalid exponent symbol: must be ASCII and not a digit or a `+/-` sign'"), Self::InvalidBasePrefix => format_message!(formatter, "'invalid base prefix character'"), Self::InvalidBaseSuffix => format_message!(formatter, "'invalid base suffix character'"), Self::InvalidPunctuation => format_message!(formatter, "'invalid punctuation: multiple characters overlap'"), Self::InvalidExponentFlags => format_message!(formatter, "'exponent flags set while disabling exponent notation'"), Self::InvalidMantissaSign => format_message!(formatter, "'disabled the `+` sign while requiring a sign for significant digits'"), Self::InvalidExponentSign => format_message!(formatter, "'disabled the `+` sign while requiring a sign for exponent digits'"), Self::InvalidSpecial => format_message!(formatter, "'special flags set while disabling special floats'"), Self::InvalidConsecutiveIntegerDigitSeparator => format_message!(formatter, "'enabled consecutive digit separators in the integer without setting a valid location'"), Self::InvalidConsecutiveFractionDigitSeparator => format_message!(formatter, "'enabled consecutive digit separators in the fraction without setting a valid location'"), Self::InvalidConsecutiveExponentDigitSeparator => format_message!(formatter, "'enabled consecutive digit separators in the exponent without setting a valid location'"), Self::InvalidFlags => format_message!(formatter, "'invalid flags enabled without the format feature'"), // OPTION ERRORS Self::InvalidNanString => options_message!(formatter, "'NaN string must started with `n`'"), Self::NanStringTooLong => options_message!(formatter, "'NaN string is too long'"), Self::InvalidInfString => options_message!(formatter, "'short infinity string must started with `i`'"), Self::InfStringTooLong => options_message!(formatter, "'short infinity string is too long'"), Self::InvalidInfinityString => options_message!(formatter, "'long infinity string must started with `i`'"), Self::InfinityStringTooLong => options_message!(formatter, "'long infinity string is too long'"), Self::InfinityStringTooShort => options_message!(formatter, "'long infinity string is too short'"), Self::InvalidFloatParseAlgorithm => options_message!(formatter, "'invalid combination of float parse algorithms'"), Self::InvalidRadix => options_message!(formatter, "'invalid radix for significant digits'"), Self::InvalidFloatPrecision => options_message!(formatter, "'invalid float precision: min digits is larger than max digits'"), Self::InvalidNegativeExponentBreak => options_message!(formatter, "'invalid negative exponent break: value is above 0'"), Self::InvalidPositiveExponentBreak => options_message!(formatter, "'invalid positive exponent break: value is below 0'"), // NOT AN ERROR Self::Success => write!(formatter, "'not actually an error'"), } } } #[cfg(feature = "std")] impl error::Error for Error { } lexical-util-1.0.6/src/extended_float.rs000064400000000000000000000024221046102023000163460ustar 00000000000000//! Extended precision floating-point type. //! //! Also contains helpers to convert to and from native rust floats. //! This representation stores the mantissa as a 64-bit unsigned integer, //! and the exponent as a 32-bit unsigned integer, allowed ~80 bits of //! precision (only 16 bits of the 32-bit integer are used, u32 is used //! for performance). Since there is no storage for the sign bit, //! this only works for positive floats. #![cfg(feature = "floats")] use crate::num::UnsignedInteger; /// Extended precision floating-point type. /// /// This doesn't have any methods because it's used for **very** different /// things for the Lemire, Bellepheron, and other algorithms. In Grisu, /// it's an unbiased representation, for Lemire, it's a biased representation. #[derive(Clone, Copy, Debug, PartialEq, Eq)] pub struct ExtendedFloat { /// Mantissa for the extended-precision float. pub mant: M, /// Binary exponent for the extended-precision float. pub exp: i32, } impl ExtendedFloat { /// Get the mantissa component. #[inline(always)] pub fn mantissa(&self) -> M { self.mant } /// Get the exponent component. #[inline(always)] pub fn exponent(&self) -> i32 { self.exp } } lexical-util-1.0.6/src/f16.rs000064400000000000000000001053521046102023000137630ustar 00000000000000//! Half-precision IEEE-754 floating point implementation. //! //! f16 is meant as an interchange format, and therefore there may be //! rounding error in using it for fast-path algorithms. Since there //! are no native operations using `f16`, this is of minimal concern. //! //! Most of this code has been implemented from [`half`], to enable simple //! conversions to and from f32. This is provided as standalone code //! to avoid any external dependencies and avoid the serialization logic //! for serde, etc. //! //! There is no unsafety in this module other than a manual implementation //! of sync/send for a primitive type. //! //! The documentation and implementation for other parts of this code is //! derived from the Rust standard library, as is some of the more complex //! functionality. //! //! [`half`] is dual licensed under an Apache 2.0 and MIT license. //! //! [`half`]: https://github.com/starkat99/half-rs #![cfg(feature = "f16")] #![doc(hidden)] use core::cmp::Ordering; use core::iter::{Product, Sum}; use core::num::FpCategory; use core::ops::*; use core::{fmt, mem, num, str}; use crate::num::Float; use crate::numtypes::*; /// Half-precision IEEE-754 floating point type. /// /// This has the same representation as [`f16`] from [`half`], and /// is guaranteed to be supported as a `u16` to/from C. /// /// [`f16`]: https://docs.rs/half/latest/half/struct.f16.html /// [`half`]: https://docs.rs/half/latest/half/ #[repr(C)] #[allow(non_camel_case_types)] #[derive(Default, Copy, Clone)] pub struct f16(u16); // # SAFETY: bf16 is a trivial type internally represented by u16. unsafe impl Send for f16 { } // # SAFETY: bf16 is a trivial type internally represented by u16. unsafe impl Sync for f16 { } impl f16 { /// The radix or base of the internal representation of `f16`. pub const RADIX: u32 = 2; /// Number of significant digits in base 2. pub const MANTISSA_DIGITS: u32 = ::MANTISSA_SIZE as u32 + 1; /// Approximate number of significant digits in base 10. /// /// This is the maximum x such that any decimal number with x /// significant digits can be converted to `f16` and back without loss. /// /// Equal to floor(log10 2[`MANTISSA_DIGITS`] & /// minus; 1). /// /// [`MANTISSA_DIGITS`]: f16::MANTISSA_DIGITS pub const DIGITS: u32 = 3; /// [Machine epsilon] value for `f16`. /// /// This is the difference between `1.0` and the next larger representable /// number. /// /// Equal to 21 − [`MANTISSA_DIGITS`]. /// /// [Machine epsilon]: https://en.wikipedia.org/wiki/Machine_epsilon /// [`MANTISSA_DIGITS`]: f16::MANTISSA_DIGITS pub const EPSILON: Self = f16(0x1400u16); /// Smallest finite `f16` value. /// /// Equal to −[`MAX`]. /// /// [`MAX`]: f16::MAX pub const MIN: Self = ::MIN; /// Smallest positive normal `f16` value. /// /// Equal to 2[`MIN_EXP`] − 1. /// /// [`MIN_EXP`]: f16::MIN_EXP pub const MIN_POSITIVE: Self = Self(0x0400u16); /// Largest finite `f16` value. /// /// Equal to /// (1 − 2−[`MANTISSA_DIGITS`])  /// 2[`MAX_EXP`]. /// /// [`MANTISSA_DIGITS`]: f16::MANTISSA_DIGITS /// [`MAX_EXP`]: f16::MAX_EXP pub const MAX: Self = ::MAX; /// Maximum possible power of 2 exponent. /// /// If x = `MAX_EXP`, then normal numbers /// < 1 × 2x. pub const MAX_EXP: i32 = Self::MAX_EXPONENT + Self::MANTISSA_SIZE; /// One greater than the minimum possible normal power of 2 exponent. /// /// If x = `MIN_EXP`, then normal numbers /// ≥ 0.5 × 2x. // NOTE: This is -MAX_EXP + 3 pub const MIN_EXP: i32 = -Self::MAX_EXP + 3; /// Minimum x for which 10x is normal. /// /// Equal to ceil(log10 [`MIN_POSITIVE`]). /// /// [`MIN_POSITIVE`]: f16::MIN_POSITIVE pub const MIN_10_EXP: i32 = -4; /// Maximum x for which 10x is normal. /// /// Equal to floor(log10 [`MAX`]). /// /// [`MAX`]: f16::MAX pub const MAX_10_EXP: i32 = 4; /// Not a Number (NaN). /// /// Note that IEEE 754 doesn't define just a single NaN value; /// a plethora of bit patterns are considered to be NaN. /// Furthermore, the standard makes a difference /// between a "signaling" and a "quiet" NaN, /// and allows inspecting its "payload" (the unspecified bits in the bit /// pattern). This constant isn't guaranteed to equal to any specific /// NaN bitpattern, and the stability of its representation over Rust /// versions and target platforms isn't guaranteed. pub const NAN: Self = ::NAN; /// Infinity (∞). pub const INFINITY: Self = ::INFINITY; /// Negative infinity (−∞). pub const NEG_INFINITY: Self = ::NEG_INFINITY; /// Sign bit pub const SIGN_MASK: u16 = ::SIGN_MASK; /// Exponent mask pub const EXP_MASK: u16 = ::EXPONENT_MASK; /// Mantissa mask pub const MAN_MASK: u16 = ::MANTISSA_MASK; /// Minimum representable positive value (min subnormal) pub const TINY_BITS: u16 = 0x1; /// Minimum representable negative value (min negative subnormal) pub const NEG_TINY_BITS: u16 = Self::TINY_BITS | Self::SIGN_MASK; /// Returns `true` if this value is NaN. #[must_use] #[inline(always)] pub const fn is_nan(self) -> bool { let bits = self.to_bits(); let is_special = bits & Self::EXPONENT_MASK == Self::EXPONENT_MASK; is_special && (bits & Self::MANTISSA_MASK) != 0 } /// Computes the absolute value of `self`. #[must_use] #[inline(always)] pub const fn abs(self) -> Self { Self(self.0 & !Self::SIGN_MASK) } /// Returns `true` if this value is positive infinity or negative infinity, /// and `false` otherwise. #[must_use] #[inline(always)] pub const fn is_infinite(self) -> bool { eq(self, Self::INFINITY) | eq(self, Self::NEG_INFINITY) } /// Returns `true` if this number is neither infinite nor NaN. #[must_use] #[inline(always)] pub const fn is_finite(self) -> bool { self.to_bits() & Self::EXPONENT_MASK != Self::EXPONENT_MASK } /// Returns `true` if the number is [subnormal]. /// /// [subnormal]: https://en.wikipedia.org/wiki/Denormal_number #[must_use] #[inline(always)] pub const fn is_subnormal(self) -> bool { matches!(self.classify(), FpCategory::Subnormal) } /// Returns `true` if the number is neither zero, infinite, /// [subnormal], or NaN. /// /// [subnormal]: https://en.wikipedia.org/wiki/Denormal_number #[must_use] #[inline(always)] pub const fn is_normal(self) -> bool { matches!(self.classify(), FpCategory::Normal) } /// Returns the floating point category of the number. If only one property /// is going to be tested, it is generally faster to use the specific /// predicate instead. #[inline(always)] pub const fn classify(self) -> FpCategory { let b = self.to_bits(); match (b & Self::MAN_MASK, b & Self::EXP_MASK) { (0, Self::EXP_MASK) => FpCategory::Infinite, (_, Self::EXP_MASK) => FpCategory::Nan, (0, 0) => FpCategory::Zero, (_, 0) => FpCategory::Subnormal, _ => FpCategory::Normal, } } /// Returns `true` if `self` has a positive sign, including `+0.0`, NaNs /// with positive sign bit and positive infinity. /// /// Note that IEEE 754 doesn't assign any meaning to the sign bit in case of /// a NaN, and as Rust doesn't guarantee that the bit pattern of NaNs are /// conserved over arithmetic operations, the result of `is_sign_positive` /// on a NaN might produce an unexpected or non-portable result. See the /// [specification of NaN bit patterns](f32#nan-bit-patterns) for more /// info. Use `self.signum() == 1.0` if you need fully portable behavior /// (will return `false` for all NaNs). #[inline(always)] pub const fn is_sign_positive(self) -> bool { self.to_bits() & Self::SIGN_MASK == 0 } /// Returns `true` if `self` has a negative sign, including `-0.0`, NaNs /// with negative sign bit and negative infinity. /// /// Note that IEEE 754 doesn't assign any meaning to the sign bit in case of /// a NaN, and as Rust doesn't guarantee that the bit pattern of NaNs are /// conserved over arithmetic operations, the result of `is_sign_negative` /// on a NaN might produce an unexpected or non-portable result. See the /// [specification of NaN bit patterns](f32#nan-bit-patterns) for more /// info. Use `self.signum() == -1.0` if you need fully portable /// behavior (will return `false` for all NaNs). #[inline(always)] pub const fn is_sign_negative(self) -> bool { !self.is_sign_positive() } /// Takes the reciprocal (inverse) of a number, `1/x`. #[must_use] #[inline(always)] pub fn recip(self) -> Self { Self::ONE / self } /// Converts radians to degrees. #[must_use] #[inline(always)] pub fn to_degrees(self) -> Self { self * Self::from_u16(180) / Self::PI } /// Converts degrees to radians. #[must_use] #[inline(always)] pub fn to_radians(self) -> Self { self * Self::PI / Self::from_u16(180) } /// Returns the maximum of the two numbers, ignoring NaN. /// /// If one of the arguments is NaN, then the other argument is returned. #[must_use] #[inline(always)] pub fn max(self, other: Self) -> Self { if other > self && !other.is_nan() { other } else { self } } /// Returns the minimum of the two numbers. /// /// If one of the arguments is NaN, then the other argument is returned. #[must_use] #[inline(always)] pub fn min(self, other: Self) -> Self { if other < self && !other.is_nan() { other } else { self } } /// Raw transmutation to `u16`. /// /// This is currently identical to `transmute::(self)` on all /// platforms. /// /// See [`from_bits`](Self::from_bits) for some discussion of the /// portability of this operation (there are almost no issues). /// /// Note that this function is distinct from `as` casting, which attempts to /// preserve the *numeric* value, and not the bitwise value. #[inline(always)] pub const fn to_bits(self) -> u16 { self.0 } /// Raw transmutation from `u16`. /// /// This is currently identical to `transmute::(v)` on all /// platforms. It turns out this is incredibly portable, for two /// reasons: /// /// * Floats and Ints have the same endianness on all supported platforms. /// * IEEE 754 very precisely specifies the bit layout of floats. /// /// However there is one caveat: prior to the 2008 version of IEEE 754, how /// to interpret the NaN signaling bit wasn't actually specified. Most /// platforms (notably x86 and ARM) picked the interpretation that was /// ultimately standardized in 2008, but some didn't (notably MIPS). As /// a result, all signaling NaNs on MIPS are quiet NaNs on x86, and /// vice-versa. /// /// Rather than trying to preserve signaling-ness cross-platform, this /// implementation favors preserving the exact bits. This means that /// any payloads encoded in NaNs will be preserved even if the result of /// this method is sent over the network from an x86 machine to a MIPS one. /// /// If the results of this method are only manipulated by the same /// architecture that produced them, then there is no portability concern. /// /// If the input isn't NaN, then there is no portability concern. /// /// If you don't care about signalingness (very likely), then there is no /// portability concern. /// /// Note that this function is distinct from `as` casting, which attempts to /// preserve the *numeric* value, and not the bitwise value. #[inline(always)] pub const fn from_bits(bits: u16) -> Self { Self(bits) } /// Returns the memory representation of this floating point number as a /// byte array in big-endian (network) byte order. /// /// See [`from_bits`](Self::from_bits) for some discussion of the /// portability of this operation (there are almost no issues). #[must_use] #[inline(always)] pub const fn to_be_bytes(self) -> [u8; 2] { self.to_bits().to_be_bytes() } /// Returns the memory representation of this floating point number as a /// byte array in little-endian byte order. /// /// See [`from_bits`](Self::from_bits) for some discussion of the /// portability of this operation (there are almost no issues). #[must_use] #[inline(always)] pub const fn to_le_bytes(self) -> [u8; 2] { self.to_bits().to_le_bytes() } /// Returns the memory representation of this floating point number as a /// byte array in native byte order. /// /// As the target platform's native endianness is used, portable code /// should use [`to_be_bytes`] or [`to_le_bytes`], as appropriate, instead. /// /// [`to_be_bytes`]: Self::to_be_bytes /// [`to_le_bytes`]: Self::to_le_bytes /// /// See [`from_bits`](Self::from_bits) for some discussion of the #[must_use] #[inline(always)] pub const fn to_ne_bytes(self) -> [u8; 2] { self.to_bits().to_ne_bytes() } /// Creates a floating point value from its representation as a byte array /// in big endian. /// /// See [`from_bits`](Self::from_bits) for some discussion of the /// portability of this operation (there are almost no issues). #[must_use] #[inline(always)] pub const fn from_be_bytes(bytes: [u8; 2]) -> Self { Self::from_bits(u16::from_be_bytes(bytes)) } /// Creates a floating point value from its representation as a byte array /// in little endian. /// /// See [`from_bits`](Self::from_bits) for some discussion of the /// portability of this operation (there are almost no issues). #[must_use] #[inline(always)] pub const fn from_le_bytes(bytes: [u8; 2]) -> Self { Self::from_bits(u16::from_le_bytes(bytes)) } /// Creates a floating point value from its representation as a byte array /// in native endian. /// /// As the target platform's native endianness is used, portable code /// likely wants to use [`from_be_bytes`] or [`from_le_bytes`], as /// appropriate instead. /// /// [`from_be_bytes`]: Self::from_be_bytes /// [`from_le_bytes`]: Self::from_le_bytes /// /// See [`from_bits`](Self::from_bits) for some discussion of the /// portability of this operation (there are almost no issues). #[must_use] #[inline(always)] pub const fn from_ne_bytes(bytes: [u8; 2]) -> Self { Self::from_bits(u16::from_ne_bytes(bytes)) } /// Returns the ordering between `self` and `other`. /// /// Unlike the standard partial comparison between floating point numbers, /// this comparison always produces an ordering in accordance to /// the `totalOrder` predicate as defined in the IEEE 754 (2008 revision) /// floating point standard. The values are ordered in the following /// sequence: /// /// - negative quiet NaN /// - negative signaling NaN /// - negative infinity /// - negative numbers /// - negative subnormal numbers /// - negative zero /// - positive zero /// - positive subnormal numbers /// - positive numbers /// - positive infinity /// - positive signaling NaN /// - positive quiet NaN. /// /// The ordering established by this function does not always agree with the /// [`PartialOrd`] and [`PartialEq`] implementations of `f16`. For example, /// they consider negative and positive zero equal, while `total_cmp` /// doesn't. /// /// The interpretation of the signaling NaN bit follows the definition in /// the IEEE 754 standard, which may not match the interpretation by some of /// the older, non-conformant (e.g. MIPS) hardware implementations. /// /// # Examples /// ``` /// # use half::f16; /// let mut v: Vec = vec![]; /// v.push(f16::ONE); /// v.push(f16::INFINITY); /// v.push(f16::NEG_INFINITY); /// v.push(f16::NAN); /// v.push(f16::MAX_SUBNORMAL); /// v.push(-f16::MAX_SUBNORMAL); /// v.push(f16::ZERO); /// v.push(f16::NEG_ZERO); /// v.push(f16::NEG_ONE); /// v.push(f16::MIN_POSITIVE); /// /// v.sort_by(|a, b| a.total_cmp(&b)); /// /// assert!(v /// .into_iter() /// .zip( /// [ /// f16::NEG_INFINITY, /// f16::NEG_ONE, /// -f16::MAX_SUBNORMAL, /// f16::NEG_ZERO, /// f16::ZERO, /// f16::MAX_SUBNORMAL, /// f16::MIN_POSITIVE, /// f16::ONE, /// f16::INFINITY, /// f16::NAN /// ] /// .iter() /// ) /// .all(|(a, b)| a.to_bits() == b.to_bits())); /// ``` // Implementation based on: https://doc.rust-lang.org/std/primitive.f32.html#method.total_cmp #[must_use] #[inline(always)] pub fn total_cmp(&self, other: &Self) -> Ordering { let mut left = self.to_bits() as i16; let mut right = other.to_bits() as i16; left ^= (((left >> 15) as u16) >> 1) as i16; right ^= (((right >> 15) as u16) >> 1) as i16; left.cmp(&right) } /// Restrict a value to a certain interval unless it is NaN. /// /// Returns `max` if `self` is greater than `max`, and `min` if `self` is /// less than `min`. Otherwise this returns `self`. /// /// Note that this function returns NaN if the initial value was NaN as /// well. /// /// # Panics /// Panics if `min > max`, `min` is NaN, or `max` is NaN. /// /// # Examples /// /// ``` /// # use half::prelude::*; /// assert!(f16::from_f32(-3.0).clamp(f16::from_f32(-2.0), f16::from_f32(1.0)) == f16::from_f32(-2.0)); /// assert!(f16::from_f32(0.0).clamp(f16::from_f32(-2.0), f16::from_f32(1.0)) == f16::from_f32(0.0)); /// assert!(f16::from_f32(2.0).clamp(f16::from_f32(-2.0), f16::from_f32(1.0)) == f16::from_f32(1.0)); /// assert!(f16::NAN.clamp(f16::from_f32(-2.0), f16::from_f32(1.0)).is_nan()); /// ``` #[must_use] #[inline(always)] pub fn clamp(self, min: f16, max: f16) -> f16 { assert!(min <= max); let mut x = self; if x < min { x = min; } if x > max { x = max; } x } } macro_rules! from_int_impl { ($t:ty, $func:ident) => { /// Create from the integral type, as if by an `as` cast. #[inline(always)] pub const fn $func(value: $t) -> Self { f32_to_f16(value as f32) } }; } // Non-standard extensions to simplify working with `f16`. impl f16 { /// [`f16`] 1 pub const ONE: f16 = f16(0x3C00u16); /// [`f16`] 0 pub const ZERO: f16 = f16(0x0000u16); /// [`f16`] -0 pub const NEG_ZERO: f16 = f16(0x8000u16); /// [`f16`] -1 pub const NEG_ONE: f16 = f16(0xBC00u16); /// [`f16`] Euler's number (ℯ) pub const E: f16 = f16(0x4170u16); /// [`f16`] Archimedes' constant (π) pub const PI: f16 = f16(0x4248u16); /// [`f16`] 1/π pub const FRAC_1_PI: f16 = f16(0x3518u16); /// [`f16`] 1/√2 pub const FRAC_1_SQRT_2: f16 = f16(0x39A8u16); /// [`f16`] 2/π pub const FRAC_2_PI: f16 = f16(0x3918u16); /// [`f16`] 2/√π pub const FRAC_2_SQRT_PI: f16 = f16(0x3C83u16); /// [`f16`] π/2 pub const FRAC_PI_2: f16 = f16(0x3E48u16); /// [`f16`] π/3 pub const FRAC_PI_3: f16 = f16(0x3C30u16); /// [`f16`] π/4 pub const FRAC_PI_4: f16 = f16(0x3A48u16); /// [`f16`] π/6 pub const FRAC_PI_6: f16 = f16(0x3830u16); /// [`f16`] π/8 pub const FRAC_PI_8: f16 = f16(0x3648u16); /// [`f16`] 𝗅𝗇 10 pub const LN_10: f16 = f16(0x409Bu16); /// [`f16`] 𝗅𝗇 2 pub const LN_2: f16 = f16(0x398Cu16); /// [`f16`] 𝗅𝗈𝗀₁₀ℯ pub const LOG10_E: f16 = f16(0x36F3u16); /// [`f16`] 𝗅𝗈𝗀₁₀2 pub const LOG10_2: f16 = f16(0x34D1u16); /// [`f16`] 𝗅𝗈𝗀₂ℯ pub const LOG2_E: f16 = f16(0x3DC5u16); /// [`f16`] 𝗅𝗈𝗀₂10 pub const LOG2_10: f16 = f16(0x42A5u16); /// [`f16`] √2 pub const SQRT_2: f16 = f16(0x3DA8u16); /// Convert the data to an `f32` type, used for numerical operations. #[inline(always)] pub const fn as_f32(self) -> f32 { f16_to_f32(self) } /// Create the type from an `f32` type, used for numerical operations. #[inline(always)] pub const fn from_f32(value: f32) -> Self { f32_to_f16(value) } from_int_impl!(u8, from_u8); from_int_impl!(u16, from_u16); from_int_impl!(u32, from_u32); from_int_impl!(u64, from_u64); from_int_impl!(u128, from_u128); from_int_impl!(i8, from_i8); from_int_impl!(i16, from_i16); from_int_impl!(i32, from_i32); from_int_impl!(i64, from_i64); from_int_impl!(i128, from_i128); from_int_impl!(f64, from_f64); } impl PartialEq for f16 { #[inline(always)] fn eq(&self, other: &Self) -> bool { eq(*self, *other) } } impl PartialOrd for f16 { #[inline(always)] fn partial_cmp(&self, other: &Self) -> Option { partial_cmp(*self, *other) } #[inline(always)] fn lt(&self, other: &f16) -> bool { lt(*self, *other) } #[inline(always)] fn le(&self, other: &f16) -> bool { le(*self, *other) } #[inline(always)] fn gt(&self, other: &f16) -> bool { gt(*self, *other) } #[inline(always)] fn ge(&self, other: &f16) -> bool { ge(*self, *other) } } impl Add for f16 { type Output = Self; #[inline(always)] fn add(self, rhs: Self) -> Self::Output { Self::from_f32(self.as_f32() + rhs.as_f32()) } } op_impl!(f16, Add, AddAssign, add, add_assign); impl Div for f16 { type Output = Self; #[inline(always)] fn div(self, rhs: Self) -> Self::Output { Self::from_f32(self.as_f32() / rhs.as_f32()) } } op_impl!(f16, Div, DivAssign, div, div_assign); impl Mul for f16 { type Output = Self; #[inline(always)] fn mul(self, rhs: Self) -> Self::Output { Self::from_f32(self.as_f32() * rhs.as_f32()) } } op_impl!(f16, Mul, MulAssign, mul, mul_assign); impl Sub for f16 { type Output = Self; #[inline(always)] fn sub(self, rhs: Self) -> Self::Output { Self::from_f32(self.as_f32() - rhs.as_f32()) } } op_impl!(f16, Sub, SubAssign, sub, sub_assign); impl Rem for f16 { type Output = Self; #[inline(always)] fn rem(self, rhs: Self) -> Self::Output { Self::from_f32(self.as_f32() % rhs.as_f32()) } } op_impl!(f16, Rem, RemAssign, rem, rem_assign); impl Neg for f16 { type Output = Self; #[inline(always)] fn neg(self) -> Self::Output { Self::from_bits(self.0 ^ (1 << 15)) } } ref_impl!(f16, Neg, neg); // NOTE: This is not optimized, and is optimized in `lexical`. impl str::FromStr for f16 { type Err = num::ParseFloatError; fn from_str(src: &str) -> Result { f32::from_str(src).map(f16::from_f32) } } impl fmt::Debug for f16 { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> { fmt::Debug::fmt(&self.as_f32(), f) } } impl fmt::Display for f16 { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> { fmt::Display::fmt(&self.as_f32(), f) } } impl fmt::LowerExp for f16 { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> { write!(f, "{:e}", self.as_f32()) } } impl fmt::UpperExp for f16 { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> { write!(f, "{:E}", self.as_f32()) } } impl fmt::Binary for f16 { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> { write!(f, "{:b}", self.0) } } impl fmt::Octal for f16 { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> { write!(f, "{:o}", self.0) } } impl fmt::LowerHex for f16 { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> { write!(f, "{:x}", self.0) } } impl fmt::UpperHex for f16 { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> { write!(f, "{:X}", self.0) } } impl Product for f16 { #[inline(always)] fn product>(iter: I) -> Self { product_f16(iter.map(|f| f.to_bits())) } } impl<'a> Product<&'a f16> for f16 { #[inline] fn product>(iter: I) -> Self { product_f16(iter.map(|f| f.to_bits())) } } impl Sum for f16 { #[inline] fn sum>(iter: I) -> Self { sum_f16(iter.map(|f| f.to_bits())) } } impl<'a> Sum<&'a f16> for f16 { #[inline] fn sum>(iter: I) -> Self { sum_f16(iter.map(|f| f.to_bits())) } } from_impl!(f16, u8, from_u8); from_impl!(f16, u16, from_u16); from_impl!(f16, u32, from_u32); from_impl!(f16, u64, from_u64); from_impl!(f16, u128, from_u128); from_impl!(f16, i8, from_i8); from_impl!(f16, i16, from_i16); from_impl!(f16, i32, from_i32); from_impl!(f16, i64, from_i64); from_impl!(f16, i128, from_i128); from_impl!(f16, f64, from_f64); // In the below functions, round to nearest, with ties to even. // Let us call the most significant bit that will be shifted out the round_bit. // // Round up if either // a) Removed part > tie. // (mantissa & round_bit) != 0 && (mantissa & (round_bit - 1)) != 0 // b) Removed part == tie, and retained part is odd. // (mantissa & round_bit) != 0 && (mantissa & (2 * round_bit)) != 0 // (If removed part == tie and retained part is even, do not round up.) // These two conditions can be combined into one: // (mantissa & round_bit) != 0 && (mantissa & ((round_bit - 1) | (2 * // round_bit))) != 0 which can be simplified into // (mantissa & round_bit) != 0 && (mantissa & (3 * round_bit - 1)) != 0 #[must_use] #[inline] const fn f16_to_f32(half: f16) -> f32 { let man_shift = f32::MANTISSA_SIZE - f16::MANTISSA_SIZE; let f16_bias = f16::EXPONENT_BIAS - f16::MANTISSA_SIZE; let f32_bias = f32::EXPONENT_BIAS - f32::MANTISSA_SIZE; // Check for signed zero if half.0 & (f16::SIGN_MASK - 1) == 0 { return f32_from_bits((half.0 as u32) << 16); } let half_sign = (half.0 & f16::SIGN_MASK) as u32; let half_exp = (half.0 & f16::EXPONENT_MASK) as u32; let half_man = (half.0 & f16::MANTISSA_MASK) as u32; if half.is_nan() { return f32_from_bits((half_sign << 16) | 0x7FC0_0000u32 | (half_man << man_shift)); } else if half.is_infinite() { return f32_from_bits((half_sign << 16) | f32::INFINITY_BITS); } // Calculate single-precision components with adjusted exponent let sign = half_sign << 16; // Unbias exponent let unbiased_exp = ((half_exp as i32) >> f16::MANTISSA_SIZE) - f16_bias; // Check for subnormals, which will be normalized by adjusting exponent if half_exp == 0 { // Calculate how much to adjust the exponent by let e = (half_man as u16).leading_zeros() - (16 - f16::MANTISSA_SIZE as u32); // Rebias and adjust exponent let exp = (f32_bias as u32 - f16_bias as u32 - e) << f32::MANTISSA_SIZE; let man = (half_man << (f16_bias as u32 - 1 + e)) & f32::MANTISSA_MASK; return f32_from_bits(sign | exp | man); } // Rebias exponent for a normalized normal let exp = ((unbiased_exp + f32_bias) as u32) << f32::MANTISSA_SIZE; let man = (half_man & f16::MANTISSA_MASK as u32) << man_shift; f32_from_bits(sign | exp | man) } #[must_use] #[inline] const fn f32_to_f16(value: f32) -> f16 { let man_shift = f32::MANTISSA_SIZE - f16::MANTISSA_SIZE; let f16_bias = f16::EXPONENT_BIAS - f16::MANTISSA_SIZE; let f32_bias = f32::EXPONENT_BIAS - f32::MANTISSA_SIZE; // Convert to raw bytes let x = f32_to_bits(value); // Extract IEEE754 components let sign = x & f32::SIGN_MASK; let exp = x & f32::EXPONENT_MASK; let man = x & f32::MANTISSA_MASK; // Check for all exponent bits being set, which is Infinity or NaN if f32_is_nan(value) { return f16::from_bits((sign >> 16) as u16 | 0x7e00 | (man >> man_shift) as u16); } else if f32_is_infinite(value) { return f16::from_bits((sign >> 16) as u16 | f16::INFINITY_BITS); } // The number is normalized, start assembling half precision version let half_sign = sign >> 16; // Unbias the exponent, then bias for half precision let unbiased_exp = ((exp >> f32::MANTISSA_SIZE) as i32) - f32_bias; let half_exp = unbiased_exp + f16_bias; // Check for exponent overflow, return +infinity if unbiased_exp >= 0x1F { return f16::from_bits(half_sign as u16 | f16::INFINITY_BITS); } // Check for underflow if half_exp <= 0 { // Check mantissa for what we can do if f16_bias - 1 - half_exp > f32::MANTISSA_SIZE + 1 { // No rounding possibility, so this is a full underflow, return signed zero return f16::from_bits(half_sign as u16); } // Don't forget about hidden leading mantissa bit when assembling mantissa let man = man | f32::HIDDEN_BIT_MASK; let mut half_man = man >> (f16_bias - 1 - half_exp); // Check for rounding (see comment above functions) let round_bit = 1 << (man_shift - half_exp); if (man & round_bit) != 0 && (man & (3 * round_bit - 1)) != 0 { half_man += 1; } // No exponent for subnormals return f16::from_bits((half_sign | half_man) as u16); } // Rebias the exponent let half_exp = (half_exp as u32) << f16::MANTISSA_SIZE; let half_man = man >> man_shift; let round_bit = 1 << (man_shift - 1); if (man & round_bit) != 0 && (man & (3 * round_bit - 1)) != 0 { // Round it f16::from_bits(((half_sign | half_exp | half_man) + 1) as u16) } else { f16::from_bits((half_sign | half_exp | half_man) as u16) } } // Private functions for const expr. #[must_use] #[inline(always)] const fn eq(lhs: f16, rhs: f16) -> bool { // NOTE: This optimizes identically at opt levels 1+ to asm // https://godbolt.org/z/bW7s7o5M6 if lhs.is_nan() { false } else if lhs.to_bits() & !f16::SIGN_MASK == 0 { rhs.to_bits() & !f16::SIGN_MASK == 0 } else { lhs.to_bits() == rhs.to_bits() } } #[must_use] #[inline(always)] fn partial_cmp(lhs: f16, rhs: f16) -> Option { if lhs.is_nan() || rhs.is_nan() { None } else { let neg = lhs.0 & 0x8000u16 != 0; let rhs_neg = rhs.0 & 0x8000u16 != 0; match (neg, rhs_neg) { (false, false) => Some(lhs.0.cmp(&rhs.0)), (false, true) => { if (lhs.0 | rhs.0) & 0x7FFFu16 == 0 { Some(Ordering::Equal) } else { Some(Ordering::Greater) } }, (true, false) => { if (lhs.0 | rhs.0) & 0x7FFFu16 == 0 { Some(Ordering::Equal) } else { Some(Ordering::Less) } }, (true, true) => Some(rhs.0.cmp(&lhs.0)), } } } #[must_use] #[inline(always)] const fn lt(lhs: f16, rhs: f16) -> bool { if lhs.is_nan() || rhs.is_nan() { false } else { let neg = lhs.0 & 0x8000u16 != 0; let rhs_neg = rhs.0 & 0x8000u16 != 0; match (neg, rhs_neg) { (false, false) => lhs.0 < rhs.0, (false, true) => false, (true, false) => (lhs.0 | rhs.0) & 0x7FFFu16 != 0, (true, true) => lhs.0 > rhs.0, } } } #[must_use] #[inline(always)] const fn le(lhs: f16, rhs: f16) -> bool { if lhs.is_nan() || rhs.is_nan() { false } else { let neg = lhs.0 & 0x8000u16 != 0; let rhs_neg = rhs.0 & 0x8000u16 != 0; match (neg, rhs_neg) { (false, false) => lhs.0 <= rhs.0, (false, true) => (lhs.0 | rhs.0) & 0x7FFFu16 == 0, (true, false) => true, (true, true) => lhs.0 >= rhs.0, } } } #[must_use] #[inline(always)] const fn gt(lhs: f16, rhs: f16) -> bool { if lhs.is_nan() || rhs.is_nan() { false } else { let neg = lhs.0 & 0x8000u16 != 0; let rhs_neg = rhs.0 & 0x8000u16 != 0; match (neg, rhs_neg) { (false, false) => lhs.0 > rhs.0, (false, true) => (lhs.0 | rhs.0) & 0x7FFFu16 != 0, (true, false) => false, (true, true) => lhs.0 < rhs.0, } } } #[must_use] #[inline(always)] const fn ge(lhs: f16, rhs: f16) -> bool { if lhs.is_nan() || rhs.is_nan() { false } else { let neg = lhs.0 & 0x8000u16 != 0; let rhs_neg = rhs.0 & 0x8000u16 != 0; match (neg, rhs_neg) { (false, false) => lhs.0 >= rhs.0, (false, true) => true, (true, false) => (lhs.0 | rhs.0) & 0x7FFFu16 == 0, (true, true) => lhs.0 <= rhs.0, } } } #[must_use] #[inline(always)] const fn f32_is_special(v: f32) -> bool { f32_to_bits(v) & f32::EXPONENT_MASK == f32::EXPONENT_MASK } #[must_use] #[inline(always)] const fn f32_is_nan(v: f32) -> bool { f32_is_special(v) && (f32_to_bits(v) & f32::MANTISSA_MASK) != 0 } #[must_use] #[inline(always)] const fn f32_is_infinite(v: f32) -> bool { f32_is_special(v) && (f32_to_bits(v) & f32::MANTISSA_MASK) == 0 } // NOTE: taken from the core implementation. #[must_use] #[inline(always)] const fn f32_from_bits(v: u32) -> f32 { // SAFETY: The type is POD unsafe { mem::transmute(v) } } #[must_use] #[inline(always)] const fn f32_to_bits(v: f32) -> u32 { // SAFETY: The type is POD unsafe { mem::transmute(v) } } #[must_use] #[inline(always)] const fn u16_to_f32(v: u16) -> f32 { f16_to_f32(f16(v)) } #[must_use] #[inline(always)] fn product_f16>(iter: I) -> f16 { f32_to_f16(iter.map(u16_to_f32).product()) } #[must_use] #[inline(always)] fn sum_f16>(iter: I) -> f16 { f32_to_f16(iter.map(u16_to_f32).sum()) } lexical-util-1.0.6/src/feature_format.rs000064400000000000000000002470001046102023000163670ustar 00000000000000//! Configuration options for parsing and formatting numbers. //! //! This comprises 2 parts: a low-level API for generating packed structs //! containing enumerating for number formats (both syntax and lexer). //! //! # Syntax Format //! //! The syntax format defines **which** numeric string are valid. //! For example, if exponent notation is required or not //! allowed. //! //! # Control Format //! //! The control format defines what characters are valid, that is, which //! characters should be consider valid to continue tokenization. #![cfg(feature = "format")] // Sample test code for each language used: // // Rust // ---- // // Setup: // Save to `main.rs` and run `rustc main.rs -o main`. // // Code: // ```text // pub fn main() { // println!("{:?}", 3_.0f32); // println!("{:?}", "3_.0".parse::()); // } // ``` // // Python // ------ // // Setup: // Run `python` to enter the interpreter. // // Code: // ```text // print(3_.0) // print(float("3_.0")) // ``` // // C++ // --- // // Setup: // Save to `main.cc` and run `g++ main.cc -o main -std=c++XX`, // where XX is one of the following values: // - 98 // - 03 // - 11 // - 14 // - 17 // // Code: // ```text // #include // #include // #include // #include // #include // // double parse(const char* string) { // char* end; // double result = strtod(string, &end); // auto endp = reinterpret_cast(end); // if (std::distance(string, endp) != strlen(string)) { // throw std::invalid_argument("did not consume entire string."); // } // return result; // } // // int main() { // std::cout << 3'.0 << std::endl; // std::cout << parse("3'.0") << std::endl; // } // ``` // // C // - // // Setup: // Save to `main.c` and run `gcc main.c -o main -std=cXX`, // where XX is one of the following values: // - 89 // - 90 // - 99 // - 11 // - 18 // // Code: // ```text // #include // #include // #include // #include // // size_t distance(const char* first, const char* last) { // uintptr_t x = (uintptr_t) first; // uintptr_t y = (uintptr_t) last; // return (size_t) (y - x); // } // // double parse(const char* string) { // char* end; // double result = strtod(string, &end); // if (distance(string, (const char*) end) != strlen(string)) { // abort(); // } // return result; // } // // int main() { // printf("%f\n", 3'.); // printf("%f\n", parse("3'.")); // } // ``` // // Ruby // ---- // // Setup: // Run `irb` to enter the interpreter. // // Code: // ```text // puts 3.0_1; // puts "3.0_1".to_f; // ``` // Swift // ----- // // Setup: // Run `swift` to enter the interpreter. // // Code: // ```text // print(3.0); // print(Float("3.0")); // ``` // Golang // ------ // // Setup: // Save to `main.go` and run `go run main.go` // // Code: // ```text // package main // // import ( // "fmt" // "strconv" // ) // // func main() { // fmt.Println(3.0) // fmt.Println(strconv.ParseFloat("3.0", 64)) // } // ``` // // Haskell // ------- // // Setup: // Run `ghci` to enter the interpreter. // // Code: // ```text // :m Numeric // showFloat 3.0 "" // let x = "3.0" // read x :: Float // ``` // // Javascript // ---------- // // Setup: // Run `nodejs` (or `node`) to enter the interpreter. // // Code: // ```text // console.log(3.0) // console.log(parseFloat("3.0")) // ``` // // Perl // ---- // // Setup: // Run `perl -de1` to enter the interpret. // // Code: // ```text // print 3.01; // print '3.01' * 1; // ``` // // PHP // --- // // Setup: // Run `php -a` to enter the interpret. // // Code: // ```text // printf("%f\n", 3.0); // printf("%f\n", floatval("3.0")); // ``` // // Java // ---- // // Setup: // Save to `main.java` and run `javac main.java`, then run `java Main`. // // Code: // ```text // class Main { // public static void main(String args[]) { // System.out.println(3.0); // System.out.println(Float.parseFloat("3.0")); // } // } // ``` // // R // - // // Setup: // Run `R` to enter the interpret. // // Code: // ```text // print(3.0); // print(as.numeric("3.0")); // ``` // // Kotlin // ------ // // Setup: // Save file to `main.kt` and run `kotlinc main.kt -d main.jar`, // then run `java -jar main.jar`. // // Code: // ```text // fun main() { // println(3.0) // println("3.0".toDouble()) // } // ``` // // Julia // ----- // // Setup: // Run `julia` to enter the interpret. // // Code: // ```text // print(3.0); // print(parse(Float64, "3.0")); // ``` // // C# // -- // // Note: // Mono accepts both integer and fraction decimal separators, Mono is // just buggy, see https://github.com/dotnet/csharplang/issues/55#issuecomment-574902516. // // Setup: // Run `csharp -langversion:X` to enter the interpret, // where XX is one of the following values: // - ISO-1 // - ISO-2 // - 3 // - 4 // - 5 // - 6 // - 7 // // Code: // ```text // Console.WriteLine("{0}", 3.0); // Console.WriteLine("{0}", float.Parse("3.0")); // ``` // // Kawa // ---- // // Setup: // Run `kawa` to enter the interpreter. // // Code: // ```text // 3.0 // (string->number "3.0") // ``` // // Gambit-C // -------- // // Setup: // Run `gsc` to enter the interpreter. // // Code: // ```text // 3.0 // (string->number "3.0") // ``` // // Guile // ----- // // Setup: // Run `guile` to enter the interpreter. // // Code: // ```text // 3.0 // (string->number "3.0") // ``` // // Clojure // ------- // // Setup: // Run `clojure` to enter the interpreter. // // Code: // ```text // 3.0 // (Float/parseFloat "3.0") // ``` // // Erlang // ------ // // Setup: // Run `erl` to enter the interpreter. // // Code: // ```text // io:format("~p~n", [3.0]). // string:to_float("3.0"). // ``` // // Elm // --- // // Setup: // Run `elm repl` to enter the interpreter. // // Code: // ```text // 3.0 // String.toFloat "3.0" // ``` // // Scala // ----- // // Setup: // Run `scala` to enter the interpreter. // // Code: // ```text // 3.0 // "3.0".toFloat // ``` // // Elixir // ------ // // Setup: // Run `iex` to enter the interpreter. // // Code: // ```text // 3.0; // String.to_float("3.0"); // ``` // // FORTRAN // ------- // // Setup: // Save to `main.f90` and run `gfortran -o main main.f90` // // Code: // ```text // program main // real :: x // character (len=30) :: word // word = "3." // read(word, *) x // print *, 3. // print *, x // end program main // ``` // // D // - // // Setup: // Save to `main.d` and run `dmd -run main.d` // // Code: // ```text // import std.conv; // import std.stdio; // // void main() // { // writeln(3.0); // writeln(to!double("3.0")); // } // ``` // // Coffeescript // ------------ // // Setup: // Run `coffee` to enter the interpreter. // // Code: // ```text // 3.0; // parseFloat("3.0"); // ``` // // Cobol // ----- // // Setup: // Save to `main.cbl` and run `cobc main.cbl` then `cobcrun main`. // // Code: // ```text // IDENTIFICATION DIVISION. // PROGRAM-ID. main. // // DATA DIVISION. // WORKING-STORAGE SECTION. // 01 R PIC X(20) VALUE "3.0". // 01 TOTAL USAGE IS COMP-2. // // PROCEDURE DIVISION. // COMPUTE TOTAL = FUNCTION NUMVAL(R). // Display 3.0. // Display TOTAL. // STOP RUN. // ``` // // F# // -- // // Setup: // Run `dotnet fsi` to enter the interpreter. // // Code: // ```text // printfn "%f" 3.0;; // let f = float "3.0";; // printfn "%f" f;; // ``` // // Visual Basic // ------------ // // Setup: // Save to `main.vb` and run `vbnc main.vb`. // // Code: // ```text // Imports System // // Module Module1 // Sub Main() // Console.WriteLine(Format$(3.0, "0.0000000000000")) // Console.WriteLine(Format$(CDbl("3.0"), "0.0000000000000")) // End Sub // End Module // ``` // // OCaml // ----- // // Setup: // Save to `main.ml` and run `ocamlc -o main main.ml`. // // Code: // ```text // Printf.printf "%f\n" 3.0 // let () = // let f = float_of_string "3.0" in // Printf.printf "%f\n" f // ``` // // Objective-C // ----------- // // Setup: // Save to `main.m` and run `gcc -o main -lobjc -lgnustep-base main.m // -fconstant-string-class=NSConstantString`. // // Code: // ```text // #import // #import // // int main(int argv, char* argc[]) // { // printf("%f\n", 3.0); // NSString *s = @"3.0"; // double f = [s doubleValue]; // printf("%f\n", f); // } // ``` // // ReasonML // -------- // // Setup: // Run `rtop` to enter the interpreter. // // Code: // ```text // Printf.printf("%f\n", 3.0); // Printf.printf("%f\n", float_of_string("3.0")); // ``` // // Zig // --- // // Setup: // Save to `main.zig` and run `zig build-exe main.zig` // // Code: // ```text // const std = @import("std"); // // pub fn main() void { // const f: f64 = 3.0; // std.debug.warn("{}\n", f); // const x: f64 = std.fmt.parseFloat(f64, "3.0") catch unreachable; // std.debug.warn("{}\n", x); // } // ``` // // // Octave (and Matlab) // ------------------- // // Setup: // Run `octave` to enter the interpreter, or // run `octave --traditional` to enter the Matlab interpret. // // Code: // ```text // 3.0 // str2double("3.0") // ``` // // Sage // ---- // // Setup: // Run `sage` to enter the interpreter. // // Code: // ```text // 3.0 // float("3.0") // ``` // // JSON // ---- // // Setup: // Run `node` (or `nodejs`) to enter the JS interpreter. // // Code: // ```text // JSON.parse("3.0") // ``` // // TOML // ---- // // Setup: // Run `python` to enter the Python interpreter. // // Code: // ```text // import tomlkit // tomlkit.parse("a = 3.0") // ``` // // XML // --- // // Setup: // Run `python` to enter the Python interpreter. // // Code: // ```text // from lxml import etree // // def validate_xml(xsd, xml): // '''Validate XML file against schema''' // // schema = etree.fromstring(xsd) // doc = etree.fromstring(xml) // xmlschema = etree.XMLSchema(schema) // // return xmlschema.validate(doc) // // // xsd = b''' // // // ''' // // xml = b''' // 3.0 // ''' // // validate_xml(xsd, xml) // ``` // // SQLite // ------ // // Setup: // Run `sqlite3 :memory:` to enter the sqlite3 interpreter // with an in-memory database. // // Code: // ```text // CREATE TABLE stocks (price real); // INSERT INTO stocks VALUES (3.0); // SELECT * FROM stocks; // ``` // // PostgreSQL // ---------- // // Setup: // Run `initdb -D db` to create a database data direction, // then run `pg_ctl -D db start` to start the server, then run // `createdb` to create a user database and `psql` to start the // interpreter. // // Code: // ```text // CREATE TABLE stocks (price real); // INSERT INTO stocks VALUES (3.0); // SELECT * FROM stocks; // ``` // // MySQL // ----- // // Setup: // Run `mysqld` to start the server, then run `mysql` to start the // interpreter. // // Code: // ```text // USE mysql; // CREATE TABLE stocks (price real); // INSERT INTO stocks VALUES (3.0); // SELECT * FROM stocks; // ``` // // MongoDB // ------- // // Setup: // Run `mongod --dbpath data/db` to start the server, then run // `mongo` to start the interpreter. // // Code: // ```text // use mydb // db.movie.insert({"name": 3.0}) // db.movie.find() // ``` use core::num; use static_assertions::const_assert; use crate::error::Error; use crate::format_builder::NumberFormatBuilder; use crate::format_flags as flags; /// Add multiple flags to `SyntaxFormat`. macro_rules! from_flag { ($format:ident, $flag:ident) => {{ $format & flags::$flag != 0 }}; } /// Wrapper for the 128-bit packed struct. /// /// See `NumberFormatBuilder` for the `FORMAT` fields /// for the packed struct. #[doc(hidden)] pub struct NumberFormat; #[rustfmt::skip] impl NumberFormat { // CONSTRUCTORS /// Create new instance (for methods and validation). pub const fn new() -> Self { Self {} } // VALIDATION /// Determine if the number format is valid. pub const fn is_valid(&self) -> bool { self.error().is_success() } /// Get the error type from the format. #[allow(clippy::if_same_then_else)] // reason="all are different logic conditions" pub const fn error(&self) -> Error { if !flags::is_valid_radix(self.mantissa_radix()) { Error::InvalidMantissaRadix } else if !flags::is_valid_radix(self.exponent_base()) { Error::InvalidExponentBase } else if !flags::is_valid_radix(self.exponent_radix()) { Error::InvalidExponentRadix } else if !flags::is_valid_digit_separator(FORMAT) { Error::InvalidDigitSeparator } else if !flags::is_valid_base_prefix(FORMAT) { Error::InvalidBasePrefix } else if !flags::is_valid_base_suffix(FORMAT) { Error::InvalidBaseSuffix } else if !flags::is_valid_punctuation(FORMAT) { Error::InvalidPunctuation } else if !flags::is_valid_exponent_flags(FORMAT) { Error::InvalidExponentFlags } else if self.no_positive_mantissa_sign() && self.required_mantissa_sign() { Error::InvalidMantissaSign } else if self.no_positive_exponent_sign() && self.required_exponent_sign() { Error::InvalidExponentSign } else if self.no_special() && self.case_sensitive_special() { Error::InvalidSpecial } else if self.no_special() && self.special_digit_separator() { Error::InvalidSpecial } else if self.integer_digit_separator_flags() == flags::INTEGER_CONSECUTIVE_DIGIT_SEPARATOR { Error::InvalidConsecutiveIntegerDigitSeparator } else if self.fraction_digit_separator_flags() == flags::FRACTION_CONSECUTIVE_DIGIT_SEPARATOR { Error::InvalidConsecutiveFractionDigitSeparator } else if self.exponent_digit_separator_flags() == flags::EXPONENT_CONSECUTIVE_DIGIT_SEPARATOR { Error::InvalidConsecutiveExponentDigitSeparator } else { Error::Success } } // NON-DIGIT SEPARATOR FLAGS & MASKS /// If digits are required before the decimal point. pub const REQUIRED_INTEGER_DIGITS: bool = from_flag!(FORMAT, REQUIRED_INTEGER_DIGITS); /// Get if digits are required before the decimal point. #[inline(always)] pub const fn required_integer_digits(&self) -> bool { Self::REQUIRED_INTEGER_DIGITS } /// If digits are required after the decimal point. pub const REQUIRED_FRACTION_DIGITS: bool = from_flag!(FORMAT, REQUIRED_FRACTION_DIGITS); /// Get if digits are required after the decimal point. #[inline(always)] pub const fn required_fraction_digits(&self) -> bool { Self::REQUIRED_FRACTION_DIGITS } /// If digits are required after the exponent character. pub const REQUIRED_EXPONENT_DIGITS: bool = from_flag!(FORMAT, REQUIRED_EXPONENT_DIGITS); /// Get if digits are required after the exponent character. #[inline(always)] pub const fn required_exponent_digits(&self) -> bool { Self::REQUIRED_EXPONENT_DIGITS } /// If significant digits are required. pub const REQUIRED_MANTISSA_DIGITS: bool = from_flag!(FORMAT, REQUIRED_MANTISSA_DIGITS); /// Get if significant digits are required. #[inline(always)] pub const fn required_mantissa_digits(&self) -> bool { Self::REQUIRED_MANTISSA_DIGITS } /// If at least 1 digit in the number is required. pub const REQUIRED_DIGITS: bool = from_flag!(FORMAT, REQUIRED_DIGITS); /// Get if at least 1 digit in the number is required. #[inline(always)] pub const fn required_digits(&self) -> bool { Self::REQUIRED_DIGITS } /// If a positive sign before the mantissa is not allowed. pub const NO_POSITIVE_MANTISSA_SIGN: bool = from_flag!(FORMAT, NO_POSITIVE_MANTISSA_SIGN); /// Get if a positive sign before the mantissa is not allowed. #[inline(always)] pub const fn no_positive_mantissa_sign(&self) -> bool { Self::NO_POSITIVE_MANTISSA_SIGN } /// If a sign symbol before the mantissa is required. pub const REQUIRED_MANTISSA_SIGN: bool = from_flag!(FORMAT, REQUIRED_MANTISSA_SIGN); /// Get if a sign symbol before the mantissa is required. #[inline(always)] pub const fn required_mantissa_sign(&self) -> bool { Self::REQUIRED_MANTISSA_SIGN } /// If exponent notation is not allowed. pub const NO_EXPONENT_NOTATION: bool = from_flag!(FORMAT, NO_EXPONENT_NOTATION); /// Get if exponent notation is not allowed. #[inline(always)] pub const fn no_exponent_notation(&self) -> bool { Self::NO_EXPONENT_NOTATION } /// If a positive sign before the exponent is not allowed. pub const NO_POSITIVE_EXPONENT_SIGN: bool = from_flag!(FORMAT, NO_POSITIVE_EXPONENT_SIGN); /// Get if a positive sign before the exponent is not allowed. #[inline(always)] pub const fn no_positive_exponent_sign(&self) -> bool { Self::NO_POSITIVE_EXPONENT_SIGN } /// If a sign symbol before the exponent is required. pub const REQUIRED_EXPONENT_SIGN: bool = from_flag!(FORMAT, REQUIRED_EXPONENT_SIGN); /// Get if a sign symbol before the exponent is required. #[inline(always)] pub const fn required_exponent_sign(&self) -> bool { Self::REQUIRED_EXPONENT_SIGN } /// If an exponent without fraction is not allowed. pub const NO_EXPONENT_WITHOUT_FRACTION: bool = from_flag!(FORMAT, NO_EXPONENT_WITHOUT_FRACTION); /// Get if an exponent without fraction is not allowed. #[inline(always)] pub const fn no_exponent_without_fraction(&self) -> bool { Self::NO_EXPONENT_WITHOUT_FRACTION } /// If special (non-finite) values are not allowed. pub const NO_SPECIAL: bool = from_flag!(FORMAT, NO_SPECIAL); /// Get if special (non-finite) values are not allowed. #[inline(always)] pub const fn no_special(&self) -> bool { Self::NO_SPECIAL } /// If special (non-finite) values are case-sensitive. pub const CASE_SENSITIVE_SPECIAL: bool = from_flag!(FORMAT, CASE_SENSITIVE_SPECIAL); /// Get if special (non-finite) values are case-sensitive. #[inline(always)] pub const fn case_sensitive_special(&self) -> bool { Self::CASE_SENSITIVE_SPECIAL } /// If leading zeros before an integer are not allowed. pub const NO_INTEGER_LEADING_ZEROS: bool = from_flag!(FORMAT, NO_INTEGER_LEADING_ZEROS); /// Get if leading zeros before an integer are not allowed. #[inline(always)] pub const fn no_integer_leading_zeros(&self) -> bool { Self::NO_INTEGER_LEADING_ZEROS } /// If leading zeros before a float are not allowed. pub const NO_FLOAT_LEADING_ZEROS: bool = from_flag!(FORMAT, NO_FLOAT_LEADING_ZEROS); /// Get if leading zeros before a float are not allowed. #[inline(always)] pub const fn no_float_leading_zeros(&self) -> bool { Self::NO_FLOAT_LEADING_ZEROS } /// If exponent notation is required. pub const REQUIRED_EXPONENT_NOTATION: bool = from_flag!(FORMAT, REQUIRED_EXPONENT_NOTATION); /// Get if exponent notation is required. #[inline(always)] pub const fn required_exponent_notation(&self) -> bool { Self::REQUIRED_EXPONENT_NOTATION } /// If exponent characters are case-sensitive. pub const CASE_SENSITIVE_EXPONENT: bool = from_flag!(FORMAT, CASE_SENSITIVE_EXPONENT); /// Get if exponent characters are case-sensitive. #[inline(always)] pub const fn case_sensitive_exponent(&self) -> bool { Self::CASE_SENSITIVE_EXPONENT } /// If base prefixes are case-sensitive. pub const CASE_SENSITIVE_BASE_PREFIX: bool = from_flag!(FORMAT, CASE_SENSITIVE_BASE_PREFIX); /// Get if base prefixes are case-sensitive. #[inline(always)] pub const fn case_sensitive_base_prefix(&self) -> bool { Self::CASE_SENSITIVE_BASE_PREFIX } /// If base suffixes are case-sensitive. pub const CASE_SENSITIVE_BASE_SUFFIX: bool = from_flag!(FORMAT, CASE_SENSITIVE_BASE_SUFFIX); /// Get if base suffixes are case-sensitive. #[inline(always)] pub const fn case_sensitive_base_suffix(&self) -> bool { Self::CASE_SENSITIVE_BASE_SUFFIX } // DIGIT SEPARATOR FLAGS & MASKS // If digit separators are allowed between integer digits. /// /// This will not consider an input of only the digit separator /// to be a valid separator: the digit separator must be surrounded by /// digits. pub const INTEGER_INTERNAL_DIGIT_SEPARATOR: bool = from_flag!(FORMAT, INTEGER_INTERNAL_DIGIT_SEPARATOR); /// Get if digit separators are allowed between integer digits. /// /// This will not consider an input of only the digit separator /// to be a valid separator: the digit separator must be surrounded by /// digits. #[inline(always)] pub const fn integer_internal_digit_separator(&self) -> bool { Self::INTEGER_INTERNAL_DIGIT_SEPARATOR } /// If digit separators are allowed between fraction digits. /// /// This will not consider an input of only the digit separator /// to be a valid separator: the digit separator must be surrounded by /// digits. pub const FRACTION_INTERNAL_DIGIT_SEPARATOR: bool = from_flag!(FORMAT, FRACTION_INTERNAL_DIGIT_SEPARATOR); /// Get if digit separators are allowed between fraction digits. /// /// This will not consider an input of only the digit separator /// to be a valid separator: the digit separator must be surrounded by /// digits. #[inline(always)] pub const fn fraction_internal_digit_separator(&self) -> bool { Self::FRACTION_INTERNAL_DIGIT_SEPARATOR } /// If digit separators are allowed between exponent digits. /// /// This will not consider an input of only the digit separator /// to be a valid separator: the digit separator must be surrounded by /// digits. pub const EXPONENT_INTERNAL_DIGIT_SEPARATOR: bool = from_flag!(FORMAT, EXPONENT_INTERNAL_DIGIT_SEPARATOR); /// Get if digit separators are allowed between exponent digits. /// /// This will not consider an input of only the digit separator /// to be a valid separator: the digit separator must be surrounded by /// digits. #[inline(always)] pub const fn exponent_internal_digit_separator(&self) -> bool { Self::EXPONENT_INTERNAL_DIGIT_SEPARATOR } /// If digit separators are allowed between digits. /// /// This will not consider an input of only the digit separator /// to be a valid separator: the digit separator must be surrounded by /// digits. pub const INTERNAL_DIGIT_SEPARATOR: bool = from_flag!(FORMAT, INTERNAL_DIGIT_SEPARATOR); /// Get if digit separators are allowed between digits. /// /// This will not consider an input of only the digit separator /// to be a valid separator: the digit separator must be surrounded by /// digits. #[inline(always)] pub const fn internal_digit_separator(&self) -> bool { Self::INTERNAL_DIGIT_SEPARATOR } /// If a digit separator is allowed before any integer digits. /// /// This will consider an input of only the digit separator /// to be a identical to empty input. pub const INTEGER_LEADING_DIGIT_SEPARATOR: bool = from_flag!(FORMAT, INTEGER_LEADING_DIGIT_SEPARATOR); /// Get if a digit separator is allowed before any integer digits. /// /// This will consider an input of only the digit separator /// to be a identical to empty input. #[inline(always)] pub const fn integer_leading_digit_separator(&self) -> bool { Self::INTEGER_LEADING_DIGIT_SEPARATOR } /// If a digit separator is allowed before any integer digits. /// /// This will consider an input of only the digit separator /// to be a identical to empty input. pub const FRACTION_LEADING_DIGIT_SEPARATOR: bool = from_flag!(FORMAT, FRACTION_LEADING_DIGIT_SEPARATOR); /// Get if a digit separator is allowed before any fraction digits. /// /// This will consider an input of only the digit separator /// to be a identical to empty input. #[inline(always)] pub const fn fraction_leading_digit_separator(&self) -> bool { Self::FRACTION_LEADING_DIGIT_SEPARATOR } /// If a digit separator is allowed before any exponent digits. /// /// This will consider an input of only the digit separator /// to be a identical to empty input. pub const EXPONENT_LEADING_DIGIT_SEPARATOR: bool = from_flag!(FORMAT, EXPONENT_LEADING_DIGIT_SEPARATOR); /// Get if a digit separator is allowed before any exponent digits. /// /// This will consider an input of only the digit separator /// to be a identical to empty input. #[inline(always)] pub const fn exponent_leading_digit_separator(&self) -> bool { Self::EXPONENT_LEADING_DIGIT_SEPARATOR } /// If a digit separator is allowed before any digits. /// /// This will consider an input of only the digit separator /// to be a identical to empty input. pub const LEADING_DIGIT_SEPARATOR: bool = from_flag!(FORMAT, LEADING_DIGIT_SEPARATOR); /// Get if a digit separator is allowed before any digits. /// /// This will consider an input of only the digit separator /// to be a identical to empty input. #[inline(always)] pub const fn leading_digit_separator(&self) -> bool { Self::LEADING_DIGIT_SEPARATOR } /// If a digit separator is allowed after any integer digits. /// /// This will consider an input of only the digit separator /// to be a identical to empty input. pub const INTEGER_TRAILING_DIGIT_SEPARATOR: bool = from_flag!(FORMAT, INTEGER_TRAILING_DIGIT_SEPARATOR); /// Get if a digit separator is allowed after any integer digits. /// /// This will consider an input of only the digit separator /// to be a identical to empty input. #[inline(always)] pub const fn integer_trailing_digit_separator(&self) -> bool { Self::INTEGER_TRAILING_DIGIT_SEPARATOR } /// If a digit separator is allowed after any fraction digits. /// /// This will consider an input of only the digit separator /// to be a identical to empty input. pub const FRACTION_TRAILING_DIGIT_SEPARATOR: bool = from_flag!(FORMAT, FRACTION_TRAILING_DIGIT_SEPARATOR); /// Get if a digit separator is allowed after any fraction digits. /// /// This will consider an input of only the digit separator /// to be a identical to empty input. #[inline(always)] pub const fn fraction_trailing_digit_separator(&self) -> bool { Self::FRACTION_TRAILING_DIGIT_SEPARATOR } /// If a digit separator is allowed after any exponent digits. /// /// This will consider an input of only the digit separator /// to be a identical to empty input. pub const EXPONENT_TRAILING_DIGIT_SEPARATOR: bool = from_flag!(FORMAT, EXPONENT_TRAILING_DIGIT_SEPARATOR); /// Get if a digit separator is allowed after any exponent digits. /// /// This will consider an input of only the digit separator /// to be a identical to empty input. #[inline(always)] pub const fn exponent_trailing_digit_separator(&self) -> bool { Self::EXPONENT_TRAILING_DIGIT_SEPARATOR } /// If a digit separator is allowed after any digits. /// /// This will consider an input of only the digit separator /// to be a identical to empty input. pub const TRAILING_DIGIT_SEPARATOR: bool = from_flag!(FORMAT, TRAILING_DIGIT_SEPARATOR); /// Get if a digit separator is allowed after any digits. /// /// This will consider an input of only the digit separator /// to be a identical to empty input. #[inline(always)] pub const fn trailing_digit_separator(&self) -> bool { Self::TRAILING_DIGIT_SEPARATOR } /// If multiple consecutive integer digit separators are allowed. pub const INTEGER_CONSECUTIVE_DIGIT_SEPARATOR: bool = from_flag!(FORMAT, INTEGER_CONSECUTIVE_DIGIT_SEPARATOR); /// Get if multiple consecutive integer digit separators are allowed. #[inline(always)] pub const fn integer_consecutive_digit_separator(&self) -> bool { Self::INTEGER_CONSECUTIVE_DIGIT_SEPARATOR } /// If multiple consecutive fraction digit separators are allowed. pub const FRACTION_CONSECUTIVE_DIGIT_SEPARATOR: bool = from_flag!(FORMAT, FRACTION_CONSECUTIVE_DIGIT_SEPARATOR); /// Get if multiple consecutive fraction digit separators are allowed. #[inline(always)] pub const fn fraction_consecutive_digit_separator(&self) -> bool { Self::FRACTION_CONSECUTIVE_DIGIT_SEPARATOR } /// If multiple consecutive exponent digit separators are allowed. pub const EXPONENT_CONSECUTIVE_DIGIT_SEPARATOR: bool = from_flag!(FORMAT, EXPONENT_CONSECUTIVE_DIGIT_SEPARATOR); /// Get if multiple consecutive exponent digit separators are allowed. #[inline(always)] pub const fn exponent_consecutive_digit_separator(&self) -> bool { Self::EXPONENT_CONSECUTIVE_DIGIT_SEPARATOR } /// If multiple consecutive digit separators are allowed. pub const CONSECUTIVE_DIGIT_SEPARATOR: bool = from_flag!(FORMAT, CONSECUTIVE_DIGIT_SEPARATOR); /// Get if multiple consecutive digit separators are allowed. #[inline(always)] pub const fn consecutive_digit_separator(&self) -> bool { Self::CONSECUTIVE_DIGIT_SEPARATOR } /// If any digit separators are allowed in special (non-finite) values. pub const SPECIAL_DIGIT_SEPARATOR: bool = from_flag!(FORMAT, SPECIAL_DIGIT_SEPARATOR); /// Get if any digit separators are allowed in special (non-finite) values. #[inline(always)] pub const fn special_digit_separator(&self) -> bool { Self::SPECIAL_DIGIT_SEPARATOR } // CHARACTERS /// The digit separator character in the packed struct. pub const DIGIT_SEPARATOR: u8 = flags::digit_separator(FORMAT); /// Get the digit separator character. /// /// If the digit separator is 0, digit separators are not allowed. #[inline(always)] pub const fn digit_separator(&self) -> u8 { Self::DIGIT_SEPARATOR } /// The base prefix character in the packed struct. pub const BASE_PREFIX: u8 = flags::base_prefix(FORMAT); /// Get the character for the base prefix. /// /// If the base prefix is 0, base prefixes are not allowed. /// The number will have then have the format `0$base_prefix...`. /// For example, a hex base prefix would be `0x`. Base prefixes are /// always optional. #[inline(always)] pub const fn base_prefix(&self) -> u8 { Self::BASE_PREFIX } /// Get if the format has a base suffix. #[inline(always)] pub const fn has_base_prefix(&self) -> bool { self.base_prefix() != 0 } /// The base suffix character in the packed struct. pub const BASE_SUFFIX: u8 = flags::base_suffix(FORMAT); /// Character for the base suffix. /// /// If not provided, base suffixes are not allowed. /// The number will have then have the format `...$base_suffix`. /// For example, a hex base prefix would be `0x`. Base prefixes are /// always optional. #[inline(always)] pub const fn base_suffix(&self) -> u8 { Self::BASE_SUFFIX } /// Get if the format has a base suffix. #[inline(always)] pub const fn has_base_suffix(&self) -> bool { self.base_suffix() != 0 } // RADIX /// The radix for the significant digits in the packed struct. pub const MANTISSA_RADIX: u32 = flags::mantissa_radix(FORMAT); /// Get the radix for the mantissa digits. #[inline(always)] pub const fn mantissa_radix(&self) -> u32 { Self::MANTISSA_RADIX } /// The radix for the significant digits in the packed struct. /// Alias for `MANTISSA_RADIX`. pub const RADIX: u32 = Self::MANTISSA_RADIX; /// Get the radix for the significant digits. #[inline(always)] pub const fn radix(&self) -> u32 { Self::RADIX } /// Get the radix**2 for the significant digits. #[inline(always)] pub const fn radix2(&self) -> u32 { self.radix().wrapping_mul(self.radix()) } /// Get the radix**4 for the significant digits. #[inline(always)] pub const fn radix4(&self) -> u32 { self.radix2().wrapping_mul(self.radix2()) } /// Get the radix*** for the significant digits. #[inline(always)] pub const fn radix8(&self) -> u32 { // NOTE: radix >= 16 will overflow here but this has no security concerns self.radix4().wrapping_mul(self.radix4()) } /// The base for the exponent. pub const EXPONENT_BASE: u32 = flags::exponent_base(FORMAT); /// Get the base for the exponent. /// /// IE, a base of 2 means we have `mantissa * 2^exponent`. /// If not provided, it defaults to `radix`. #[inline(always)] pub const fn exponent_base(&self) -> u32 { Self::EXPONENT_BASE } /// The radix for the exponent digits. pub const EXPONENT_RADIX: u32 = flags::exponent_radix(FORMAT); /// Get the radix for the exponent digits. /// /// If not provided, defaults to `radix`. #[inline(always)] pub const fn exponent_radix(&self) -> u32 { Self::EXPONENT_RADIX } // FLAGS /// Get the flags from the number format. #[inline(always)] pub const fn flags(&self) -> u128 { FORMAT & flags::FLAG_MASK } /// Get the interface flags from the number format. #[inline(always)] pub const fn interface_flags(&self) -> u128 { FORMAT & flags::INTERFACE_FLAG_MASK } /// Get the digit separator flags from the number format. #[inline(always)] pub const fn digit_separator_flags(&self) -> u128 { FORMAT & flags::DIGIT_SEPARATOR_FLAG_MASK } /// Get the exponent flags from the number format. #[inline(always)] pub const fn exponent_flags(&self) -> u128 { FORMAT & flags::EXPONENT_FLAG_MASK } /// Get the integer digit separator flags from the number format. #[inline(always)] pub const fn integer_digit_separator_flags(&self) -> u128 { FORMAT & flags::INTEGER_DIGIT_SEPARATOR_FLAG_MASK } /// Get the fraction digit separator flags from the number format. #[inline(always)] pub const fn fraction_digit_separator_flags(&self) -> u128 { FORMAT & flags::FRACTION_DIGIT_SEPARATOR_FLAG_MASK } /// Get the exponent digit separator flags from the number format. #[inline(always)] pub const fn exponent_digit_separator_flags(&self) -> u128 { FORMAT & flags::EXPONENT_DIGIT_SEPARATOR_FLAG_MASK } // BUILDER /// Get the number format builder from the format. #[inline(always)] pub const fn builder() -> NumberFormatBuilder { NumberFormatBuilder::new() } /// Get the number format builder from the format. #[inline(always)] pub const fn rebuild() -> NumberFormatBuilder { NumberFormatBuilder::rebuild(FORMAT) } } impl Default for NumberFormat { fn default() -> Self { Self::new() } } // PRE-DEFINED CONSTANTS // --------------------- // // Sample Format Shorthand: // ------------------------ // // The format shorthand lists the test cases, and if applicable, // the digit separator character. For example, the shorthand // `[134-_]` specifies it passes tests 1, 3, and 4, and uses // `'_'` as a digit-separator character. Meanwhile, `[0]` means it // passes test 0, and has no digit separator. // RUST LITERAL [4569ABFGHIJKMN-_] /// Number format for a `Rust` literal floating-point number. #[rustfmt::skip] pub const RUST_LITERAL: u128 = NumberFormatBuilder::new() .digit_separator(num::NonZeroU8::new(b'_')) .required_digits(true) .no_positive_mantissa_sign(true) .no_special(true) .internal_digit_separator(true) .trailing_digit_separator(true) .consecutive_digit_separator(true) .build(); const_assert!(NumberFormat::<{ RUST_LITERAL }> {}.is_valid()); // RUST STRING [0134567MN] /// Number format to parse a `Rust` float from string. #[rustfmt::skip] pub const RUST_STRING: u128 = NumberFormatBuilder::new().build(); const_assert!(NumberFormat::<{ RUST_STRING }> {}.is_valid()); /// Number format for a `Python` literal floating-point number. pub const PYTHON_LITERAL: u128 = PYTHON3_LITERAL; /// Number format to parse a `Python` float from string. pub const PYTHON_STRING: u128 = PYTHON3_STRING; /// Number format for a `Python3` literal floating-point number. pub const PYTHON3_LITERAL: u128 = PYTHON36_LITERAL; // PYTHON3 STRING [0134567MN] /// Number format to parse a `Python3` float from string. #[rustfmt::skip] pub const PYTHON3_STRING: u128 = NumberFormatBuilder::new().build(); const_assert!(NumberFormat::<{ PYTHON3_STRING }> {}.is_valid()); // PYTHON3.6+ LITERAL [013456N-_] /// Number format for a `Python3.6` or higher literal floating-point number. #[rustfmt::skip] pub const PYTHON36_LITERAL: u128 = NumberFormatBuilder::new() .digit_separator(num::NonZeroU8::new(b'_')) .no_special(true) .no_integer_leading_zeros(true) .internal_digit_separator(true) .build(); const_assert!(NumberFormat::<{ PYTHON36_LITERAL }> {}.is_valid()); // PYTHON3.5- LITERAL [013456N] /// Number format for a `Python3.5` or lower literal floating-point number. #[rustfmt::skip] pub const PYTHON35_LITERAL: u128 = NumberFormatBuilder::new() .no_special(true) .no_integer_leading_zeros(true) .build(); const_assert!(NumberFormat::<{ PYTHON35_LITERAL }> {}.is_valid()); // PYTHON2 LITERAL [013456MN] /// Number format for a `Python2` literal floating-point number. #[rustfmt::skip] pub const PYTHON2_LITERAL: u128 = NumberFormatBuilder::new() .no_special(true) .build(); const_assert!(NumberFormat::<{ PYTHON2_LITERAL }> {}.is_valid()); // PYTHON2 STRING [0134567MN] /// Number format to parse a `Python2` float from string. #[rustfmt::skip] pub const PYTHON2_STRING: u128 = NumberFormatBuilder::new().build(); const_assert!(NumberFormat::<{ PYTHON2_STRING }> {}.is_valid()); /// Number format for a `C++` literal floating-point number. pub const CXX_LITERAL: u128 = CXX20_LITERAL; /// Number format to parse a `C++` float from string. pub const CXX_STRING: u128 = CXX20_STRING; /// Number format for a `C++` literal hexadecimal floating-point number. #[cfg(feature = "power-of-two")] pub const CXX_HEX_LITERAL: u128 = CXX20_HEX_LITERAL; /// Number format to parse a `C++` hexadecimal float from string. #[cfg(feature = "power-of-two")] pub const CXX_HEX_STRING: u128 = CXX20_HEX_STRING; // C++20 LITERAL [013456789ABMN-'] /// Number format for a `C++20` literal floating-point number. #[rustfmt::skip] pub const CXX20_LITERAL: u128 = NumberFormatBuilder::new() .digit_separator(num::NonZeroU8::new(b'\'')) .case_sensitive_special(true) .internal_digit_separator(true) .build(); const_assert!(NumberFormat::<{ CXX20_LITERAL }> {}.is_valid()); // C++20 STRING [0134567MN] /// Number format for a `C++20` string floating-point number. #[rustfmt::skip] pub const CXX20_STRING: u128 = NumberFormatBuilder::new().build(); const_assert!(NumberFormat::<{ CXX20_STRING }> {}.is_valid()); // C++20 HEX LITERAL [013456789ABMN-'] /// Number format for a `C++20` literal hexadecimal floating-point number. #[rustfmt::skip] #[cfg(feature = "power-of-two")] pub const CXX20_HEX_LITERAL: u128 = NumberFormatBuilder::new() .required_exponent_notation(true) .digit_separator(num::NonZeroU8::new(b'\'')) .mantissa_radix(16) .exponent_base(num::NonZeroU8::new(2)) .exponent_radix(num::NonZeroU8::new(10)) .case_sensitive_special(true) .internal_digit_separator(true) .build(); #[cfg(feature = "power-of-two")] const_assert!(NumberFormat::<{ CXX20_HEX_LITERAL }> {}.is_valid()); // C++20 HEX STRING [0134567MN] /// Number format for a `C++20` string hexadecimal floating-point number. #[rustfmt::skip] #[cfg(feature = "power-of-two")] pub const CXX20_HEX_STRING: u128 = NumberFormatBuilder::new() .mantissa_radix(16) .exponent_base(num::NonZeroU8::new(2)) .exponent_radix(num::NonZeroU8::new(10)) .build(); #[cfg(feature = "power-of-two")] const_assert!(NumberFormat::<{ CXX20_HEX_STRING }> {}.is_valid()); // C++17 LITERAL [013456789ABMN-'] /// Number format for a `C++17` literal floating-point number. #[rustfmt::skip] pub const CXX17_LITERAL: u128 = NumberFormatBuilder::new() .digit_separator(num::NonZeroU8::new(b'\'')) .case_sensitive_special(true) .internal_digit_separator(true) .build(); const_assert!(NumberFormat::<{ CXX17_LITERAL }> {}.is_valid()); // C++17 STRING [0134567MN] /// Number format for a `C++17` string floating-point number. #[rustfmt::skip] pub const CXX17_STRING: u128 = NumberFormatBuilder::new().build(); const_assert!(NumberFormat::<{ CXX17_STRING }> {}.is_valid()); // C++17 HEX LITERAL [013456789ABMN-'] /// Number format for a `C++17` literal hexadecimal floating-point number. #[rustfmt::skip] #[cfg(feature = "power-of-two")] pub const CXX17_HEX_LITERAL: u128 = NumberFormatBuilder::new() .required_exponent_notation(true) .digit_separator(num::NonZeroU8::new(b'\'')) .mantissa_radix(16) .exponent_base(num::NonZeroU8::new(2)) .exponent_radix(num::NonZeroU8::new(10)) .case_sensitive_special(true) .internal_digit_separator(true) .build(); #[cfg(feature = "power-of-two")] const_assert!(NumberFormat::<{ CXX17_HEX_LITERAL }> {}.is_valid()); // C++17 HEX STRING [0134567MN] /// Number format for a `C++17` string hexadecimal floating-point number. #[rustfmt::skip] #[cfg(feature = "power-of-two")] pub const CXX17_HEX_STRING: u128 = NumberFormatBuilder::new() .mantissa_radix(16) .exponent_base(num::NonZeroU8::new(2)) .exponent_radix(num::NonZeroU8::new(10)) .build(); #[cfg(feature = "power-of-two")] const_assert!(NumberFormat::<{ CXX17_HEX_STRING }> {}.is_valid()); // C++14 LITERAL [013456789ABMN-'] /// Number format for a `C++14` literal floating-point number. #[rustfmt::skip] pub const CXX14_LITERAL: u128 = NumberFormatBuilder::new() .digit_separator(num::NonZeroU8::new(b'\'')) .case_sensitive_special(true) .internal_digit_separator(true) .build(); const_assert!(NumberFormat::<{ CXX14_LITERAL }> {}.is_valid()); // C++14 STRING [0134567MN] /// Number format for a `C++14` string floating-point number. #[rustfmt::skip] pub const CXX14_STRING: u128 = NumberFormatBuilder::new().build(); const_assert!(NumberFormat::<{ CXX14_STRING }> {}.is_valid()); // C++14 HEX STRING [0134567MN] /// Number format for a `C++14` string hexadecimal floating-point number. #[rustfmt::skip] #[cfg(feature = "power-of-two")] pub const CXX14_HEX_STRING: u128 = NumberFormatBuilder::new() .mantissa_radix(16) .exponent_base(num::NonZeroU8::new(2)) .exponent_radix(num::NonZeroU8::new(10)) .build(); #[cfg(feature = "power-of-two")] const_assert!(NumberFormat::<{ CXX14_HEX_STRING }> {}.is_valid()); // C++11 LITERAL [01345678MN] /// Number format for a `C++11` literal floating-point number. #[rustfmt::skip] pub const CXX11_LITERAL: u128 = NumberFormatBuilder::new() .case_sensitive_special(true) .build(); const_assert!(NumberFormat::<{ CXX11_LITERAL }> {}.is_valid()); // C++11 STRING [0134567MN] /// Number format for a `C++11` string floating-point number. #[rustfmt::skip] pub const CXX11_STRING: u128 = NumberFormatBuilder::new().build(); const_assert!(NumberFormat::<{ CXX11_STRING }> {}.is_valid()); // C++11 HEX STRING [0134567MN] /// Number format for a `C++11` string hexadecimal floating-point number. #[rustfmt::skip] #[cfg(feature = "power-of-two")] pub const CXX11_HEX_STRING: u128 = NumberFormatBuilder::new() .mantissa_radix(16) .exponent_base(num::NonZeroU8::new(2)) .exponent_radix(num::NonZeroU8::new(10)) .build(); #[cfg(feature = "power-of-two")] const_assert!(NumberFormat::<{ CXX11_HEX_STRING }> {}.is_valid()); // C++03 LITERAL [01345678MN] /// Number format for a `C++03` literal floating-point number. #[rustfmt::skip] pub const CXX03_LITERAL: u128 = NumberFormatBuilder::new() .case_sensitive_special(true) .build(); const_assert!(NumberFormat::<{ CXX03_LITERAL }> {}.is_valid()); // C++03 STRING [0134567MN] /// Number format for a `C++03` string floating-point number. #[rustfmt::skip] pub const CXX03_STRING: u128 = NumberFormatBuilder::new().build(); const_assert!(NumberFormat::<{ CXX03_STRING }> {}.is_valid()); // C++98 LITERAL [01345678MN] /// Number format for a `C++98` literal floating-point number. #[rustfmt::skip] pub const CXX98_LITERAL: u128 = NumberFormatBuilder::new() .case_sensitive_special(true) .build(); const_assert!(NumberFormat::<{ CXX98_LITERAL }> {}.is_valid()); // C++98 STRING [0134567MN] /// Number format for a `C++98` string floating-point number. #[rustfmt::skip] pub const CXX98_STRING: u128 = NumberFormatBuilder::new().build(); const_assert!(NumberFormat::<{ CXX98_STRING }> {}.is_valid()); /// Number format for a C literal floating-point number. pub const C_LITERAL: u128 = C18_LITERAL; /// Number format to parse a `C` float from string. pub const C_STRING: u128 = C18_STRING; /// Number format for a `C` literal hexadecimal floating-point number. #[cfg(feature = "power-of-two")] pub const C_HEX_LITERAL: u128 = C18_HEX_LITERAL; /// Number format to parse a `C` hexadecimal float from string. #[cfg(feature = "power-of-two")] pub const C_HEX_STRING: u128 = C18_HEX_STRING; // C18 LITERAL [01345678MN] /// Number format for a `C18` literal floating-point number. #[rustfmt::skip] pub const C18_LITERAL: u128 = NumberFormatBuilder::new() .case_sensitive_special(true) .build(); const_assert!(NumberFormat::<{ C18_LITERAL }> {}.is_valid()); // C18 STRING [0134567MN] /// Number format for a `C18` string floating-point number. #[rustfmt::skip] pub const C18_STRING: u128 = NumberFormatBuilder::new().build(); const_assert!(NumberFormat::<{ C18_STRING }> {}.is_valid()); // C18 HEX LITERAL [01345678MN] /// Number format for a `C18` literal hexadecimal floating-point number. #[rustfmt::skip] #[cfg(feature = "power-of-two")] pub const C18_HEX_LITERAL: u128 = NumberFormatBuilder::new() .case_sensitive_special(true) .required_exponent_notation(true) .mantissa_radix(16) .exponent_base(num::NonZeroU8::new(2)) .exponent_radix(num::NonZeroU8::new(10)) .build(); #[cfg(feature = "power-of-two")] const_assert!(NumberFormat::<{ C18_HEX_LITERAL }> {}.is_valid()); // C18 HEX STRING [0134567MN] /// Number format for a `C18` string hexadecimal floating-point number. #[rustfmt::skip] #[cfg(feature = "power-of-two")] pub const C18_HEX_STRING: u128 = NumberFormatBuilder::new() .mantissa_radix(16) .exponent_base(num::NonZeroU8::new(2)) .exponent_radix(num::NonZeroU8::new(10)) .build(); #[cfg(feature = "power-of-two")] const_assert!(NumberFormat::<{ C18_HEX_STRING }> {}.is_valid()); // C11 LITERAL [01345678MN] /// Number format for a `C11` literal floating-point number. #[rustfmt::skip] pub const C11_LITERAL: u128 = NumberFormatBuilder::new() .case_sensitive_special(true) .build(); const_assert!(NumberFormat::<{ C11_LITERAL }> {}.is_valid()); // C11 STRING [0134567MN] /// Number format for a `C11` string floating-point number. #[rustfmt::skip] pub const C11_STRING: u128 = NumberFormatBuilder::new().build(); const_assert!(NumberFormat::<{ C11_STRING }> {}.is_valid()); // C11 HEX LITERAL [01345678MN] /// Number format for a `C11` literal hexadecimal floating-point number. #[rustfmt::skip] #[cfg(feature = "power-of-two")] pub const C11_HEX_LITERAL: u128 = NumberFormatBuilder::new() .case_sensitive_special(true) .required_exponent_notation(true) .mantissa_radix(16) .exponent_base(num::NonZeroU8::new(2)) .exponent_radix(num::NonZeroU8::new(10)) .build(); #[cfg(feature = "power-of-two")] const_assert!(NumberFormat::<{ C11_HEX_LITERAL }> {}.is_valid()); // C11 HEX STRING [0134567MN] /// Number format for a `C11` string hexadecimal floating-point number. #[rustfmt::skip] #[cfg(feature = "power-of-two")] pub const C11_HEX_STRING: u128 = NumberFormatBuilder::new() .mantissa_radix(16) .exponent_base(num::NonZeroU8::new(2)) .exponent_radix(num::NonZeroU8::new(10)) .build(); #[cfg(feature = "power-of-two")] const_assert!(NumberFormat::<{ C11_HEX_STRING }> {}.is_valid()); // C99 LITERAL [01345678MN] /// Number format for a `C99` literal floating-point number. #[rustfmt::skip] pub const C99_LITERAL: u128 = NumberFormatBuilder::new() .case_sensitive_special(true) .build(); const_assert!(NumberFormat::<{ C99_LITERAL }> {}.is_valid()); // C99 STRING [0134567MN] /// Number format for a `C99` string floating-point number. #[rustfmt::skip] pub const C99_STRING: u128 = NumberFormatBuilder::new().build(); const_assert!(NumberFormat::<{ C99_STRING }> {}.is_valid()); // C99 HEX LITERAL [01345678MN] /// Number format for a `C99` literal hexadecimal floating-point number. #[rustfmt::skip] #[cfg(feature = "power-of-two")] pub const C99_HEX_LITERAL: u128 = NumberFormatBuilder::new() .case_sensitive_special(true) .required_exponent_notation(true) .mantissa_radix(16) .exponent_base(num::NonZeroU8::new(2)) .exponent_radix(num::NonZeroU8::new(10)) .build(); #[cfg(feature = "power-of-two")] const_assert!(NumberFormat::<{ C99_HEX_LITERAL }> {}.is_valid()); // C99 HEX STRING [0134567MN] /// Number format for a `C99` string hexadecimal floating-point number. #[rustfmt::skip] #[cfg(feature = "power-of-two")] pub const C99_HEX_STRING: u128 = NumberFormatBuilder::new() .mantissa_radix(16) .exponent_base(num::NonZeroU8::new(2)) .exponent_radix(num::NonZeroU8::new(10)) .build(); #[cfg(feature = "power-of-two")] const_assert!(NumberFormat::<{ C99_HEX_STRING }> {}.is_valid()); // C90 LITERAL [013456MN] /// Number format for a `C90` literal floating-point number. #[rustfmt::skip] pub const C90_LITERAL: u128 = NumberFormatBuilder::new() .no_special(true) .build(); const_assert!(NumberFormat::<{ C90_LITERAL }> {}.is_valid()); // C90 STRING [0134567MN] /// Number format for a `C90` string floating-point number. #[rustfmt::skip] pub const C90_STRING: u128 = NumberFormatBuilder::new().build(); const_assert!(NumberFormat::<{ C90_STRING }> {}.is_valid()); // C90 HEX STRING [0134567MN] /// Number format for a `C90` string hexadecimal floating-point number. #[rustfmt::skip] #[cfg(feature = "power-of-two")] pub const C90_HEX_STRING: u128 = NumberFormatBuilder::new() .mantissa_radix(16) .exponent_base(num::NonZeroU8::new(2)) .exponent_radix(num::NonZeroU8::new(10)) .build(); #[cfg(feature = "power-of-two")] const_assert!(NumberFormat::<{ C90_HEX_STRING }> {}.is_valid()); // C89 LITERAL [013456MN] /// Number format for a `C89` literal floating-point number. #[rustfmt::skip] pub const C89_LITERAL: u128 = NumberFormatBuilder::new() .no_special(true) .build(); const_assert!(NumberFormat::<{ C89_LITERAL }> {}.is_valid()); // C89 STRING [0134567MN] /// Number format for a `C89` string floating-point number. #[rustfmt::skip] pub const C89_STRING: u128 = NumberFormatBuilder::new().build(); const_assert!(NumberFormat::<{ C89_STRING }> {}.is_valid()); // C89 HEX STRING [0134567MN] /// Number format for a `C89` string hexadecimal floating-point number. #[rustfmt::skip] #[cfg(feature = "power-of-two")] pub const C89_HEX_STRING: u128 = NumberFormatBuilder::new() .mantissa_radix(16) .exponent_base(num::NonZeroU8::new(2)) .exponent_radix(num::NonZeroU8::new(10)) .build(); #[cfg(feature = "power-of-two")] const_assert!(NumberFormat::<{ C89_HEX_STRING }> {}.is_valid()); // RUBY LITERAL [345689AMN-_] /// Number format for a `Ruby` literal floating-point number. #[rustfmt::skip] pub const RUBY_LITERAL: u128 = NumberFormatBuilder::new() .digit_separator(num::NonZeroU8::new(b'_')) .required_exponent_sign(true) .required_digits(true) .no_special(true) .no_integer_leading_zeros(true) .no_float_leading_zeros(true) .internal_digit_separator(true) .build(); const_assert!(NumberFormat::<{ RUBY_LITERAL }> {}.is_valid()); // RUBY OCTAL LITERAL [345689AN-_] /// Number format for a `Ruby` literal floating-point number. #[rustfmt::skip] #[cfg(feature = "power-of-two")] pub const RUBY_OCTAL_LITERAL: u128 = NumberFormatBuilder::new() .digit_separator(num::NonZeroU8::new(b'_')) .mantissa_radix(8) .required_digits(true) .no_special(true) .internal_digit_separator(true) .build(); #[cfg(feature = "power-of-two")] const_assert!(NumberFormat::<{ RUBY_OCTAL_LITERAL }> {}.is_valid()); // RUBY STRING [01234569ABMN-_] // Note: Amazingly, Ruby 1.8+ do not allow parsing special values. /// Number format to parse a `Ruby` float from string. #[rustfmt::skip] pub const RUBY_STRING: u128 = NumberFormatBuilder::new() .digit_separator(num::NonZeroU8::new(b'_')) .no_special(true) .internal_digit_separator(true) .build(); const_assert!(NumberFormat::<{ RUBY_STRING }> {}.is_valid()); // SWIFT LITERAL [34569ABFGHIJKMN-_] /// Number format for a `Swift` literal floating-point number. #[rustfmt::skip] pub const SWIFT_LITERAL: u128 = NumberFormatBuilder::new() .digit_separator(num::NonZeroU8::new(b'_')) .required_digits(true) .no_special(true) .internal_digit_separator(true) .trailing_digit_separator(true) .consecutive_digit_separator(true) .build(); const_assert!(NumberFormat::<{ SWIFT_LITERAL }> {}.is_valid()); // SWIFT STRING [134567MN] /// Number format to parse a `Swift` float from string. #[rustfmt::skip] pub const SWIFT_STRING: u128 = NumberFormatBuilder::new() .required_fraction_digits(true) .build(); const_assert!(NumberFormat::<{ SWIFT_STRING }> {}.is_valid()); // GO LITERAL [13456MN] /// Number format for a `Golang` literal floating-point number. #[rustfmt::skip] pub const GO_LITERAL: u128 = NumberFormatBuilder::new() .required_fraction_digits(true) .no_special(true) .build(); const_assert!(NumberFormat::<{ GO_LITERAL }> {}.is_valid()); // GO STRING [134567MN] /// Number format to parse a `Golang` float from string. #[rustfmt::skip] pub const GO_STRING: u128 = NumberFormatBuilder::new() .required_fraction_digits(true) .build(); const_assert!(NumberFormat::<{ GO_STRING }> {}.is_valid()); // HASKELL LITERAL [456MN] /// Number format for a `Haskell` literal floating-point number. #[rustfmt::skip] pub const HASKELL_LITERAL: u128 = NumberFormatBuilder::new() .required_digits(true) .no_positive_mantissa_sign(true) .no_special(true) .build(); const_assert!(NumberFormat::<{ HASKELL_LITERAL }> {}.is_valid()); // HASKELL STRING [45678MN] /// Number format to parse a `Haskell` float from string. #[rustfmt::skip] pub const HASKELL_STRING: u128 = NumberFormatBuilder::new() .required_digits(true) .no_positive_mantissa_sign(true) .case_sensitive_special(true) .build(); const_assert!(NumberFormat::<{ HASKELL_STRING }> {}.is_valid()); // JAVASCRIPT LITERAL [01345678M] /// Number format for a `Javascript` literal floating-point number. #[rustfmt::skip] pub const JAVASCRIPT_LITERAL: u128 = NumberFormatBuilder::new() .case_sensitive_special(true) .no_float_leading_zeros(true) .build(); const_assert!(NumberFormat::<{ JAVASCRIPT_LITERAL }> {}.is_valid()); // JAVASCRIPT STRING [012345678MN] /// Number format to parse a `Javascript` float from string. #[rustfmt::skip] pub const JAVASCRIPT_STRING: u128 = NumberFormatBuilder::new() .required_exponent_digits(false) .case_sensitive_special(true) .build(); const_assert!(NumberFormat::<{ JAVASCRIPT_STRING }> {}.is_valid()); // PERL LITERAL [0134569ABDEFGHIJKMN-_] /// Number format for a `Perl` literal floating-point number. #[rustfmt::skip] pub const PERL_LITERAL: u128 = NumberFormatBuilder::new() .digit_separator(num::NonZeroU8::new(b'_')) .no_special(true) .internal_digit_separator(true) .fraction_leading_digit_separator(true) .exponent_leading_digit_separator(true) .trailing_digit_separator(true) .consecutive_digit_separator(true) .build(); const_assert!(NumberFormat::<{ PERL_LITERAL }> {}.is_valid()); // PERL STRING [01234567MN] /// Number format to parse a `Perl` float from string. pub const PERL_STRING: u128 = PERMISSIVE; // PHP LITERAL [01345678MN] /// Number format for a `PHP` literal floating-point number. #[rustfmt::skip] pub const PHP_LITERAL: u128 = NumberFormatBuilder::new() .case_sensitive_special(true) .build(); const_assert!(NumberFormat::<{ PHP_LITERAL }> {}.is_valid()); // PHP STRING [0123456MN] /// Number format to parse a `PHP` float from string. #[rustfmt::skip] pub const PHP_STRING: u128 = NumberFormatBuilder::new() .required_exponent_digits(false) .no_special(true) .build(); const_assert!(NumberFormat::<{ PHP_STRING }> {}.is_valid()); // JAVA LITERAL [0134569ABIJKMN-_] /// Number format for a `Java` literal floating-point number. #[rustfmt::skip] pub const JAVA_LITERAL: u128 = NumberFormatBuilder::new() .digit_separator(num::NonZeroU8::new(b'_')) .no_special(true) .internal_digit_separator(true) .consecutive_digit_separator(true) .build(); const_assert!(NumberFormat::<{ JAVA_LITERAL }> {}.is_valid()); // JAVA STRING [01345678MN] /// Number format to parse a `Java` float from string. #[rustfmt::skip] pub const JAVA_STRING: u128 = NumberFormatBuilder::new() .case_sensitive_special(true) .build(); const_assert!(NumberFormat::<{ JAVA_STRING }> {}.is_valid()); // R LITERAL [01345678MN] /// Number format for a `R` literal floating-point number. #[rustfmt::skip] pub const R_LITERAL: u128 = NumberFormatBuilder::new() .case_sensitive_special(true) .build(); const_assert!(NumberFormat::<{ R_LITERAL }> {}.is_valid()); // R STRING [01234567MN] /// Number format to parse a `R` float from string. pub const R_STRING: u128 = PERMISSIVE; // KOTLIN LITERAL [0134569ABIJKN-_] /// Number format for a `Kotlin` literal floating-point number. #[rustfmt::skip] pub const KOTLIN_LITERAL: u128 = NumberFormatBuilder::new() .digit_separator(num::NonZeroU8::new(b'_')) .no_special(true) .no_integer_leading_zeros(true) .internal_digit_separator(true) .consecutive_digit_separator(true) .build(); const_assert!(NumberFormat::<{ KOTLIN_LITERAL }> {}.is_valid()); // KOTLIN STRING [0134568MN] /// Number format to parse a `Kotlin` float from string. #[rustfmt::skip] pub const KOTLIN_STRING: u128 = NumberFormatBuilder::new() .case_sensitive_special(true) .build(); const_assert!(NumberFormat::<{ KOTLIN_STRING }> {}.is_valid()); // JULIA LITERAL [01345689AMN-_] /// Number format for a `Julia` literal floating-point number. #[rustfmt::skip] pub const JULIA_LITERAL: u128 = NumberFormatBuilder::new() .digit_separator(num::NonZeroU8::new(b'_')) .case_sensitive_special(true) .integer_internal_digit_separator(true) .fraction_internal_digit_separator(true) .build(); const_assert!(NumberFormat::<{ JULIA_LITERAL }> {}.is_valid()); // JULIA STRING [01345678MN] /// Number format to parse a `Julia` float from string. #[rustfmt::skip] pub const JULIA_STRING: u128 = NumberFormatBuilder::new().build(); const_assert!(NumberFormat::<{ JULIA_STRING }> {}.is_valid()); // JULIA HEX LITERAL [01345689AMN-_] /// Number format for a `Julia` literal floating-point number. #[rustfmt::skip] #[cfg(feature = "power-of-two")] pub const JULIA_HEX_LITERAL: u128 = NumberFormatBuilder::new() .digit_separator(num::NonZeroU8::new(b'_')) .mantissa_radix(16) .exponent_base(num::NonZeroU8::new(2)) .exponent_radix(num::NonZeroU8::new(10)) .case_sensitive_special(true) .integer_internal_digit_separator(true) .fraction_internal_digit_separator(true) .build(); #[cfg(feature = "power-of-two")] const_assert!(NumberFormat::<{ JULIA_HEX_LITERAL }> {}.is_valid()); // JULIA HEX STRING [01345678MN] /// Number format to parse a `Julia` float from string. #[rustfmt::skip] #[cfg(feature = "power-of-two")] pub const JULIA_HEX_STRING: u128 = NumberFormatBuilder::new() .mantissa_radix(16) .exponent_base(num::NonZeroU8::new(2)) .exponent_radix(num::NonZeroU8::new(10)) .build(); #[cfg(feature = "power-of-two")] const_assert!(NumberFormat::<{ JULIA_HEX_STRING }> {}.is_valid()); /// Number format for a `C#` literal floating-point number. pub const CSHARP_LITERAL: u128 = CSHARP7_LITERAL; /// Number format to parse a `C#` float from string. pub const CSHARP_STRING: u128 = CSHARP7_STRING; // CSHARP7 LITERAL [034569ABIJKMN-_] /// Number format for a `C#7` literal floating-point number. #[rustfmt::skip] pub const CSHARP7_LITERAL: u128 = NumberFormatBuilder::new() .digit_separator(num::NonZeroU8::new(b'_')) .required_fraction_digits(true) .no_special(true) .internal_digit_separator(true) .consecutive_digit_separator(true) .build(); const_assert!(NumberFormat::<{ CSHARP7_LITERAL }> {}.is_valid()); // CSHARP7 STRING [0134568MN] /// Number format to parse a `C#7` float from string. #[rustfmt::skip] pub const CSHARP7_STRING: u128 = NumberFormatBuilder::new() .case_sensitive_special(true) .build(); const_assert!(NumberFormat::<{ CSHARP7_STRING }> {}.is_valid()); // CSHARP6 LITERAL [03456MN] /// Number format for a `C#6` literal floating-point number. #[rustfmt::skip] pub const CSHARP6_LITERAL: u128 = NumberFormatBuilder::new() .required_fraction_digits(true) .no_special(true) .build(); const_assert!(NumberFormat::<{ CSHARP6_LITERAL }> {}.is_valid()); // CSHARP6 STRING [0134568MN] /// Number format to parse a `C#6` float from string. #[rustfmt::skip] pub const CSHARP6_STRING: u128 = NumberFormatBuilder::new() .case_sensitive_special(true) .build(); const_assert!(NumberFormat::<{ CSHARP6_STRING }> {}.is_valid()); // CSHARP5 LITERAL [03456MN] /// Number format for a `C#5` literal floating-point number. #[rustfmt::skip] pub const CSHARP5_LITERAL: u128 = NumberFormatBuilder::new() .required_fraction_digits(true) .no_special(true) .build(); const_assert!(NumberFormat::<{ CSHARP5_LITERAL }> {}.is_valid()); // CSHARP5 STRING [0134568MN] /// Number format to parse a `C#5` float from string. #[rustfmt::skip] pub const CSHARP5_STRING: u128 = NumberFormatBuilder::new() .case_sensitive_special(true) .build(); const_assert!(NumberFormat::<{ CSHARP5_STRING }> {}.is_valid()); // CSHARP4 LITERAL [03456MN] /// Number format for a `C#4` literal floating-point number. #[rustfmt::skip] pub const CSHARP4_LITERAL: u128 = NumberFormatBuilder::new() .required_fraction_digits(true) .no_special(true) .build(); const_assert!(NumberFormat::<{ CSHARP4_LITERAL }> {}.is_valid()); // CSHARP4 STRING [0134568MN] /// Number format to parse a `C#4` float from string. #[rustfmt::skip] pub const CSHARP4_STRING: u128 = NumberFormatBuilder::new() .case_sensitive_special(true) .build(); const_assert!(NumberFormat::<{ CSHARP4_STRING }> {}.is_valid()); // CSHARP3 LITERAL [03456MN] /// Number format for a `C#3` literal floating-point number. #[rustfmt::skip] pub const CSHARP3_LITERAL: u128 = NumberFormatBuilder::new() .required_fraction_digits(true) .no_special(true) .build(); const_assert!(NumberFormat::<{ CSHARP3_LITERAL }> {}.is_valid()); // CSHARP3 STRING [0134568MN] /// Number format to parse a `C#3` float from string. #[rustfmt::skip] pub const CSHARP3_STRING: u128 = NumberFormatBuilder::new() .case_sensitive_special(true) .build(); const_assert!(NumberFormat::<{ CSHARP3_STRING }> {}.is_valid()); // CSHARP2 LITERAL [03456MN] /// Number format for a `C#2` literal floating-point number. #[rustfmt::skip] pub const CSHARP2_LITERAL: u128 = NumberFormatBuilder::new() .required_fraction_digits(true) .no_special(true) .build(); const_assert!(NumberFormat::<{ CSHARP2_LITERAL }> {}.is_valid()); // CSHARP2 STRING [0134568MN] /// Number format to parse a `C#2` float from string. #[rustfmt::skip] pub const CSHARP2_STRING: u128 = NumberFormatBuilder::new() .case_sensitive_special(true) .build(); const_assert!(NumberFormat::<{ CSHARP2_STRING }> {}.is_valid()); // CSHARP1 LITERAL [03456MN] /// Number format for a `C#1` literal floating-point number. #[rustfmt::skip] pub const CSHARP1_LITERAL: u128 = NumberFormatBuilder::new() .required_fraction_digits(true) .no_special(true) .build(); const_assert!(NumberFormat::<{ CSHARP1_LITERAL }> {}.is_valid()); // CSHARP1 STRING [0134568MN] /// Number format to parse a `C#1` float from string. #[rustfmt::skip] pub const CSHARP1_STRING: u128 = NumberFormatBuilder::new() .case_sensitive_special(true) .build(); const_assert!(NumberFormat::<{ CSHARP1_STRING }> {}.is_valid()); // KAWA LITERAL [013456MN] /// Number format for a `Kawa` literal floating-point number. #[rustfmt::skip] pub const KAWA_LITERAL: u128 = NumberFormatBuilder::new() .no_special(true) .build(); const_assert!(NumberFormat::<{ KAWA_LITERAL }> {}.is_valid()); // KAWA STRING [013456MN] /// Number format to parse a `Kawa` float from string. #[rustfmt::skip] pub const KAWA_STRING: u128 = NumberFormatBuilder::new() .no_special(true) .build(); const_assert!(NumberFormat::<{ KAWA_STRING }> {}.is_valid()); // GAMBITC LITERAL [013456MN] /// Number format for a `Gambit-C` literal floating-point number. #[rustfmt::skip] pub const GAMBITC_LITERAL: u128 = NumberFormatBuilder::new() .no_special(true) .build(); const_assert!(NumberFormat::<{ GAMBITC_LITERAL }> {}.is_valid()); // GAMBITC STRING [013456MN] /// Number format to parse a `Gambit-C` float from string. #[rustfmt::skip] pub const GAMBITC_STRING: u128 = NumberFormatBuilder::new() .no_special(true) .build(); const_assert!(NumberFormat::<{ GAMBITC_STRING }> {}.is_valid()); // GUILE LITERAL [013456MN] /// Number format for a `Guile` literal floating-point number. #[rustfmt::skip] pub const GUILE_LITERAL: u128 = NumberFormatBuilder::new() .no_special(true) .build(); const_assert!(NumberFormat::<{ GUILE_LITERAL }> {}.is_valid()); // GUILE STRING [013456MN] /// Number format to parse a `Guile` float from string. #[rustfmt::skip] pub const GUILE_STRING: u128 = NumberFormatBuilder::new() .no_special(true) .build(); const_assert!(NumberFormat::<{ GUILE_STRING }> {}.is_valid()); // CLOJURE LITERAL [13456MN] /// Number format for a `Clojure` literal floating-point number. #[rustfmt::skip] pub const CLOJURE_LITERAL: u128 = NumberFormatBuilder::new() .required_integer_digits(true) .no_special(true) .build(); const_assert!(NumberFormat::<{ CLOJURE_LITERAL }> {}.is_valid()); // CLOJURE STRING [01345678MN] /// Number format to parse a `Clojure` float from string. #[rustfmt::skip] pub const CLOJURE_STRING: u128 = NumberFormatBuilder::new() .case_sensitive_special(true) .build(); const_assert!(NumberFormat::<{ CLOJURE_STRING }> {}.is_valid()); // ERLANG LITERAL [34578MN] /// Number format for an `Erlang` literal floating-point number. #[rustfmt::skip] pub const ERLANG_LITERAL: u128 = NumberFormatBuilder::new() .required_digits(true) .no_exponent_without_fraction(true) .case_sensitive_special(true) .build(); const_assert!(NumberFormat::<{ ERLANG_LITERAL }> {}.is_valid()); // ERLANG STRING [345MN] /// Number format to parse an `Erlang` float from string. #[rustfmt::skip] pub const ERLANG_STRING: u128 = NumberFormatBuilder::new() .required_digits(true) .no_exponent_without_fraction(true) .no_special(true) .build(); const_assert!(NumberFormat::<{ ERLANG_STRING }> {}.is_valid()); // ELM LITERAL [456] /// Number format for an `Elm` literal floating-point number. #[rustfmt::skip] pub const ELM_LITERAL: u128 = NumberFormatBuilder::new() .required_digits(true) .no_positive_mantissa_sign(true) .no_integer_leading_zeros(true) .no_float_leading_zeros(true) .no_special(true) .build(); const_assert!(NumberFormat::<{ ELM_LITERAL }> {}.is_valid()); // ELM STRING [01345678MN] // Note: There is no valid representation of NaN, just Infinity. /// Number format to parse an `Elm` float from string. #[rustfmt::skip] pub const ELM_STRING: u128 = NumberFormatBuilder::new() .case_sensitive_special(true) .build(); const_assert!(NumberFormat::<{ ELM_STRING }> {}.is_valid()); // SCALA LITERAL [3456] /// Number format for a `Scala` literal floating-point number. #[rustfmt::skip] pub const SCALA_LITERAL: u128 = NumberFormatBuilder::new() .required_digits(true) .no_special(true) .no_integer_leading_zeros(true) .no_float_leading_zeros(true) .build(); const_assert!(NumberFormat::<{ SCALA_LITERAL }> {}.is_valid()); // SCALA STRING [01345678MN] /// Number format to parse a `Scala` float from string. #[rustfmt::skip] pub const SCALA_STRING: u128 = NumberFormatBuilder::new() .case_sensitive_special(true) .build(); const_assert!(NumberFormat::<{ SCALA_STRING }> {}.is_valid()); // ELIXIR LITERAL [3459ABMN-_] /// Number format for an `Elixir` literal floating-point number. #[rustfmt::skip] pub const ELIXIR_LITERAL: u128 = NumberFormatBuilder::new() .digit_separator(num::NonZeroU8::new(b'_')) .required_digits(true) .no_exponent_without_fraction(true) .no_special(true) .internal_digit_separator(true) .build(); const_assert!(NumberFormat::<{ ELIXIR_LITERAL }> {}.is_valid()); // ELIXIR STRING [345MN] /// Number format to parse an `Elixir` float from string. #[rustfmt::skip] pub const ELIXIR_STRING: u128 = NumberFormatBuilder::new() .required_digits(true) .no_exponent_without_fraction(true) .no_special(true) .build(); const_assert!(NumberFormat::<{ ELIXIR_STRING }> {}.is_valid()); // FORTRAN LITERAL [013456MN] /// Number format for a `FORTRAN` literal floating-point number. #[rustfmt::skip] pub const FORTRAN_LITERAL: u128 = NumberFormatBuilder::new() .no_special(true) .build(); const_assert!(NumberFormat::<{ FORTRAN_LITERAL }> {}.is_valid()); // FORTRAN STRING [0134567MN] /// Number format to parse a `FORTRAN` float from string. #[rustfmt::skip] pub const FORTRAN_STRING: u128 = NumberFormatBuilder::new().build(); const_assert!(NumberFormat::<{ FORTRAN_STRING }> {}.is_valid()); // D LITERAL [0134569ABFGHIJKN-_] /// Number format for a `D` literal floating-point number. #[rustfmt::skip] pub const D_LITERAL: u128 = NumberFormatBuilder::new() .digit_separator(num::NonZeroU8::new(b'_')) .no_special(true) .no_integer_leading_zeros(true) .internal_digit_separator(true) .trailing_digit_separator(true) .consecutive_digit_separator(true) .build(); const_assert!(NumberFormat::<{ D_LITERAL }> {}.is_valid()); // D STRING [01345679AFGMN-_] /// Number format to parse a `D` float from string. #[rustfmt::skip] pub const D_STRING: u128 = NumberFormatBuilder::new() .digit_separator(num::NonZeroU8::new(b'_')) .integer_internal_digit_separator(true) .fraction_internal_digit_separator(true) .integer_trailing_digit_separator(true) .fraction_trailing_digit_separator(true) .build(); const_assert!(NumberFormat::<{ D_STRING }> {}.is_valid()); // COFFEESCRIPT LITERAL [01345678] /// Number format for a `Coffeescript` literal floating-point number. #[rustfmt::skip] pub const COFFEESCRIPT_LITERAL: u128 = NumberFormatBuilder::new() .case_sensitive_special(true) .no_integer_leading_zeros(true) .no_float_leading_zeros(true) .build(); const_assert!(NumberFormat::<{ COFFEESCRIPT_LITERAL }> {}.is_valid()); // COFFEESCRIPT STRING [012345678MN] /// Number format to parse a `Coffeescript` float from string. #[rustfmt::skip] pub const COFFEESCRIPT_STRING: u128 = NumberFormatBuilder::new() .case_sensitive_special(true) .build(); const_assert!(NumberFormat::<{ COFFEESCRIPT_STRING }> {}.is_valid()); // COBOL LITERAL [0345MN] /// Number format for a `Cobol` literal floating-point number. #[rustfmt::skip] pub const COBOL_LITERAL: u128 = NumberFormatBuilder::new() .required_fraction_digits(true) .no_exponent_without_fraction(true) .no_special(true) .build(); const_assert!(NumberFormat::<{ COBOL_LITERAL }> {}.is_valid()); // COBOL STRING [012356MN] /// Number format to parse a `Cobol` float from string. #[rustfmt::skip] pub const COBOL_STRING: u128 = NumberFormatBuilder::new() .required_exponent_sign(true) .no_special(true) .build(); const_assert!(NumberFormat::<{ COBOL_STRING }> {}.is_valid()); // FSHARP LITERAL [13456789ABIJKMN-_] /// Number format for a `F#` literal floating-point number. #[rustfmt::skip] pub const FSHARP_LITERAL: u128 = NumberFormatBuilder::new() .digit_separator(num::NonZeroU8::new(b'_')) .required_integer_digits(true) .required_exponent_digits(true) .case_sensitive_special(true) .internal_digit_separator(true) .consecutive_digit_separator(true) .build(); const_assert!(NumberFormat::<{ FSHARP_LITERAL }> {}.is_valid()); // FSHARP STRING [013456789ABCDEFGHIJKLMN-_] /// Number format to parse a `F#` float from string. #[rustfmt::skip] pub const FSHARP_STRING: u128 = NumberFormatBuilder::new() .digit_separator(num::NonZeroU8::new(b'_')) .internal_digit_separator(true) .leading_digit_separator(true) .trailing_digit_separator(true) .consecutive_digit_separator(true) .special_digit_separator(true) .build(); const_assert!(NumberFormat::<{ FSHARP_STRING }> {}.is_valid()); // VB LITERAL [03456MN] /// Number format for a `Visual Basic` literal floating-point number. #[rustfmt::skip] pub const VB_LITERAL: u128 = NumberFormatBuilder::new() .required_fraction_digits(true) .no_special(true) .build(); const_assert!(NumberFormat::<{ VB_LITERAL }> {}.is_valid()); // VB STRING [01345678MN] /// Number format to parse a `Visual Basic` float from string. // Note: To my knowledge, Visual Basic cannot parse infinity. #[rustfmt::skip] pub const VB_STRING: u128 = NumberFormatBuilder::new() .case_sensitive_special(true) .build(); const_assert!(NumberFormat::<{ VB_STRING }> {}.is_valid()); // OCAML LITERAL [1456789ABDFGHIJKMN-_] /// Number format for an `OCaml` literal floating-point number. #[rustfmt::skip] pub const OCAML_LITERAL: u128 = NumberFormatBuilder::new() .digit_separator(num::NonZeroU8::new(b'_')) .required_integer_digits(true) .required_exponent_digits(true) .no_positive_mantissa_sign(true) .case_sensitive_special(true) .internal_digit_separator(true) .fraction_leading_digit_separator(true) .trailing_digit_separator(true) .consecutive_digit_separator(true) .build(); const_assert!(NumberFormat::<{ OCAML_LITERAL }> {}.is_valid()); // OCAML STRING [01345679ABCDEFGHIJKLMN-_] /// Number format to parse an `OCaml` float from string. #[rustfmt::skip] pub const OCAML_STRING: u128 = NumberFormatBuilder::new() .digit_separator(num::NonZeroU8::new(b'_')) .internal_digit_separator(true) .leading_digit_separator(true) .trailing_digit_separator(true) .consecutive_digit_separator(true) .special_digit_separator(true) .build(); const_assert!(NumberFormat::<{ OCAML_STRING }> {}.is_valid()); // OBJECTIVEC LITERAL [013456MN] /// Number format for an `Objective-C` literal floating-point number. #[rustfmt::skip] pub const OBJECTIVEC_LITERAL: u128 = NumberFormatBuilder::new() .no_special(true) .build(); const_assert!(NumberFormat::<{ OBJECTIVEC_LITERAL }> {}.is_valid()); // OBJECTIVEC STRING [013456MN] /// Number format to parse an `Objective-C` float from string. #[rustfmt::skip] pub const OBJECTIVEC_STRING: u128 = NumberFormatBuilder::new() .no_special(true) .build(); const_assert!(NumberFormat::<{ OBJECTIVEC_STRING }> {}.is_valid()); // REASONML LITERAL [13456789ABDFGHIJKMN-_] /// Number format for a `ReasonML` literal floating-point number. #[rustfmt::skip] pub const REASONML_LITERAL: u128 = NumberFormatBuilder::new() .digit_separator(num::NonZeroU8::new(b'_')) .required_integer_digits(true) .required_exponent_digits(true) .case_sensitive_special(true) .internal_digit_separator(true) .fraction_leading_digit_separator(true) .trailing_digit_separator(true) .consecutive_digit_separator(true) .build(); const_assert!(NumberFormat::<{ REASONML_LITERAL }> {}.is_valid()); // REASONML STRING [01345679ABCDEFGHIJKLMN-_] /// Number format to parse a `ReasonML` float from string. #[rustfmt::skip] pub const REASONML_STRING: u128 = NumberFormatBuilder::new() .digit_separator(num::NonZeroU8::new(b'_')) .internal_digit_separator(true) .leading_digit_separator(true) .trailing_digit_separator(true) .consecutive_digit_separator(true) .special_digit_separator(true) .build(); const_assert!(NumberFormat::<{ REASONML_STRING }> {}.is_valid()); // OCTAVE LITERAL [013456789ABDFGHIJKMN-_] // Note: Octave accepts both NaN and nan, Inf and inf. /// Number format for an `Octave` literal floating-point number. #[rustfmt::skip] pub const OCTAVE_LITERAL: u128 = NumberFormatBuilder::new() .digit_separator(num::NonZeroU8::new(b'_')) .case_sensitive_special(true) .internal_digit_separator(true) .fraction_leading_digit_separator(true) .trailing_digit_separator(true) .consecutive_digit_separator(true) .build(); const_assert!(NumberFormat::<{ OCTAVE_LITERAL }> {}.is_valid()); // OCTAVE STRING [01345679ABCDEFGHIJKMN-,] /// Number format to parse an `Octave` float from string. #[rustfmt::skip] pub const OCTAVE_STRING: u128 = NumberFormatBuilder::new() .digit_separator(num::NonZeroU8::new(b',')) .internal_digit_separator(true) .leading_digit_separator(true) .trailing_digit_separator(true) .consecutive_digit_separator(true) .build(); const_assert!(NumberFormat::<{ OCTAVE_STRING }> {}.is_valid()); // MATLAB LITERAL [013456789ABDFGHIJKMN-_] // Note: Matlab accepts both NaN and nan, Inf and inf. /// Number format for an `Matlab` literal floating-point number. #[rustfmt::skip] pub const MATLAB_LITERAL: u128 = NumberFormatBuilder::new() .digit_separator(num::NonZeroU8::new(b'_')) .case_sensitive_special(true) .internal_digit_separator(true) .fraction_leading_digit_separator(true) .trailing_digit_separator(true) .consecutive_digit_separator(true) .build(); const_assert!(NumberFormat::<{ MATLAB_LITERAL }> {}.is_valid()); // MATLAB STRING [01345679ABCDEFGHIJKMN-,] /// Number format to parse an `Matlab` float from string. #[rustfmt::skip] pub const MATLAB_STRING: u128 = NumberFormatBuilder::new() .digit_separator(num::NonZeroU8::new(b',')) .internal_digit_separator(true) .leading_digit_separator(true) .trailing_digit_separator(true) .consecutive_digit_separator(true) .build(); const_assert!(NumberFormat::<{ MATLAB_STRING }> {}.is_valid()); // ZIG LITERAL [1456MN] /// Number format for a `Zig` literal floating-point number. #[rustfmt::skip] pub const ZIG_LITERAL: u128 = NumberFormatBuilder::new() .required_integer_digits(true) .no_positive_mantissa_sign(true) .no_special(true) .build(); const_assert!(NumberFormat::<{ ZIG_LITERAL }> {}.is_valid()); // ZIG STRING [01234567MN] /// Number format to parse a `Zig` float from string. pub const ZIG_STRING: u128 = PERMISSIVE; // SAGE LITERAL [012345678MN] // Note: Both Infinity and infinity are accepted. /// Number format for a `Sage` literal floating-point number. #[rustfmt::skip] pub const SAGE_LITERAL: u128 = NumberFormatBuilder::new() .case_sensitive_special(true) .build(); const_assert!(NumberFormat::<{ SAGE_LITERAL }> {}.is_valid()); // SAGE STRING [01345679ABMN-_] /// Number format to parse a `Sage` float from string. #[rustfmt::skip] pub const SAGE_STRING: u128 = NumberFormatBuilder::new() .digit_separator(num::NonZeroU8::new(b'_')) .internal_digit_separator(true) .build(); const_assert!(NumberFormat::<{ SAGE_STRING }> {}.is_valid()); // JSON [456] /// Number format for a `JSON` literal floating-point number. #[rustfmt::skip] pub const JSON: u128 = NumberFormatBuilder::new() .required_digits(true) .no_positive_mantissa_sign(true) .no_special(true) .no_integer_leading_zeros(true) .no_float_leading_zeros(true) .build(); const_assert!(NumberFormat::<{ JSON }> {}.is_valid()); // TOML [34569AB] /// Number format for a `TOML` literal floating-point number. #[rustfmt::skip] pub const TOML: u128 = NumberFormatBuilder::new() .digit_separator(num::NonZeroU8::new(b'_')) .required_digits(false) .no_special(true) .no_integer_leading_zeros(true) .no_float_leading_zeros(true) .internal_digit_separator(true) .build(); const_assert!(NumberFormat::<{ TOML }> {}.is_valid()); // YAML (defined in-terms of JSON schema). /// Number format for a `YAML` literal floating-point number. pub const YAML: u128 = JSON; // XML [01234578MN] /// Number format for a `XML` literal floating-point number. #[rustfmt::skip] pub const XML: u128 = NumberFormatBuilder::new() .required_exponent_digits(false) .case_sensitive_special(true) .build(); const_assert!(NumberFormat::<{ XML }> {}.is_valid()); // SQLITE [013456MN] /// Number format for a `SQLite` literal floating-point number. #[rustfmt::skip] pub const SQLITE: u128 = NumberFormatBuilder::new() .no_special(true) .build(); const_assert!(NumberFormat::<{ SQLITE }> {}.is_valid()); // POSTGRESQL [013456MN] /// Number format for a `PostgreSQL` literal floating-point number. #[rustfmt::skip] pub const POSTGRESQL: u128 = NumberFormatBuilder::new() .no_special(true) .build(); const_assert!(NumberFormat::<{ POSTGRESQL }> {}.is_valid()); // MYSQL [013456MN] /// Number format for a `MySQL` literal floating-point number. #[rustfmt::skip] pub const MYSQL: u128 = NumberFormatBuilder::new() .no_special(true) .build(); const_assert!(NumberFormat::<{ MYSQL }> {}.is_valid()); // MONGODB [01345678M] /// Number format for a `MongoDB` literal floating-point number. #[rustfmt::skip] pub const MONGODB: u128 = NumberFormatBuilder::new() .case_sensitive_special(true) .no_float_leading_zeros(true) .build(); const_assert!(NumberFormat::<{ MONGODB }> {}.is_valid()); // HIDDEN DEFAULTS AND INTERFACES /// Number format when no flags are set. #[doc(hidden)] #[rustfmt::skip] pub const PERMISSIVE: u128 = NumberFormatBuilder::new() .required_exponent_digits(false) .required_mantissa_digits(false) .build(); const_assert!(NumberFormat::<{ PERMISSIVE }> {}.is_valid()); /// Number format when all digit separator flags are set. #[doc(hidden)] #[rustfmt::skip] pub const IGNORE: u128 = NumberFormatBuilder::new() .digit_separator(num::NonZeroU8::new(b'_')) .digit_separator_flags(true) .required_exponent_digits(false) .required_mantissa_digits(false) .build(); const_assert!(NumberFormat::<{ IGNORE }> {}.is_valid()); lexical-util-1.0.6/src/format.rs000064400000000000000000000325431046102023000146600ustar 00000000000000//! Public API for the number format packed struct. //! //! This has a consistent API whether or not the `format` feature is //! enabled, however, most functionality will be disabled if the feature //! is not enabled. //! //! # Pre-Defined Formats //! //! These are the pre-defined formats for parsing numbers from various //! programming, markup, and data languages. //! //! - [STANDARD] #![cfg_attr(feature = "format", doc = " - [`RUST_LITERAL`]")] #![cfg_attr(feature = "format", doc = " - [`RUST_STRING`]")] #![cfg_attr(feature = "format", doc = " - [`PYTHON_LITERAL`]")] #![cfg_attr(feature = "format", doc = " - [`PYTHON_STRING`]")] #![cfg_attr(feature = "format", doc = " - [`PYTHON3_LITERAL`]")] #![cfg_attr(feature = "format", doc = " - [`PYTHON3_STRING`]")] #![cfg_attr(feature = "format", doc = " - [`PYTHON36_LITERAL`]")] #![cfg_attr(feature = "format", doc = " - [`PYTHON35_LITERAL`]")] #![cfg_attr(feature = "format", doc = " - [`PYTHON2_LITERAL`]")] #![cfg_attr(feature = "format", doc = " - [`PYTHON2_STRING`]")] #![cfg_attr(feature = "format", doc = " - [`CXX_LITERAL`]")] #![cfg_attr(feature = "format", doc = " - [`CXX_STRING`]")] #![cfg_attr(all(feature = "format", feature = "power-of-two"), doc = " - [`CXX_HEX_LITERAL`]")] #![cfg_attr(all(feature = "format", feature = "power-of-two"), doc = " - [`CXX_HEX_STRING`]")] #![cfg_attr(feature = "format", doc = " - [`CXX20_LITERAL`]")] #![cfg_attr(feature = "format", doc = " - [`CXX20_STRING`]")] #![cfg_attr(all(feature = "format", feature = "power-of-two"), doc = " - [`CXX20_HEX_LITERAL`]")] #![cfg_attr(all(feature = "format", feature = "power-of-two"), doc = " - [`CXX20_HEX_STRING`]")] #![cfg_attr(feature = "format", doc = " - [`CXX17_LITERAL`]")] #![cfg_attr(feature = "format", doc = " - [`CXX17_STRING`]")] #![cfg_attr(all(feature = "format", feature = "power-of-two"), doc = " - [`CXX17_HEX_LITERAL`]")] #![cfg_attr(all(feature = "format", feature = "power-of-two"), doc = " - [`CXX17_HEX_STRING`]")] #![cfg_attr(feature = "format", doc = " - [`CXX14_LITERAL`]")] #![cfg_attr(feature = "format", doc = " - [`CXX14_STRING`]")] #![cfg_attr(all(feature = "format", feature = "power-of-two"), doc = " - [`CXX14_HEX_STRING`]")] #![cfg_attr(feature = "format", doc = " - [`CXX11_LITERAL`]")] #![cfg_attr(feature = "format", doc = " - [`CXX11_STRING`]")] #![cfg_attr(all(feature = "format", feature = "power-of-two"), doc = " - [`CXX11_HEX_STRING`]")] #![cfg_attr(feature = "format", doc = " - [`CXX03_LITERAL`]")] #![cfg_attr(feature = "format", doc = " - [`CXX03_STRING`]")] #![cfg_attr(feature = "format", doc = " - [`CXX98_LITERAL`]")] #![cfg_attr(feature = "format", doc = " - [`CXX98_STRING`]")] #![cfg_attr(feature = "format", doc = " - [`C_LITERAL`]")] #![cfg_attr(feature = "format", doc = " - [`C_STRING`]")] #![cfg_attr(all(feature = "format", feature = "power-of-two"), doc = " - [`C_HEX_LITERAL`]")] #![cfg_attr(all(feature = "format", feature = "power-of-two"), doc = " - [`C_HEX_STRING`]")] #![cfg_attr(feature = "format", doc = " - [`C18_LITERAL`]")] #![cfg_attr(feature = "format", doc = " - [`C18_STRING`]")] #![cfg_attr(all(feature = "format", feature = "power-of-two"), doc = " - [`C18_HEX_LITERAL`]")] #![cfg_attr(all(feature = "format", feature = "power-of-two"), doc = " - [`C18_HEX_STRING`]")] #![cfg_attr(feature = "format", doc = " - [`C11_LITERAL`]")] #![cfg_attr(feature = "format", doc = " - [`C11_STRING`]")] #![cfg_attr(all(feature = "format", feature = "power-of-two"), doc = " - [`C11_HEX_LITERAL`]")] #![cfg_attr(all(feature = "format", feature = "power-of-two"), doc = " - [`C11_HEX_STRING`]")] #![cfg_attr(feature = "format", doc = " - [`C99_LITERAL`]")] #![cfg_attr(feature = "format", doc = " - [`C99_STRING`]")] #![cfg_attr(all(feature = "format", feature = "power-of-two"), doc = " - [`C99_HEX_LITERAL`]")] #![cfg_attr(all(feature = "format", feature = "power-of-two"), doc = " - [`C99_HEX_STRING`]")] #![cfg_attr(feature = "format", doc = " - [`C90_LITERAL`]")] #![cfg_attr(feature = "format", doc = " - [`C90_STRING`]")] #![cfg_attr(all(feature = "format", feature = "power-of-two"), doc = " - [`C90_HEX_STRING`]")] #![cfg_attr(feature = "format", doc = " - [`C89_LITERAL`]")] #![cfg_attr(feature = "format", doc = " - [`C89_STRING`]")] #![cfg_attr(all(feature = "format", feature = "power-of-two"), doc = " - [`C89_HEX_STRING`]")] #![cfg_attr(feature = "format", doc = " - [`RUBY_LITERAL`]")] #![cfg_attr(all(feature = "format", feature = "power-of-two"), doc = " - [`RUBY_OCTAL_LITERAL`]")] #![cfg_attr(feature = "format", doc = " - [`RUBY_STRING`]")] #![cfg_attr(feature = "format", doc = " - [`SWIFT_LITERAL`]")] #![cfg_attr(feature = "format", doc = " - [`SWIFT_STRING`]")] #![cfg_attr(feature = "format", doc = " - [`GO_LITERAL`]")] #![cfg_attr(feature = "format", doc = " - [`GO_STRING`]")] #![cfg_attr(feature = "format", doc = " - [`HASKELL_LITERAL`]")] #![cfg_attr(feature = "format", doc = " - [`HASKELL_STRING`]")] #![cfg_attr(feature = "format", doc = " - [`JAVASCRIPT_LITERAL`]")] #![cfg_attr(feature = "format", doc = " - [`JAVASCRIPT_STRING`]")] #![cfg_attr(feature = "format", doc = " - [`PERL_LITERAL`]")] #![cfg_attr(feature = "format", doc = " - [`PERL_STRING`]")] #![cfg_attr(feature = "format", doc = " - [`PHP_LITERAL`]")] #![cfg_attr(feature = "format", doc = " - [`PHP_STRING`]")] #![cfg_attr(feature = "format", doc = " - [`JAVA_LITERAL`]")] #![cfg_attr(feature = "format", doc = " - [`JAVA_STRING`]")] #![cfg_attr(feature = "format", doc = " - [`R_LITERAL`]")] #![cfg_attr(feature = "format", doc = " - [`R_STRING`]")] #![cfg_attr(feature = "format", doc = " - [`KOTLIN_LITERAL`]")] #![cfg_attr(feature = "format", doc = " - [`KOTLIN_STRING`]")] #![cfg_attr(feature = "format", doc = " - [`JULIA_LITERAL`]")] #![cfg_attr(feature = "format", doc = " - [`JULIA_STRING`]")] #![cfg_attr(all(feature = "format", feature = "power-of-two"), doc = " - [`JULIA_HEX_LITERAL`]")] #![cfg_attr(all(feature = "format", feature = "power-of-two"), doc = " - [`JULIA_HEX_STRING`]")] #![cfg_attr(feature = "format", doc = " - [`CSHARP_LITERAL`]")] #![cfg_attr(feature = "format", doc = " - [`CSHARP_STRING`]")] #![cfg_attr(feature = "format", doc = " - [`CSHARP7_LITERAL`]")] #![cfg_attr(feature = "format", doc = " - [`CSHARP7_STRING`]")] #![cfg_attr(feature = "format", doc = " - [`CSHARP6_LITERAL`]")] #![cfg_attr(feature = "format", doc = " - [`CSHARP6_STRING`]")] #![cfg_attr(feature = "format", doc = " - [`CSHARP5_LITERAL`]")] #![cfg_attr(feature = "format", doc = " - [`CSHARP5_STRING`]")] #![cfg_attr(feature = "format", doc = " - [`CSHARP4_LITERAL`]")] #![cfg_attr(feature = "format", doc = " - [`CSHARP4_STRING`]")] #![cfg_attr(feature = "format", doc = " - [`CSHARP3_LITERAL`]")] #![cfg_attr(feature = "format", doc = " - [`CSHARP3_STRING`]")] #![cfg_attr(feature = "format", doc = " - [`CSHARP2_LITERAL`]")] #![cfg_attr(feature = "format", doc = " - [`CSHARP2_STRING`]")] #![cfg_attr(feature = "format", doc = " - [`CSHARP1_LITERAL`]")] #![cfg_attr(feature = "format", doc = " - [`CSHARP1_STRING`]")] #![cfg_attr(feature = "format", doc = " - [`KAWA_LITERAL`]")] #![cfg_attr(feature = "format", doc = " - [`KAWA_STRING`]")] #![cfg_attr(feature = "format", doc = " - [`GAMBITC_LITERAL`]")] #![cfg_attr(feature = "format", doc = " - [`GAMBITC_STRING`]")] #![cfg_attr(feature = "format", doc = " - [`GUILE_LITERAL`]")] #![cfg_attr(feature = "format", doc = " - [`GUILE_STRING`]")] #![cfg_attr(feature = "format", doc = " - [`CLOJURE_LITERAL`]")] #![cfg_attr(feature = "format", doc = " - [`CLOJURE_STRING`]")] #![cfg_attr(feature = "format", doc = " - [`ERLANG_LITERAL`]")] #![cfg_attr(feature = "format", doc = " - [`ERLANG_STRING`]")] #![cfg_attr(feature = "format", doc = " - [`ELM_LITERAL`]")] #![cfg_attr(feature = "format", doc = " - [`ELM_STRING`]")] #![cfg_attr(feature = "format", doc = " - [`SCALA_LITERAL`]")] #![cfg_attr(feature = "format", doc = " - [`SCALA_STRING`]")] #![cfg_attr(feature = "format", doc = " - [`ELIXIR_LITERAL`]")] #![cfg_attr(feature = "format", doc = " - [`ELIXIR_STRING`]")] #![cfg_attr(feature = "format", doc = " - [`FORTRAN_LITERAL`]")] #![cfg_attr(feature = "format", doc = " - [`FORTRAN_STRING`]")] #![cfg_attr(feature = "format", doc = " - [`D_LITERAL`]")] #![cfg_attr(feature = "format", doc = " - [`D_STRING`]")] #![cfg_attr(feature = "format", doc = " - [`COFFEESCRIPT_LITERAL`]")] #![cfg_attr(feature = "format", doc = " - [`COFFEESCRIPT_STRING`]")] #![cfg_attr(feature = "format", doc = " - [`COBOL_LITERAL`]")] #![cfg_attr(feature = "format", doc = " - [`COBOL_STRING`]")] #![cfg_attr(feature = "format", doc = " - [`FSHARP_LITERAL`]")] #![cfg_attr(feature = "format", doc = " - [`FSHARP_STRING`]")] #![cfg_attr(feature = "format", doc = " - [`VB_LITERAL`]")] #![cfg_attr(feature = "format", doc = " - [`VB_STRING`]")] #![cfg_attr(feature = "format", doc = " - [`OCAML_LITERAL`]")] #![cfg_attr(feature = "format", doc = " - [`OCAML_STRING`]")] #![cfg_attr(feature = "format", doc = " - [`OBJECTIVEC_LITERAL`]")] #![cfg_attr(feature = "format", doc = " - [`OBJECTIVEC_STRING`]")] #![cfg_attr(feature = "format", doc = " - [`REASONML_LITERAL`]")] #![cfg_attr(feature = "format", doc = " - [`REASONML_STRING`]")] #![cfg_attr(feature = "format", doc = " - [`OCTAVE_LITERAL`]")] #![cfg_attr(feature = "format", doc = " - [`OCTAVE_STRING`]")] #![cfg_attr(feature = "format", doc = " - [`MATLAB_LITERAL`]")] #![cfg_attr(feature = "format", doc = " - [`MATLAB_STRING`]")] #![cfg_attr(feature = "format", doc = " - [`ZIG_LITERAL`]")] #![cfg_attr(feature = "format", doc = " - [`ZIG_STRING`]")] #![cfg_attr(feature = "format", doc = " - [`SAGE_LITERAL`]")] #![cfg_attr(feature = "format", doc = " - [`SAGE_STRING`]")] #![cfg_attr(feature = "format", doc = " - [`JSON`]")] #![cfg_attr(feature = "format", doc = " - [`TOML`]")] #![cfg_attr(feature = "format", doc = " - [`YAML`]")] #![cfg_attr(feature = "format", doc = " - [`XML`]")] #![cfg_attr(feature = "format", doc = " - [`SQLITE`]")] #![cfg_attr(feature = "format", doc = " - [`POSTGRESQL`]")] #![cfg_attr(feature = "format", doc = " - [`MYSQL`]")] #![cfg_attr(feature = "format", doc = " - [`MONGODB`]")] //! //! # Syntax Flags //! //! Bitflags to get and set syntax flags for the format packed struct. //! //! - [`REQUIRED_INTEGER_DIGITS`] //! - [`REQUIRED_FRACTION_DIGITS`] //! - [`REQUIRED_EXPONENT_DIGITS`] //! - [`REQUIRED_MANTISSA_DIGITS`] //! - [`REQUIRED_DIGITS`] //! - [`NO_POSITIVE_MANTISSA_SIGN`] //! - [`REQUIRED_MANTISSA_SIGN`] //! - [`NO_EXPONENT_NOTATION`] //! - [`NO_POSITIVE_EXPONENT_SIGN`] //! - [`REQUIRED_EXPONENT_SIGN`] //! - [`NO_EXPONENT_WITHOUT_FRACTION`] //! - [`NO_SPECIAL`] //! - [`CASE_SENSITIVE_SPECIAL`] //! - [`NO_INTEGER_LEADING_ZEROS`] //! - [`NO_FLOAT_LEADING_ZEROS`] //! - [`REQUIRED_EXPONENT_NOTATION`] //! - [`CASE_SENSITIVE_EXPONENT`] //! - [`CASE_SENSITIVE_BASE_PREFIX`] //! - [`CASE_SENSITIVE_BASE_SUFFIX`] //! //! # Digit Separator Flags //! //! Bitflags to get and set digit separators flags for the format //! packed struct. //! //! - [`INTEGER_INTERNAL_DIGIT_SEPARATOR`] //! - [`FRACTION_INTERNAL_DIGIT_SEPARATOR`] //! - [`EXPONENT_INTERNAL_DIGIT_SEPARATOR`] //! - [`INTEGER_LEADING_DIGIT_SEPARATOR`] //! - [`FRACTION_LEADING_DIGIT_SEPARATOR`] //! - [`EXPONENT_LEADING_DIGIT_SEPARATOR`] //! - [`INTEGER_TRAILING_DIGIT_SEPARATOR`] //! - [`FRACTION_TRAILING_DIGIT_SEPARATOR`] //! - [`EXPONENT_TRAILING_DIGIT_SEPARATOR`] //! - [`INTEGER_CONSECUTIVE_DIGIT_SEPARATOR`] //! - [`FRACTION_CONSECUTIVE_DIGIT_SEPARATOR`] //! - [`EXPONENT_CONSECUTIVE_DIGIT_SEPARATOR`] //! - [`INTERNAL_DIGIT_SEPARATOR`] //! - [`LEADING_DIGIT_SEPARATOR`] //! - [`TRAILING_DIGIT_SEPARATOR`] //! - [`CONSECUTIVE_DIGIT_SEPARATOR`] //! - [`SPECIAL_DIGIT_SEPARATOR`] //! //! # Character Shifts and Masks //! //! Bitmasks and bit shifts to get and set control characters for the format //! packed struct. //! //! - [`DIGIT_SEPARATOR_SHIFT`] //! - [`DIGIT_SEPARATOR`] //! - [`BASE_PREFIX_SHIFT`] //! - [`BASE_PREFIX`] //! - [`BASE_SUFFIX_SHIFT`] //! - [`BASE_SUFFIX`] //! - [`MANTISSA_RADIX_SHIFT`] //! - [`MANTISSA_RADIX`] //! - [`RADIX_SHIFT`] //! - [`RADIX`] //! - [`EXPONENT_BASE_SHIFT`] //! - [`EXPONENT_BASE`] //! - [`EXPONENT_RADIX_SHIFT`] //! - [`EXPONENT_RADIX`] //! //! # Character Functions //! //! Functions to get control characters from the format packed struct. //! //! - [`digit_separator`] //! - [`base_prefix`] //! - [`base_suffix`] //! - [`mantissa_radix`] //! - [`exponent_base`] //! - [`exponent_radix`] //! - [`radix_from_flags`] //! //! # Validators //! //! Functions to validate control characters for the format packed struct. //! //! - [`is_valid_digit_separator`] //! - [`is_valid_base_prefix`] //! - [`is_valid_base_suffix`] //! - [`is_valid_punctuation`] //! - [`is_valid_radix`] use static_assertions::const_assert; use crate::error::Error; #[cfg(feature = "format")] pub use crate::feature_format::*; pub use crate::format_builder::*; pub use crate::format_flags::*; #[cfg(not(feature = "format"))] pub use crate::not_feature_format::*; /// Determine if the format packed struct is valid. #[inline(always)] pub const fn format_is_valid() -> bool { NumberFormat:: {}.is_valid() } /// Get the error type from the format packed struct. /// /// An error type of `Error::Success` means the format is valid, any /// other error signifies an invalid format. #[inline(always)] pub const fn format_error() -> Error { NumberFormat:: {}.error() } /// Standard number format. This is identical to the Rust string format. pub const STANDARD: u128 = NumberFormatBuilder::new().build(); const_assert!(NumberFormat::<{ STANDARD }> {}.is_valid()); lexical-util-1.0.6/src/format_builder.rs000064400000000000000000001222651046102023000163670ustar 00000000000000//! Builder for the number format. use core::{mem, num}; use static_assertions::const_assert; use crate::format_flags as flags; /// Type with the exact same size as a `u8`. pub type OptionU8 = Option; // Ensure the sizes are identical. const_assert!(mem::size_of::() == mem::size_of::()); /// Add single flag to `SyntaxFormat`. macro_rules! add_flag { ($format:ident, $bool:expr, $flag:ident) => { if $bool { $format |= flags::$flag; } }; } /// Add multiple flags to `SyntaxFormat`. macro_rules! add_flags { ($format:ident ; $($bool:expr, $flag:ident ;)*) => {{ $(add_flag!($format, $bool, $flag);)* }}; } /// Determine if a flag is set in the format. macro_rules! has_flag { ($format:ident, $flag:ident) => { $format & flags::$flag != 0 }; } /// Unwrap `Option` as a const fn. #[inline(always)] const fn unwrap_or_zero(option: OptionU8) -> u8 { match option { Some(x) => x.get(), None => 0, } } /// Build number format from specifications. /// /// Returns the format on calling build if it was able to compile the format, /// otherwise, returns None. /// /// # Fields /// /// * `digit_separator` - Character to separate digits. /// * `mantissa_radix` - Radix for mantissa digits. /// * `exponent_base` - Base for the exponent. /// * `exponent_radix` - Radix for the exponent digits. /// * `base_prefix` - Optional character for the /// base prefix. /// * `base_suffix` - Optional character for the /// base suffix. /// * `required_integer_digits` - If digits are required before /// the decimal point. /// * `required_fraction_digits` - If digits are required after /// the decimal point. /// * `required_exponent_digits` - If digits are required after /// the exponent character. /// * `required_mantissa_digits` - If at least 1 significant /// digit is required. /// * `no_positive_mantissa_sign` - If positive sign before the /// mantissa is not allowed. /// * `required_mantissa_sign` - If positive sign before the /// mantissa is required. /// * `no_exponent_notation` - If exponent notation is not /// allowed. /// * `no_positive_exponent_sign` - If positive sign before the /// exponent is not allowed. /// * `required_exponent_sign` - If sign before the exponent is /// required. /// * `no_exponent_without_fraction` - If exponent without fraction /// is not allowed. /// * `no_special` - If special (non-finite) values /// are not allowed. /// * `case_sensitive_special` - If special (non-finite) values /// are case-sensitive. /// * `no_integer_leading_zeros` - If leading zeros before an /// integer are not allowed. /// * `no_float_leading_zeros` - If leading zeros before a /// float are not allowed. /// * `required_exponent_notation` - If exponent notation is /// required. /// * `case_sensitive_exponent` - If exponent characters are /// case-sensitive. /// * `case_sensitive_base_prefix` - If base prefixes are /// case-sensitive. /// * `case_sensitive_base_suffix` - If base suffixes are /// case-sensitive. /// * `integer_internal_digit_separator` - If digit separators are /// allowed between integer digits. /// * `fraction_internal_digit_separator` - If digit separators are /// allowed between fraction digits. /// * `exponent_internal_digit_separator` - If digit separators are /// allowed between exponent digits. /// * `integer_leading_digit_separator` - If a digit separator is /// allowed before any integer digits. /// * `fraction_leading_digit_separator` - If a digit separator is /// allowed before any fraction digits. /// * `exponent_leading_digit_separator` - If a digit separator is /// allowed before any exponent digits. /// * `integer_trailing_digit_separator` - If a digit separator is /// allowed after any integer digits. /// * `fraction_trailing_digit_separator` - If a digit separator is /// allowed after any fraction digits. /// * `exponent_trailing_digit_separator` - If a digit separator is /// allowed after any exponent digits. /// * `integer_consecutive_digit_separator` - If multiple consecutive /// integer digit separators are allowed. /// * `fraction_consecutive_digit_separator` - If multiple consecutive /// fraction digit separators are allowed. /// * `special_digit_separator` - If any digit separators are /// allowed in special (non-finite) values. /// /// # Write Integer Fields /// /// No fields are used for writing integers. /// /// # Parse Integer Fields /// /// These fields are used for parsing integers: /// /// * `digit_separator` /// * `mantissa_radix` /// * `base_prefix` /// * `base_suffix` /// * `no_positive_mantissa_sign` /// * `required_mantissa_sign` /// * `no_integer_leading_zeros` /// * `integer_internal_digit_separator` /// * `integer_leading_digit_separator` /// * `integer_trailing_digit_separator` /// * `integer_consecutive_digit_separator` /// /// # Write Float Fields /// /// These fields are used for writing floats: /// /// * `mantissa_radix` /// * `exponent_base` /// * `exponent_radix` /// * `no_positive_mantissa_sign` /// * `required_mantissa_sign` /// * `no_exponent_notation` /// * `no_positive_exponent_sign` /// * `required_exponent_sign` /// * `required_exponent_notation` /// /// # Parse Float Fields /// /// These fields are used for parsing floats: /// /// * `digit_separator` /// * `mantissa_radix` /// * `exponent_base` /// * `exponent_radix` /// * `base_prefix` /// * `base_suffix` /// * `required_integer_digits` /// * `required_fraction_digits` /// * `required_exponent_digits` /// * `no_positive_mantissa_sign` /// * `required_mantissa_sign` /// * `no_exponent_notation` /// * `no_positive_exponent_sign` /// * `required_exponent_sign` /// * `no_exponent_without_fraction` /// * `no_special` /// * `case_sensitive_special` /// * `no_integer_leading_zeros` /// * `no_float_leading_zeros` /// * `required_exponent_notation` /// * `case_sensitive_exponent` /// * `case_sensitive_base_prefix` /// * `case_sensitive_base_suffix` /// * `integer_internal_digit_separator` /// * `fraction_internal_digit_separator` /// * `exponent_internal_digit_separator` /// * `integer_leading_digit_separator` /// * `fraction_leading_digit_separator` /// * `exponent_leading_digit_separator` /// * `integer_trailing_digit_separator` /// * `fraction_trailing_digit_separator` /// * `exponent_trailing_digit_separator` /// * `integer_consecutive_digit_separator` /// * `fraction_consecutive_digit_separator` /// * `special_digit_separator` pub struct NumberFormatBuilder { digit_separator: OptionU8, base_prefix: OptionU8, base_suffix: OptionU8, mantissa_radix: u8, exponent_base: OptionU8, exponent_radix: OptionU8, required_integer_digits: bool, required_fraction_digits: bool, required_exponent_digits: bool, required_mantissa_digits: bool, no_positive_mantissa_sign: bool, required_mantissa_sign: bool, no_exponent_notation: bool, no_positive_exponent_sign: bool, required_exponent_sign: bool, no_exponent_without_fraction: bool, no_special: bool, case_sensitive_special: bool, no_integer_leading_zeros: bool, no_float_leading_zeros: bool, required_exponent_notation: bool, case_sensitive_exponent: bool, case_sensitive_base_prefix: bool, case_sensitive_base_suffix: bool, integer_internal_digit_separator: bool, fraction_internal_digit_separator: bool, exponent_internal_digit_separator: bool, integer_leading_digit_separator: bool, fraction_leading_digit_separator: bool, exponent_leading_digit_separator: bool, integer_trailing_digit_separator: bool, fraction_trailing_digit_separator: bool, exponent_trailing_digit_separator: bool, integer_consecutive_digit_separator: bool, fraction_consecutive_digit_separator: bool, exponent_consecutive_digit_separator: bool, special_digit_separator: bool, } impl NumberFormatBuilder { // CONSTRUCTORS /// Create new `NumberFormatBuilder` with default arguments. #[inline(always)] pub const fn new() -> Self { Self { digit_separator: None, base_prefix: None, base_suffix: None, mantissa_radix: 10, exponent_base: None, exponent_radix: None, required_integer_digits: false, required_fraction_digits: false, required_exponent_digits: true, required_mantissa_digits: true, no_positive_mantissa_sign: false, required_mantissa_sign: false, no_exponent_notation: false, no_positive_exponent_sign: false, required_exponent_sign: false, no_exponent_without_fraction: false, no_special: false, case_sensitive_special: false, no_integer_leading_zeros: false, no_float_leading_zeros: false, required_exponent_notation: false, case_sensitive_exponent: false, case_sensitive_base_prefix: false, case_sensitive_base_suffix: false, integer_internal_digit_separator: false, fraction_internal_digit_separator: false, exponent_internal_digit_separator: false, integer_leading_digit_separator: false, fraction_leading_digit_separator: false, exponent_leading_digit_separator: false, integer_trailing_digit_separator: false, fraction_trailing_digit_separator: false, exponent_trailing_digit_separator: false, integer_consecutive_digit_separator: false, fraction_consecutive_digit_separator: false, exponent_consecutive_digit_separator: false, special_digit_separator: false, } } /// Create number format for standard, binary number. #[cfg(feature = "power-of-two")] pub const fn binary() -> u128 { Self::from_radix(2) } /// Create number format for standard, octal number. #[cfg(feature = "power-of-two")] pub const fn octal() -> u128 { Self::from_radix(8) } /// Create number format for standard, decimal number. pub const fn decimal() -> u128 { let mut builder = Self::new(); builder.mantissa_radix = 10; builder.exponent_base = num::NonZeroU8::new(10); builder.exponent_radix = num::NonZeroU8::new(10); builder.build() } /// Create number format for standard, hexadecimal number. #[cfg(feature = "power-of-two")] pub const fn hexadecimal() -> u128 { Self::from_radix(16) } /// Create number format from radix. #[cfg(feature = "power-of-two")] pub const fn from_radix(radix: u8) -> u128 { Self::new() .radix(radix) .exponent_base(num::NonZeroU8::new(radix)) .exponent_radix(num::NonZeroU8::new(radix)) .build() } // GETTERS /// Get the digit separator for the number format. #[inline(always)] pub const fn get_digit_separator(&self) -> OptionU8 { self.digit_separator } /// Get the radix for mantissa digits. #[inline(always)] pub const fn get_mantissa_radix(&self) -> u8 { self.mantissa_radix } /// Get the radix for the exponent. #[inline(always)] pub const fn get_exponent_base(&self) -> OptionU8 { self.exponent_base } /// Get the radix for exponent digits. #[inline(always)] pub const fn get_exponent_radix(&self) -> OptionU8 { self.exponent_radix } /// Get the optional character for the base prefix. #[inline(always)] pub const fn get_base_prefix(&self) -> OptionU8 { self.base_prefix } /// Get the optional character for the base suffix. #[inline(always)] pub const fn get_base_suffix(&self) -> OptionU8 { self.base_suffix } /// Get if digits are required before the decimal point. #[inline(always)] pub const fn get_required_integer_digits(&self) -> bool { self.required_integer_digits } /// Get if digits are required after the decimal point. #[inline(always)] pub const fn get_required_fraction_digits(&self) -> bool { self.required_fraction_digits } /// Get if digits are required after the exponent character. #[inline(always)] pub const fn get_required_exponent_digits(&self) -> bool { self.required_exponent_digits } /// Get if at least 1 significant digit is required. #[inline(always)] pub const fn get_required_mantissa_digits(&self) -> bool { self.required_mantissa_digits } /// Get if a positive sign before the mantissa is not allowed. #[inline(always)] pub const fn get_no_positive_mantissa_sign(&self) -> bool { self.no_positive_mantissa_sign } /// Get if a sign symbol before the mantissa is required. #[inline(always)] pub const fn get_required_mantissa_sign(&self) -> bool { self.required_mantissa_sign } /// Get if exponent notation is not allowed. #[inline(always)] pub const fn get_no_exponent_notation(&self) -> bool { self.no_exponent_notation } /// Get if a positive sign before the exponent is not allowed. #[inline(always)] pub const fn get_no_positive_exponent_sign(&self) -> bool { self.no_positive_exponent_sign } /// Get if a sign symbol before the exponent is required. #[inline(always)] pub const fn get_required_exponent_sign(&self) -> bool { self.required_exponent_sign } /// Get if an exponent without fraction is not allowed. #[inline(always)] pub const fn get_no_exponent_without_fraction(&self) -> bool { self.no_exponent_without_fraction } /// Get if special (non-finite) values are not allowed. #[inline(always)] pub const fn get_no_special(&self) -> bool { self.no_special } /// Get if special (non-finite) values are case-sensitive. #[inline(always)] pub const fn get_case_sensitive_special(&self) -> bool { self.case_sensitive_special } /// Get if leading zeros before an integer are not allowed. #[inline(always)] pub const fn get_no_integer_leading_zeros(&self) -> bool { self.no_integer_leading_zeros } /// Get if leading zeros before a float are not allowed. #[inline(always)] pub const fn get_no_float_leading_zeros(&self) -> bool { self.no_float_leading_zeros } /// Get if exponent notation is required. #[inline(always)] pub const fn get_required_exponent_notation(&self) -> bool { self.required_exponent_notation } /// Get if exponent characters are case-sensitive. #[inline(always)] pub const fn get_case_sensitive_exponent(&self) -> bool { self.case_sensitive_exponent } /// Get if base prefixes are case-sensitive. #[inline(always)] pub const fn get_case_sensitive_base_prefix(&self) -> bool { self.case_sensitive_base_prefix } /// Get if base suffixes are case-sensitive. #[inline(always)] pub const fn get_case_sensitive_base_suffix(&self) -> bool { self.case_sensitive_base_suffix } /// Get if digit separators are allowed between integer digits. /// /// This will not consider an input of only the digit separator /// to be a valid separator: the digit separator must be surrounded by /// digits. #[inline(always)] pub const fn get_integer_internal_digit_separator(&self) -> bool { self.integer_internal_digit_separator } /// Get if digit separators are allowed between fraction digits. /// /// This will not consider an input of only the digit separator /// to be a valid separator: the digit separator must be surrounded by /// digits. #[inline(always)] pub const fn get_fraction_internal_digit_separator(&self) -> bool { self.fraction_internal_digit_separator } /// Get if digit separators are allowed between exponent digits. /// /// This will not consider an input of only the digit separator /// to be a valid separator: the digit separator must be surrounded by /// digits. #[inline(always)] pub const fn get_exponent_internal_digit_separator(&self) -> bool { self.exponent_internal_digit_separator } /// Get if a digit separator is allowed before any integer digits. /// /// This will consider an input of only the digit separator /// to be a identical to empty input. #[inline(always)] pub const fn get_integer_leading_digit_separator(&self) -> bool { self.integer_leading_digit_separator } /// Get if a digit separator is allowed before any fraction digits. /// /// This will consider an input of only the digit separator /// to be a identical to empty input. #[inline(always)] pub const fn get_fraction_leading_digit_separator(&self) -> bool { self.fraction_leading_digit_separator } /// Get if a digit separator is allowed before any exponent digits. /// /// This will consider an input of only the digit separator /// to be a identical to empty input. #[inline(always)] pub const fn get_exponent_leading_digit_separator(&self) -> bool { self.exponent_leading_digit_separator } /// Get if a digit separator is allowed after any integer digits. /// /// This will consider an input of only the digit separator /// to be a identical to empty input. #[inline(always)] pub const fn get_integer_trailing_digit_separator(&self) -> bool { self.integer_trailing_digit_separator } /// Get if a digit separator is allowed after any fraction digits. /// /// This will consider an input of only the digit separator /// to be a identical to empty input. #[inline(always)] pub const fn get_fraction_trailing_digit_separator(&self) -> bool { self.fraction_trailing_digit_separator } /// Get if a digit separator is allowed after any exponent digits. /// /// This will consider an input of only the digit separator /// to be a identical to empty input. #[inline(always)] pub const fn get_exponent_trailing_digit_separator(&self) -> bool { self.exponent_trailing_digit_separator } /// Get if multiple consecutive integer digit separators are allowed. #[inline(always)] pub const fn get_integer_consecutive_digit_separator(&self) -> bool { self.integer_consecutive_digit_separator } /// Get if multiple consecutive fraction digit separators are allowed. #[inline(always)] pub const fn get_fraction_consecutive_digit_separator(&self) -> bool { self.fraction_consecutive_digit_separator } /// Get if multiple consecutive exponent digit separators are allowed. #[inline(always)] pub const fn get_exponent_consecutive_digit_separator(&self) -> bool { self.exponent_consecutive_digit_separator } /// Get if any digit separators are allowed in special (non-finite) values. #[inline(always)] pub const fn get_special_digit_separator(&self) -> bool { self.special_digit_separator } // SETTERS /// Set the digit separator for the number format. #[inline(always)] #[cfg(feature = "format")] pub const fn digit_separator(mut self, character: OptionU8) -> Self { self.digit_separator = character; self } /// Alias for mantissa radix. #[inline(always)] #[cfg(feature = "power-of-two")] pub const fn radix(self, radix: u8) -> Self { self.mantissa_radix(radix) } /// Set the radix for mantissa digits. #[inline(always)] #[cfg(feature = "power-of-two")] pub const fn mantissa_radix(mut self, radix: u8) -> Self { self.mantissa_radix = radix; self } /// Set the radix for the exponent. #[inline(always)] #[cfg(feature = "power-of-two")] pub const fn exponent_base(mut self, base: OptionU8) -> Self { self.exponent_base = base; self } /// Set the radix for exponent digits. #[inline(always)] #[cfg(feature = "power-of-two")] pub const fn exponent_radix(mut self, radix: OptionU8) -> Self { self.exponent_radix = radix; self } /// Set the optional character for the base prefix. #[inline(always)] #[cfg(all(feature = "power-of-two", feature = "format"))] pub const fn base_prefix(mut self, base_prefix: OptionU8) -> Self { self.base_prefix = base_prefix; self } /// Set the optional character for the base suffix. #[inline(always)] #[cfg(all(feature = "power-of-two", feature = "format"))] pub const fn base_suffix(mut self, base_suffix: OptionU8) -> Self { self.base_suffix = base_suffix; self } /// Set if digits are required before the decimal point. #[inline(always)] #[cfg(feature = "format")] pub const fn required_integer_digits(mut self, flag: bool) -> Self { self.required_integer_digits = flag; self } /// Set if digits are required after the decimal point. #[inline(always)] #[cfg(feature = "format")] pub const fn required_fraction_digits(mut self, flag: bool) -> Self { self.required_fraction_digits = flag; self } /// Set if digits are required after the exponent character. #[inline(always)] #[cfg(feature = "format")] pub const fn required_exponent_digits(mut self, flag: bool) -> Self { self.required_exponent_digits = flag; self } /// Set if at least 1 significant digit is required. #[inline(always)] #[cfg(feature = "format")] pub const fn required_mantissa_digits(mut self, flag: bool) -> Self { self.required_mantissa_digits = flag; self } /// Set if digits are required for all float components. #[inline(always)] #[cfg(feature = "format")] pub const fn required_digits(mut self, flag: bool) -> Self { self = self.required_integer_digits(flag); self = self.required_fraction_digits(flag); self = self.required_exponent_digits(flag); self = self.required_mantissa_digits(flag); self } /// Set if a positive sign before the mantissa is not allowed. #[inline(always)] #[cfg(feature = "format")] pub const fn no_positive_mantissa_sign(mut self, flag: bool) -> Self { self.no_positive_mantissa_sign = flag; self } /// Set if a sign symbol before the mantissa is required. #[inline(always)] #[cfg(feature = "format")] pub const fn required_mantissa_sign(mut self, flag: bool) -> Self { self.required_mantissa_sign = flag; self } /// Set if exponent notation is not allowed. #[inline(always)] #[cfg(feature = "format")] pub const fn no_exponent_notation(mut self, flag: bool) -> Self { self.no_exponent_notation = flag; self } /// Set if a positive sign before the exponent is not allowed. #[inline(always)] #[cfg(feature = "format")] pub const fn no_positive_exponent_sign(mut self, flag: bool) -> Self { self.no_positive_exponent_sign = flag; self } /// Set if a sign symbol before the exponent is required. #[inline(always)] #[cfg(feature = "format")] pub const fn required_exponent_sign(mut self, flag: bool) -> Self { self.required_exponent_sign = flag; self } /// Set if an exponent without fraction is not allowed. #[inline(always)] #[cfg(feature = "format")] pub const fn no_exponent_without_fraction(mut self, flag: bool) -> Self { self.no_exponent_without_fraction = flag; self } /// Set if special (non-finite) values are not allowed. #[inline(always)] #[cfg(feature = "format")] pub const fn no_special(mut self, flag: bool) -> Self { self.no_special = flag; self } /// Set if special (non-finite) values are case-sensitive. #[inline(always)] #[cfg(feature = "format")] pub const fn case_sensitive_special(mut self, flag: bool) -> Self { self.case_sensitive_special = flag; self } /// Set if leading zeros before an integer are not allowed. #[inline(always)] #[cfg(feature = "format")] pub const fn no_integer_leading_zeros(mut self, flag: bool) -> Self { self.no_integer_leading_zeros = flag; self } /// Set if leading zeros before a float are not allowed. #[inline(always)] #[cfg(feature = "format")] pub const fn no_float_leading_zeros(mut self, flag: bool) -> Self { self.no_float_leading_zeros = flag; self } /// Set if exponent notation is required. #[inline(always)] #[cfg(feature = "format")] pub const fn required_exponent_notation(mut self, flag: bool) -> Self { self.required_exponent_notation = flag; self } /// Set if exponent characters are case-sensitive. #[inline(always)] #[cfg(feature = "format")] pub const fn case_sensitive_exponent(mut self, flag: bool) -> Self { self.case_sensitive_exponent = flag; self } /// Set if base prefixes are case-sensitive. #[inline(always)] #[cfg(all(feature = "power-of-two", feature = "format"))] pub const fn case_sensitive_base_prefix(mut self, flag: bool) -> Self { self.case_sensitive_base_prefix = flag; self } /// Set if base suffixes are case-sensitive. #[inline(always)] #[cfg(all(feature = "power-of-two", feature = "format"))] pub const fn case_sensitive_base_suffix(mut self, flag: bool) -> Self { self.case_sensitive_base_suffix = flag; self } /// Set if digit separators are allowed between integer digits. /// /// This will not consider an input of only the digit separator /// to be a valid separator: the digit separator must be surrounded by /// digits. #[inline(always)] #[cfg(feature = "format")] pub const fn integer_internal_digit_separator(mut self, flag: bool) -> Self { self.integer_internal_digit_separator = flag; self } /// Set if digit separators are allowed between fraction digits. /// /// This will not consider an input of only the digit separator /// to be a valid separator: the digit separator must be surrounded by /// digits. #[inline(always)] #[cfg(feature = "format")] pub const fn fraction_internal_digit_separator(mut self, flag: bool) -> Self { self.fraction_internal_digit_separator = flag; self } /// Set if digit separators are allowed between exponent digits. /// /// This will not consider an input of only the digit separator /// to be a valid separator: the digit separator must be surrounded by /// digits. #[inline(always)] #[cfg(feature = "format")] pub const fn exponent_internal_digit_separator(mut self, flag: bool) -> Self { self.exponent_internal_digit_separator = flag; self } /// Set all internal digit separator flags. /// /// This will not consider an input of only the digit separator /// to be a valid separator: the digit separator must be surrounded by /// digits. #[inline(always)] #[cfg(feature = "format")] pub const fn internal_digit_separator(mut self, flag: bool) -> Self { self = self.integer_internal_digit_separator(flag); self = self.fraction_internal_digit_separator(flag); self = self.exponent_internal_digit_separator(flag); self } /// Set if a digit separator is allowed before any integer digits. /// /// This will consider an input of only the digit separator /// to be a identical to empty input. #[inline(always)] #[cfg(feature = "format")] pub const fn integer_leading_digit_separator(mut self, flag: bool) -> Self { self.integer_leading_digit_separator = flag; self } /// Set if a digit separator is allowed before any fraction digits. /// /// This will consider an input of only the digit separator /// to be a identical to empty input. #[inline(always)] #[cfg(feature = "format")] pub const fn fraction_leading_digit_separator(mut self, flag: bool) -> Self { self.fraction_leading_digit_separator = flag; self } /// Set if a digit separator is allowed before any exponent digits. /// /// This will consider an input of only the digit separator /// to be a identical to empty input. #[inline(always)] #[cfg(feature = "format")] pub const fn exponent_leading_digit_separator(mut self, flag: bool) -> Self { self.exponent_leading_digit_separator = flag; self } /// Set all leading digit separator flags. /// /// This will consider an input of only the digit separator /// to be a identical to empty input. #[inline(always)] #[cfg(feature = "format")] pub const fn leading_digit_separator(mut self, flag: bool) -> Self { self = self.integer_leading_digit_separator(flag); self = self.fraction_leading_digit_separator(flag); self = self.exponent_leading_digit_separator(flag); self } /// Set if a digit separator is allowed after any integer digits. /// /// This will consider an input of only the digit separator /// to be a identical to empty input. #[inline(always)] #[cfg(feature = "format")] pub const fn integer_trailing_digit_separator(mut self, flag: bool) -> Self { self.integer_trailing_digit_separator = flag; self } /// Set if a digit separator is allowed after any fraction digits. /// /// This will consider an input of only the digit separator /// to be a identical to empty input. #[inline(always)] #[cfg(feature = "format")] pub const fn fraction_trailing_digit_separator(mut self, flag: bool) -> Self { self.fraction_trailing_digit_separator = flag; self } /// Set if a digit separator is allowed after any exponent digits. /// /// This will consider an input of only the digit separator /// to be a identical to empty input. #[inline(always)] #[cfg(feature = "format")] pub const fn exponent_trailing_digit_separator(mut self, flag: bool) -> Self { self.exponent_trailing_digit_separator = flag; self } /// Set all trailing digit separator flags. /// /// This will consider an input of only the digit separator /// to be a identical to empty input. #[inline(always)] #[cfg(feature = "format")] pub const fn trailing_digit_separator(mut self, flag: bool) -> Self { self = self.integer_trailing_digit_separator(flag); self = self.fraction_trailing_digit_separator(flag); self = self.exponent_trailing_digit_separator(flag); self } /// Set if multiple consecutive integer digit separators are allowed. #[inline(always)] #[cfg(feature = "format")] pub const fn integer_consecutive_digit_separator(mut self, flag: bool) -> Self { self.integer_consecutive_digit_separator = flag; self } /// Set if multiple consecutive fraction digit separators are allowed. #[inline(always)] #[cfg(feature = "format")] pub const fn fraction_consecutive_digit_separator(mut self, flag: bool) -> Self { self.fraction_consecutive_digit_separator = flag; self } /// Set if multiple consecutive exponent digit separators are allowed. #[inline(always)] #[cfg(feature = "format")] pub const fn exponent_consecutive_digit_separator(mut self, flag: bool) -> Self { self.exponent_consecutive_digit_separator = flag; self } /// Set all consecutive digit separator flags. #[inline(always)] #[cfg(feature = "format")] pub const fn consecutive_digit_separator(mut self, flag: bool) -> Self { self = self.integer_consecutive_digit_separator(flag); self = self.fraction_consecutive_digit_separator(flag); self = self.exponent_consecutive_digit_separator(flag); self } /// Set if any digit separators are allowed in special (non-finite) values. #[inline(always)] #[cfg(feature = "format")] pub const fn special_digit_separator(mut self, flag: bool) -> Self { self.special_digit_separator = flag; self } /// Set all digit separator flag masks. #[inline(always)] #[cfg(feature = "format")] pub const fn digit_separator_flags(mut self, flag: bool) -> Self { self = self.integer_digit_separator_flags(flag); self = self.fraction_digit_separator_flags(flag); self = self.exponent_digit_separator_flags(flag); self = self.special_digit_separator(flag); self } /// Set all integer digit separator flag masks. #[inline(always)] #[cfg(feature = "format")] pub const fn integer_digit_separator_flags(mut self, flag: bool) -> Self { self = self.integer_internal_digit_separator(flag); self = self.integer_leading_digit_separator(flag); self = self.integer_trailing_digit_separator(flag); self = self.integer_consecutive_digit_separator(flag); self } /// Set all fraction digit separator flag masks. #[inline(always)] #[cfg(feature = "format")] pub const fn fraction_digit_separator_flags(mut self, flag: bool) -> Self { self = self.fraction_internal_digit_separator(flag); self = self.fraction_leading_digit_separator(flag); self = self.fraction_trailing_digit_separator(flag); self = self.fraction_consecutive_digit_separator(flag); self } /// Set all exponent digit separator flag masks. #[inline(always)] #[cfg(feature = "format")] pub const fn exponent_digit_separator_flags(mut self, flag: bool) -> Self { self = self.exponent_internal_digit_separator(flag); self = self.exponent_leading_digit_separator(flag); self = self.exponent_trailing_digit_separator(flag); self = self.exponent_consecutive_digit_separator(flag); self } // BUILDER /// Create 128-bit, packed number format struct from builder options. /// /// NOTE: This function will never fail, due to issues with panicking /// (and therefore unwrapping Errors/Options) in const fns. It is /// therefore up to you to ensure the format is valid, called via the /// `is_valid` function on `NumberFormat`. #[inline(always)] pub const fn build(&self) -> u128 { let mut format: u128 = 0; add_flags!( format ; self.required_integer_digits, REQUIRED_INTEGER_DIGITS ; self.required_fraction_digits, REQUIRED_FRACTION_DIGITS ; self.required_exponent_digits, REQUIRED_EXPONENT_DIGITS ; self.required_mantissa_digits, REQUIRED_MANTISSA_DIGITS ; self.no_positive_mantissa_sign, NO_POSITIVE_MANTISSA_SIGN ; self.required_mantissa_sign, REQUIRED_MANTISSA_SIGN ; self.no_exponent_notation, NO_EXPONENT_NOTATION ; self.no_positive_exponent_sign, NO_POSITIVE_EXPONENT_SIGN ; self.required_exponent_sign, REQUIRED_EXPONENT_SIGN ; self.no_exponent_without_fraction, NO_EXPONENT_WITHOUT_FRACTION ; self.no_special, NO_SPECIAL ; self.case_sensitive_special, CASE_SENSITIVE_SPECIAL ; self.no_integer_leading_zeros, NO_INTEGER_LEADING_ZEROS ; self.no_float_leading_zeros, NO_FLOAT_LEADING_ZEROS ; self.required_exponent_notation, REQUIRED_EXPONENT_NOTATION ; self.case_sensitive_exponent, CASE_SENSITIVE_EXPONENT ; self.case_sensitive_base_prefix, CASE_SENSITIVE_BASE_PREFIX ; self.case_sensitive_base_suffix, CASE_SENSITIVE_BASE_SUFFIX ; self.integer_internal_digit_separator, INTEGER_INTERNAL_DIGIT_SEPARATOR ; self.fraction_internal_digit_separator, FRACTION_INTERNAL_DIGIT_SEPARATOR ; self.exponent_internal_digit_separator, EXPONENT_INTERNAL_DIGIT_SEPARATOR ; self.integer_leading_digit_separator, INTEGER_LEADING_DIGIT_SEPARATOR ; self.fraction_leading_digit_separator, FRACTION_LEADING_DIGIT_SEPARATOR ; self.exponent_leading_digit_separator, EXPONENT_LEADING_DIGIT_SEPARATOR ; self.integer_trailing_digit_separator, INTEGER_TRAILING_DIGIT_SEPARATOR ; self.fraction_trailing_digit_separator, FRACTION_TRAILING_DIGIT_SEPARATOR ; self.exponent_trailing_digit_separator, EXPONENT_TRAILING_DIGIT_SEPARATOR ; self.integer_consecutive_digit_separator, INTEGER_CONSECUTIVE_DIGIT_SEPARATOR ; self.fraction_consecutive_digit_separator, FRACTION_CONSECUTIVE_DIGIT_SEPARATOR ; self.exponent_consecutive_digit_separator, EXPONENT_CONSECUTIVE_DIGIT_SEPARATOR ; self.special_digit_separator, SPECIAL_DIGIT_SEPARATOR ; ); if format & flags::DIGIT_SEPARATOR_FLAG_MASK != 0 { format |= (unwrap_or_zero(self.digit_separator) as u128) << flags::DIGIT_SEPARATOR_SHIFT; } format |= (unwrap_or_zero(self.base_prefix) as u128) << flags::BASE_PREFIX_SHIFT; format |= (unwrap_or_zero(self.base_suffix) as u128) << flags::BASE_SUFFIX_SHIFT; format |= (self.mantissa_radix as u128) << flags::MANTISSA_RADIX_SHIFT; format |= (unwrap_or_zero(self.exponent_base) as u128) << flags::EXPONENT_BASE_SHIFT; format |= (unwrap_or_zero(self.exponent_radix) as u128) << flags::EXPONENT_RADIX_SHIFT; format } /// Re-create builder from format. #[inline(always)] pub const fn rebuild(format: u128) -> Self { NumberFormatBuilder { digit_separator: num::NonZeroU8::new(flags::digit_separator(format)), base_prefix: num::NonZeroU8::new(flags::base_prefix(format)), base_suffix: num::NonZeroU8::new(flags::base_suffix(format)), mantissa_radix: flags::mantissa_radix(format) as u8, exponent_base: num::NonZeroU8::new(flags::exponent_base(format) as u8), exponent_radix: num::NonZeroU8::new(flags::exponent_radix(format) as u8), required_integer_digits: has_flag!(format, REQUIRED_INTEGER_DIGITS), required_fraction_digits: has_flag!(format, REQUIRED_FRACTION_DIGITS), required_exponent_digits: has_flag!(format, REQUIRED_EXPONENT_DIGITS), required_mantissa_digits: has_flag!(format, REQUIRED_MANTISSA_DIGITS), no_positive_mantissa_sign: has_flag!(format, NO_POSITIVE_MANTISSA_SIGN), required_mantissa_sign: has_flag!(format, REQUIRED_MANTISSA_SIGN), no_exponent_notation: has_flag!(format, NO_EXPONENT_NOTATION), no_positive_exponent_sign: has_flag!(format, NO_POSITIVE_EXPONENT_SIGN), required_exponent_sign: has_flag!(format, REQUIRED_EXPONENT_SIGN), no_exponent_without_fraction: has_flag!(format, NO_EXPONENT_WITHOUT_FRACTION), no_special: has_flag!(format, NO_SPECIAL), case_sensitive_special: has_flag!(format, CASE_SENSITIVE_SPECIAL), no_integer_leading_zeros: has_flag!(format, NO_INTEGER_LEADING_ZEROS), no_float_leading_zeros: has_flag!(format, NO_FLOAT_LEADING_ZEROS), required_exponent_notation: has_flag!(format, REQUIRED_EXPONENT_NOTATION), case_sensitive_exponent: has_flag!(format, CASE_SENSITIVE_EXPONENT), case_sensitive_base_prefix: has_flag!(format, CASE_SENSITIVE_BASE_PREFIX), case_sensitive_base_suffix: has_flag!(format, CASE_SENSITIVE_BASE_SUFFIX), integer_internal_digit_separator: has_flag!(format, INTEGER_INTERNAL_DIGIT_SEPARATOR), fraction_internal_digit_separator: has_flag!(format, FRACTION_INTERNAL_DIGIT_SEPARATOR), exponent_internal_digit_separator: has_flag!(format, EXPONENT_INTERNAL_DIGIT_SEPARATOR), integer_leading_digit_separator: has_flag!(format, INTEGER_LEADING_DIGIT_SEPARATOR), fraction_leading_digit_separator: has_flag!(format, FRACTION_LEADING_DIGIT_SEPARATOR), exponent_leading_digit_separator: has_flag!(format, EXPONENT_LEADING_DIGIT_SEPARATOR), integer_trailing_digit_separator: has_flag!(format, INTEGER_TRAILING_DIGIT_SEPARATOR), fraction_trailing_digit_separator: has_flag!(format, FRACTION_TRAILING_DIGIT_SEPARATOR), exponent_trailing_digit_separator: has_flag!(format, EXPONENT_TRAILING_DIGIT_SEPARATOR), integer_consecutive_digit_separator: has_flag!( format, INTEGER_CONSECUTIVE_DIGIT_SEPARATOR ), fraction_consecutive_digit_separator: has_flag!( format, FRACTION_CONSECUTIVE_DIGIT_SEPARATOR ), exponent_consecutive_digit_separator: has_flag!( format, EXPONENT_CONSECUTIVE_DIGIT_SEPARATOR ), special_digit_separator: has_flag!(format, SPECIAL_DIGIT_SEPARATOR), } } } impl Default for NumberFormatBuilder { #[inline(always)] fn default() -> Self { Self::new() } } lexical-util-1.0.6/src/format_flags.rs000064400000000000000000000725401046102023000160350ustar 00000000000000//! Bitmask flags and masks for numeric formats. //! //! These bitflags and masks comprise a compressed struct as a 128-bit //! integer, allowing its use in const generics. This comprises two parts: //! flags designating which numerical components are valid in a string, //! and masks to designate the control characters. //! //! The flags are designated in the lower 64 bits that modify //! the syntax of strings that are parsed by lexical. //! //! Bits 8-32 are reserved for float component flags, such //! as for example if base prefixes or postfixes are case-sensitive, //! if leading zeros in a float are valid, etc. //! //! Bits 32-64 are reserved for digit separator flags. These //! define which locations within a float or integer digit separators //! are valid, for example, before any digits in the integer component, //! whether consecutive digit separators are allowed, and more. //! //! ```text //! 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 //! +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ //! |I/R|F/R|E/R|M/R|+/M|R/M|e/e|+/E|R/E|e/F|S/S|S/C|N/I|N/F|R/e|e/C| //! +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ //! //! 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 //! +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ //! |e/P|e/S| | //! +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ //! //! 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 //! +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ //! |I/I|F/I|E/I|I/L|F/L|E/L|I/T|F/T|E/T|I/C|F/C|E/C|S/D| | //! +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ //! //! 48 49 50 51 52 53 54 55 56 57 58 59 60 62 62 63 64 //! +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ //! | | //! +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ //! //! Where: //! Non-Digit Separator Flags: //! I/R = Required integer digits. //! F/R = Required fraction digits. //! E/R = Required exponent digits. //! M/R = Required mantissa digits. //! +/M = No mantissa positive sign. //! R/M = Required positive sign. //! e/e = No exponent notation. //! +/E = No exponent positive sign. //! R/E = Required exponent sign. //! e/F = No exponent without fraction. //! S/S = No special (non-finite) values. //! S/C = Case-sensitive special (non-finite) values. //! N/I = No integer leading zeros. //! N/F = No float leading zeros. //! R/e = Required exponent characters. //! e/C = Case-sensitive exponent character. //! e/P = Case-sensitive base prefix. //! e/S = Case-sensitive base suffix. //! //! Digit Separator Flags: //! I/I = Integer internal digit separator. //! F/I = Fraction internal digit separator. //! E/I = Exponent internal digit separator. //! I/L = Integer leading digit separator. //! F/L = Fraction leading digit separator. //! E/L = Exponent leading digit separator. //! I/T = Integer trailing digit separator. //! F/T = Fraction trailing digit separator. //! E/T = Exponent trailing digit separator. //! I/C = Integer consecutive digit separator. //! F/C = Fraction consecutive digit separator. //! E/C = Exponent consecutive digit separator. //! S/D = Special (non-finite) digit separator. //! ``` //! //! The upper 64-bits are designated for control characters and radixes, //! such as the digit separator and base prefix characters, radixes, //! and more. //! //! ```text //! 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 //! +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ //! | Digit Separator | | //! +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ //! //! 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 //! +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ //! | | Base Prefix | | //! +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ //! //! 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 //! +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ //! | Base Suffix | | Mantissa Radix | | //! +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ //! //! 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 //! +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ //! | Exponent Base | | Exponent Radix | | //! +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ //! ``` //! //! //! Note: //! ----- //! //! In order to limit the format specification and avoid parsing //! non-numerical data, all number formats require some significant //! digits. Examples of always invalid numbers include: //! - ` ` //! - `.` //! - `e` //! - `e7` //! //! Test Cases: //! ----------- //! //! The following test-cases are used to define whether a literal or //! a string float is valid in a given language, and these tests are //! used to denote features in pre-defined formats. Only a few //! of these flags may modify the parsing behavior of integers. //! Integer parsing is assumed to be derived from float parsing, //! so if consecutive digit separators are valid in the integer //! component of a float, they are also valid in an integer. //! //! ```text //! 0: '.3' // Non-required integer. //! 1: '3.' // Non-required fraction. //! 2: '3e' // Non-required exponent. //! 3. '+3.0' // Mantissa positive sign. //! 4: '3.0e7' // Exponent notation. //! 5: '3.0e+7' // Exponent positive sign. //! 6. '3e7' // Exponent notation without fraction. //! 7: 'NaN' // Special (non-finite) values. //! 8: 'NAN' // Case-sensitive special (non-finite) values. //! 9: '3_4.01' // Integer internal digit separator. //! A: '3.0_1' // Fraction internal digit separator. //! B: '3.0e7_1' // Exponent internal digit separator. //! C: '_3.01' // Integer leading digit separator. //! D: '3._01' // Fraction leading digit separator. //! E: '3.0e_71' // Exponent leading digit separator. //! F: '3_.01' // Integer trailing digit separator. //! G: '3.01_' // Fraction trailing digit separator. //! H: '3.0e71_' // Exponent trailing digit separator. //! I: '3__4.01' // Integer consecutive digit separator. //! J: '3.0__1' // Fraction consecutive digit separator. //! K: '3.0e7__1' // Exponent consecutive digit separator. //! L: 'In_f' // Special (non-finite) digit separator. //! M: '010' // No integer leading zeros. //! N: '010.0' // No float leading zeros. //! O: '1.0' // No required exponent notation. //! P: '3.0E7' // Case-insensitive exponent character. //! P: '0x3.0' // Case-insensitive base prefix. //! P: '3.0H' // Case-insensitive base postfix. //! ``` //! //! Currently Supported Programming and Data Languages: //! --------------------------------------------------- //! //! 1. `Rust` //! 2. `Python` //! 3. `C++` (98, 03, 11, 14, 17) //! 4. `C` (89, 90, 99, 11, 18) //! 5. `Ruby` //! 6. `Swift` //! 7. `Go` //! 8. `Haskell` //! 9. `Javascript` //! 10. `Perl` //! 11. `PHP` //! 12. `Java` //! 13. `R` //! 14. `Kotlin` //! 15. `Julia` //! 16. `C#` (ISO-1, ISO-2, 3, 4, 5, 6, 7) //! 17. `Kawa` //! 18. `Gambit-C` //! 19. `Guile` //! 20. `Clojure` //! 21. `Erlang` //! 22. `Elm` //! 23. `Scala` //! 24. `Elixir` //! 25. `FORTRAN` //! 26. `D` //! 27. `Coffeescript` //! 28. `Cobol` //! 29. `F#` //! 30. `Visual Basic` //! 31. `OCaml` //! 32. `Objective-C` //! 33. `ReasonML` //! 34. `Octave` //! 35. `Matlab` //! 36. `Zig` //! 37. `SageMath` //! 38. `JSON` //! 39. `TOML` //! 40. `XML` //! 41. `SQLite` //! 42. `PostgreSQL` //! 43. `MySQL` //! 44. `MongoDB` #![cfg_attr(rustfmt, rustfmt::skip)] use static_assertions::const_assert; // ASSERTIONS // ---------- // Ensure all our bit flags are valid. macro_rules! check_subsequent_flags { ($x:ident, $y:ident) => { const_assert!($x << 1 == $y); }; } // Ensure all our bit masks don't overlap. macro_rules! check_subsequent_masks { ($x:ident, $y:ident) => { const_assert!($x & $y == 0); }; } // Check all our masks are in the range `[0, 255]` after shifting. macro_rules! check_mask_shifts { ($mask:ident, $shift:ident) => { const_assert!(0 < $mask >> $shift && 255 >= $mask >> $shift); }; } // Ensure all our bit masks don't overlap with existing flags. macro_rules! check_masks_and_flags { ($x:ident, $y:ident) => { const_assert!($x & $y == 0); }; } // NON-DIGIT SEPARATOR FLAGS & MASKS // --------------------------------- /// Digits are required before the decimal point. pub const REQUIRED_INTEGER_DIGITS: u128 = 1 << 0; /// Digits are required after the decimal point. /// This check will only occur if the decimal point is present. pub const REQUIRED_FRACTION_DIGITS: u128 = 1 << 1; /// Digits are required after the exponent character. /// This check will only occur if the exponent character is present. pub const REQUIRED_EXPONENT_DIGITS: u128 = 1 << 2; /// Mantissa digits are required (either before or after the decimal point). pub const REQUIRED_MANTISSA_DIGITS: u128 = 1 << 3; /// At least 1 digit in the number is required. pub const REQUIRED_DIGITS: u128 = REQUIRED_INTEGER_DIGITS | REQUIRED_FRACTION_DIGITS | REQUIRED_EXPONENT_DIGITS | REQUIRED_MANTISSA_DIGITS; /// Positive sign before the mantissa is not allowed. pub const NO_POSITIVE_MANTISSA_SIGN: u128 = 1 << 4; /// Positive sign before the mantissa is required. pub const REQUIRED_MANTISSA_SIGN: u128 = 1 << 5; /// Exponent notation is not allowed. pub const NO_EXPONENT_NOTATION: u128 = 1 << 6; /// Positive sign before the exponent is not allowed. pub const NO_POSITIVE_EXPONENT_SIGN: u128 = 1 << 7; /// Positive sign before the exponent is required. pub const REQUIRED_EXPONENT_SIGN: u128 = 1 << 8; /// Exponent without a fraction component is not allowed. /// /// This only checks if a decimal point precedes the exponent character. /// To require fraction digits or exponent digits with this check, /// please use the appropriate flags. pub const NO_EXPONENT_WITHOUT_FRACTION: u128 = 1 << 9; /// Special (non-finite) values are not allowed. pub const NO_SPECIAL: u128 = 1 << 10; /// Special (non-finite) values are case-sensitive. pub const CASE_SENSITIVE_SPECIAL: u128 = 1 << 11; /// Leading zeros before an integer value are not allowed. /// /// If the value is a literal, then this distinction applies /// when the value is treated like an integer literal, typically /// when there is no decimal point. If the value is parsed, /// then this distinction applies when the value as parsed /// as an integer. /// /// # Warning /// /// This also does not mean that the value parsed will be correct, /// for example, in languages like C, this will not auto- /// deduce that the radix is 8 with leading zeros, for an octal /// literal. pub const NO_INTEGER_LEADING_ZEROS: u128 = 1 << 12; /// Leading zeros before a float value are not allowed. /// /// If the value is a literal, then this distinction applies /// when the value is treated like an integer float, typically /// when there is a decimal point. If the value is parsed, /// then this distinction applies when the value as parsed /// as a float. /// /// # Warning /// /// This also does not mean that the value parsed will be correct, /// for example, in languages like C, this will not auto- /// deduce that the radix is 8 with leading zeros, for an octal /// literal. pub const NO_FLOAT_LEADING_ZEROS: u128 = 1 << 13; /// Exponent notation is required. /// /// Valid floats must contain an exponent notation character, and if /// applicable, a sign character and digits afterwards. pub const REQUIRED_EXPONENT_NOTATION: u128 = 1 << 14; /// Exponent characters are case-sensitive. pub const CASE_SENSITIVE_EXPONENT: u128 = 1 << 15; /// Base prefixes are case-sensitive. pub const CASE_SENSITIVE_BASE_PREFIX: u128 = 1 << 16; /// Base suffixes are case-sensitive. pub const CASE_SENSITIVE_BASE_SUFFIX: u128 = 1 << 17; // Non-digit separator flags. const_assert!(REQUIRED_INTEGER_DIGITS == 1); check_subsequent_flags!(REQUIRED_INTEGER_DIGITS, REQUIRED_FRACTION_DIGITS); check_subsequent_flags!(REQUIRED_FRACTION_DIGITS, REQUIRED_EXPONENT_DIGITS); check_subsequent_flags!(REQUIRED_EXPONENT_DIGITS, REQUIRED_MANTISSA_DIGITS); check_subsequent_flags!(REQUIRED_MANTISSA_DIGITS, NO_POSITIVE_MANTISSA_SIGN); check_subsequent_flags!(NO_POSITIVE_MANTISSA_SIGN, REQUIRED_MANTISSA_SIGN); check_subsequent_flags!(REQUIRED_MANTISSA_SIGN, NO_EXPONENT_NOTATION); check_subsequent_flags!(NO_EXPONENT_NOTATION, NO_POSITIVE_EXPONENT_SIGN); check_subsequent_flags!(NO_POSITIVE_EXPONENT_SIGN, REQUIRED_EXPONENT_SIGN); check_subsequent_flags!(REQUIRED_EXPONENT_SIGN, NO_EXPONENT_WITHOUT_FRACTION); check_subsequent_flags!(NO_EXPONENT_WITHOUT_FRACTION, NO_SPECIAL); check_subsequent_flags!(NO_SPECIAL, CASE_SENSITIVE_SPECIAL); check_subsequent_flags!(NO_SPECIAL, CASE_SENSITIVE_SPECIAL); check_subsequent_flags!(CASE_SENSITIVE_SPECIAL, NO_INTEGER_LEADING_ZEROS); check_subsequent_flags!(NO_INTEGER_LEADING_ZEROS, NO_FLOAT_LEADING_ZEROS); check_subsequent_flags!(NO_FLOAT_LEADING_ZEROS, REQUIRED_EXPONENT_NOTATION); check_subsequent_flags!(REQUIRED_EXPONENT_NOTATION, CASE_SENSITIVE_EXPONENT); check_subsequent_flags!(CASE_SENSITIVE_EXPONENT, CASE_SENSITIVE_BASE_PREFIX); check_subsequent_flags!(CASE_SENSITIVE_BASE_PREFIX, CASE_SENSITIVE_BASE_SUFFIX); // DIGIT SEPARATOR FLAGS & MASKS // ----------------------------- /// Digit separators are allowed between integer digits. pub const INTEGER_INTERNAL_DIGIT_SEPARATOR: u128 = 1 << 32; /// Digit separators are allowed between fraction digits. pub const FRACTION_INTERNAL_DIGIT_SEPARATOR: u128 = 1 << 33; /// Digit separators are allowed between exponent digits. pub const EXPONENT_INTERNAL_DIGIT_SEPARATOR: u128 = 1 << 34; /// A digit separator is allowed before any integer digits. pub const INTEGER_LEADING_DIGIT_SEPARATOR: u128 = 1 << 35; /// A digit separator is allowed before any fraction digits. pub const FRACTION_LEADING_DIGIT_SEPARATOR: u128 = 1 << 36; /// A digit separator is allowed before any exponent digits. pub const EXPONENT_LEADING_DIGIT_SEPARATOR: u128 = 1 << 37; /// A digit separator is allowed after any integer digits. pub const INTEGER_TRAILING_DIGIT_SEPARATOR: u128 = 1 << 38; /// A digit separator is allowed after any fraction digits. pub const FRACTION_TRAILING_DIGIT_SEPARATOR: u128 = 1 << 39; /// A digit separator is allowed after any exponent digits. pub const EXPONENT_TRAILING_DIGIT_SEPARATOR: u128 = 1 << 40; /// Multiple consecutive integer digit separators are allowed. pub const INTEGER_CONSECUTIVE_DIGIT_SEPARATOR: u128 = 1 << 41; /// Multiple consecutive fraction digit separators are allowed. pub const FRACTION_CONSECUTIVE_DIGIT_SEPARATOR: u128 = 1 << 42; /// Multiple consecutive exponent digit separators are allowed. pub const EXPONENT_CONSECUTIVE_DIGIT_SEPARATOR: u128 = 1 << 43; /// Digit separators are allowed between digits. pub const INTERNAL_DIGIT_SEPARATOR: u128 = INTEGER_INTERNAL_DIGIT_SEPARATOR | FRACTION_INTERNAL_DIGIT_SEPARATOR | EXPONENT_INTERNAL_DIGIT_SEPARATOR; /// A digit separator is allowed before any digits. pub const LEADING_DIGIT_SEPARATOR: u128 = INTEGER_LEADING_DIGIT_SEPARATOR | FRACTION_LEADING_DIGIT_SEPARATOR | EXPONENT_LEADING_DIGIT_SEPARATOR; /// A digit separator is allowed after any digits. pub const TRAILING_DIGIT_SEPARATOR: u128 = INTEGER_TRAILING_DIGIT_SEPARATOR | FRACTION_TRAILING_DIGIT_SEPARATOR | EXPONENT_TRAILING_DIGIT_SEPARATOR; /// Multiple consecutive digit separators are allowed. pub const CONSECUTIVE_DIGIT_SEPARATOR: u128 = INTEGER_CONSECUTIVE_DIGIT_SEPARATOR | FRACTION_CONSECUTIVE_DIGIT_SEPARATOR | EXPONENT_CONSECUTIVE_DIGIT_SEPARATOR; /// Any digit separators are allowed in special (non-finite) values. pub const SPECIAL_DIGIT_SEPARATOR: u128 = 1 << 44; // Digit separator flags. const_assert!(INTEGER_INTERNAL_DIGIT_SEPARATOR == 1 << 32); check_subsequent_flags!(INTEGER_INTERNAL_DIGIT_SEPARATOR, FRACTION_INTERNAL_DIGIT_SEPARATOR); check_subsequent_flags!(FRACTION_INTERNAL_DIGIT_SEPARATOR, EXPONENT_INTERNAL_DIGIT_SEPARATOR); check_subsequent_flags!(EXPONENT_INTERNAL_DIGIT_SEPARATOR, INTEGER_LEADING_DIGIT_SEPARATOR); check_subsequent_flags!(INTEGER_LEADING_DIGIT_SEPARATOR, FRACTION_LEADING_DIGIT_SEPARATOR); check_subsequent_flags!(FRACTION_LEADING_DIGIT_SEPARATOR, EXPONENT_LEADING_DIGIT_SEPARATOR); check_subsequent_flags!(EXPONENT_LEADING_DIGIT_SEPARATOR, INTEGER_TRAILING_DIGIT_SEPARATOR); check_subsequent_flags!(INTEGER_TRAILING_DIGIT_SEPARATOR, FRACTION_TRAILING_DIGIT_SEPARATOR); check_subsequent_flags!(FRACTION_TRAILING_DIGIT_SEPARATOR, EXPONENT_TRAILING_DIGIT_SEPARATOR); check_subsequent_flags!(EXPONENT_TRAILING_DIGIT_SEPARATOR, INTEGER_CONSECUTIVE_DIGIT_SEPARATOR); check_subsequent_flags!(INTEGER_CONSECUTIVE_DIGIT_SEPARATOR, FRACTION_CONSECUTIVE_DIGIT_SEPARATOR); check_subsequent_flags!(FRACTION_CONSECUTIVE_DIGIT_SEPARATOR, EXPONENT_CONSECUTIVE_DIGIT_SEPARATOR); check_subsequent_flags!(EXPONENT_CONSECUTIVE_DIGIT_SEPARATOR, SPECIAL_DIGIT_SEPARATOR); // CONTROL CHARACTER & RADIX MASKS // ------------------------------- /// Shift to convert to and from a digit separator as a `u8`. pub const DIGIT_SEPARATOR_SHIFT: i32 = 64; /// Mask to extract the digit separator character. pub const DIGIT_SEPARATOR: u128 = 0xFF << DIGIT_SEPARATOR_SHIFT; /// Shift to convert to and from a base prefix as a `u8`. pub const BASE_PREFIX_SHIFT: i32 = 88; /// Mask to extract the base prefix character. pub const BASE_PREFIX: u128 = 0xFF << BASE_PREFIX_SHIFT; /// Shift to convert to and from a base suffix as a `u8`. pub const BASE_SUFFIX_SHIFT: i32 = 96; /// Mask to extract the base suffix character. pub const BASE_SUFFIX: u128 = 0xFF << BASE_SUFFIX_SHIFT; /// Shift to convert to and from a mantissa radix as a `u32`. pub const MANTISSA_RADIX_SHIFT: i32 = 104; /// Mask to extract the mantissa radix: the radix for the significant digits. pub const MANTISSA_RADIX: u128 = 0xFF << MANTISSA_RADIX_SHIFT; /// Alias for `MANTISSA_RADIX_SHIFT`. pub const RADIX_SHIFT: i32 = MANTISSA_RADIX_SHIFT; /// Alias for `MANTISSA_RADIX`. pub const RADIX: u128 = MANTISSA_RADIX; /// Shift to convert to and from an exponent base as a `u32`. pub const EXPONENT_BASE_SHIFT: i32 = 112; /// Mask to extract the exponent base: the base the exponent is raised to. pub const EXPONENT_BASE: u128 = 0xFF << EXPONENT_BASE_SHIFT; /// Shift to convert to and from an exponent radix as a `u32`. pub const EXPONENT_RADIX_SHIFT: i32 = 120; /// Mask to extract the exponent radix: the radix for the exponent digits. pub const EXPONENT_RADIX: u128 = 0xFF << EXPONENT_RADIX_SHIFT; // Masks do not overlap. check_subsequent_masks!(DIGIT_SEPARATOR, BASE_PREFIX); check_subsequent_masks!(BASE_PREFIX, BASE_SUFFIX); check_subsequent_masks!(BASE_SUFFIX, MANTISSA_RADIX); check_subsequent_masks!(MANTISSA_RADIX, EXPONENT_BASE); check_subsequent_masks!(EXPONENT_BASE, EXPONENT_RADIX); // Check all our shifts shift the masks to a single byte. check_mask_shifts!(DIGIT_SEPARATOR, DIGIT_SEPARATOR_SHIFT); check_mask_shifts!(BASE_PREFIX, BASE_PREFIX_SHIFT); check_mask_shifts!(BASE_SUFFIX, BASE_SUFFIX_SHIFT); check_mask_shifts!(MANTISSA_RADIX, MANTISSA_RADIX_SHIFT); check_mask_shifts!(EXPONENT_BASE, EXPONENT_BASE_SHIFT); check_mask_shifts!(EXPONENT_RADIX, EXPONENT_RADIX_SHIFT); // Check masks don't overlap with neighboring flags. check_masks_and_flags!(DIGIT_SEPARATOR, SPECIAL_DIGIT_SEPARATOR); // HIDDEN MASKS // ------------ /// Mask to extract the flag bits. #[doc(hidden)] pub const FLAG_MASK: u128 = REQUIRED_DIGITS | NO_POSITIVE_MANTISSA_SIGN | REQUIRED_MANTISSA_SIGN | NO_EXPONENT_NOTATION | NO_POSITIVE_EXPONENT_SIGN | REQUIRED_EXPONENT_SIGN | NO_EXPONENT_WITHOUT_FRACTION | NO_SPECIAL | CASE_SENSITIVE_SPECIAL | NO_INTEGER_LEADING_ZEROS | NO_FLOAT_LEADING_ZEROS | REQUIRED_EXPONENT_NOTATION | CASE_SENSITIVE_EXPONENT | CASE_SENSITIVE_BASE_PREFIX | CASE_SENSITIVE_BASE_SUFFIX | INTERNAL_DIGIT_SEPARATOR | LEADING_DIGIT_SEPARATOR | TRAILING_DIGIT_SEPARATOR | CONSECUTIVE_DIGIT_SEPARATOR | SPECIAL_DIGIT_SEPARATOR; /// Mask to extract the flag bits controlling interface parsing. /// /// This mask controls all the flags handled by the interface, /// omitting those that are handled prior. This limits the /// number of match paths required to determine the correct /// interface. #[doc(hidden)] pub const INTERFACE_FLAG_MASK: u128 = REQUIRED_DIGITS | NO_EXPONENT_NOTATION | NO_POSITIVE_EXPONENT_SIGN | REQUIRED_EXPONENT_SIGN | NO_EXPONENT_WITHOUT_FRACTION | NO_FLOAT_LEADING_ZEROS | REQUIRED_EXPONENT_NOTATION | INTERNAL_DIGIT_SEPARATOR | LEADING_DIGIT_SEPARATOR | TRAILING_DIGIT_SEPARATOR | CONSECUTIVE_DIGIT_SEPARATOR; /// Mask to extract digit separator flags. #[doc(hidden)] pub const DIGIT_SEPARATOR_FLAG_MASK: u128 = INTERNAL_DIGIT_SEPARATOR | LEADING_DIGIT_SEPARATOR | TRAILING_DIGIT_SEPARATOR | CONSECUTIVE_DIGIT_SEPARATOR | SPECIAL_DIGIT_SEPARATOR; /// Mask to extract exponent flags. #[doc(hidden)] pub const EXPONENT_FLAG_MASK: u128 = REQUIRED_EXPONENT_DIGITS | NO_EXPONENT_NOTATION | NO_POSITIVE_EXPONENT_SIGN | REQUIRED_EXPONENT_SIGN | NO_EXPONENT_WITHOUT_FRACTION | REQUIRED_EXPONENT_NOTATION | EXPONENT_INTERNAL_DIGIT_SEPARATOR | EXPONENT_LEADING_DIGIT_SEPARATOR | EXPONENT_TRAILING_DIGIT_SEPARATOR | EXPONENT_CONSECUTIVE_DIGIT_SEPARATOR; /// Mask to extract integer digit separator flags. #[doc(hidden)] pub const INTEGER_DIGIT_SEPARATOR_FLAG_MASK: u128 = INTEGER_INTERNAL_DIGIT_SEPARATOR | INTEGER_LEADING_DIGIT_SEPARATOR | INTEGER_TRAILING_DIGIT_SEPARATOR | INTEGER_CONSECUTIVE_DIGIT_SEPARATOR; /// Mask to extract fraction digit separator flags. #[doc(hidden)] pub const FRACTION_DIGIT_SEPARATOR_FLAG_MASK: u128 = FRACTION_INTERNAL_DIGIT_SEPARATOR | FRACTION_LEADING_DIGIT_SEPARATOR | FRACTION_TRAILING_DIGIT_SEPARATOR | FRACTION_CONSECUTIVE_DIGIT_SEPARATOR; /// Mask to extract exponent digit separator flags. #[doc(hidden)] pub const EXPONENT_DIGIT_SEPARATOR_FLAG_MASK: u128 = EXPONENT_INTERNAL_DIGIT_SEPARATOR | EXPONENT_LEADING_DIGIT_SEPARATOR | EXPONENT_TRAILING_DIGIT_SEPARATOR | EXPONENT_CONSECUTIVE_DIGIT_SEPARATOR; // EXTRACTORS // ---------- /// Extract the digit separator from the format packed struct. #[inline(always)] pub const fn digit_separator(format: u128) -> u8 { ((format & DIGIT_SEPARATOR) >> DIGIT_SEPARATOR_SHIFT) as u8 } /// Extract the base prefix character from the format packed struct. #[inline(always)] pub const fn base_prefix(format: u128) -> u8 { ((format & BASE_PREFIX) >> BASE_PREFIX_SHIFT) as u8 } /// Extract the base suffix character from the format packed struct. #[inline(always)] pub const fn base_suffix(format: u128) -> u8 { ((format & BASE_SUFFIX) >> BASE_SUFFIX_SHIFT) as u8 } /// Extract the mantissa radix from the format packed struct. #[inline(always)] pub const fn mantissa_radix(format: u128) -> u32 { ((format & MANTISSA_RADIX) >> MANTISSA_RADIX_SHIFT) as u32 } /// Extract the exponent base from the format packed struct. /// If not provided, defaults to `mantissa_radix`. #[inline(always)] pub const fn exponent_base(format: u128) -> u32 { let radix = ((format & EXPONENT_BASE) >> EXPONENT_BASE_SHIFT) as u32; if radix == 0 { mantissa_radix(format) } else { radix } } /// Extract the exponent radix from the format packed struct. /// If not provided, defaults to `mantissa_radix`. #[inline(always)] pub const fn exponent_radix(format: u128) -> u32 { let radix = ((format & EXPONENT_RADIX) >> EXPONENT_RADIX_SHIFT) as u32; if radix == 0 { mantissa_radix(format) } else { radix } } /// Extract a generic radix from the format and bitflags. #[inline(always)] pub const fn radix_from_flags(format: u128, mask: u128, shift: i32) -> u32 { let radix = ((format & mask) >> shift) as u32; if radix == 0 { mantissa_radix(format) } else { radix } } // VALIDATORS // ---------- // NOTE: All of these are only used when building formats so it doesn't matter if // they have performance issues, since these will be built at compile time. /// Determine if the provided exponent flags are valid. #[inline(always)] pub const fn is_valid_exponent_flags(format: u128) -> bool { // Both cannot be set. format & NO_EXPONENT_NOTATION == 0 || format & REQUIRED_EXPONENT_NOTATION == 0 } /// Determine if an optional control character is valid. #[inline(always)] const fn is_valid_optional_control_radix(radix: u32, value: u8) -> bool { // Validate the character isn't a digit or sign character, and is valid ASCII. use crate::ascii::is_valid_ascii; use crate::digit::char_is_digit_const; !char_is_digit_const(value, radix) && value != b'+' && value != b'-' && (is_valid_ascii(value) || value == 0) } /// Determine if an optional control character is valid. #[inline(always)] const fn is_valid_optional_control(format: u128, value: u8) -> bool { // Need to get the larger of the two radix values, since these // will be the characters that define the valid digits. // const fn doesn't support max as of 1.55 nightly. let mradix = mantissa_radix(format); let eradix = exponent_radix(format); let radix = if mradix > eradix { mradix } else { eradix }; is_valid_optional_control_radix(radix, value) } /// Determine if an control character is valid. #[inline(always)] const fn is_valid_control(format: u128, value: u8) -> bool { value != 0 && is_valid_optional_control(format, value) } /// Determine if the digit separator is valid. /// Digit separators must not be valid digits or sign characters. #[inline(always)] pub const fn is_valid_digit_separator(format: u128) -> bool { let value = digit_separator(format); if cfg!(feature = "format") { is_valid_optional_control(format, value) } else { value == 0 } } /// Determine if the base prefix character is valid. #[inline(always)] pub const fn is_valid_base_prefix(format: u128) -> bool { let value = base_prefix(format); if cfg!(feature = "format") { is_valid_optional_control(format, value) } else { value == 0 } } /// Determine if the base suffix character is valid. #[inline(always)] pub const fn is_valid_base_suffix(format: u128) -> bool { let value = base_suffix(format); if cfg!(feature = "format") { is_valid_optional_control(format, value) } else { value == 0 } } /// Determine if all of the "punctuation" characters are valid. #[inline(always)] #[allow(clippy::if_same_then_else)] // reason="all are different logic conditions" pub const fn is_valid_punctuation(format: u128) -> bool { // All the checks against optional characters with mandatory are fine: // if they're not 0, then they can't overlap, and mandatory can't be 0. if cfg!(not(feature = "format")) && digit_separator(format) != 0 { // Digit separator set when not allowed. false } else { let separator = digit_separator(format); let prefix = base_prefix(format); let suffix = base_suffix(format); // Check all are optional, or enough are not present. match (separator, prefix, suffix) { (0, 0, 0) => true, (_, 0, 0) => true, (0, _, 0) => true, (0, 0, _) => true, // Can't have more than 1 0, check they're all different. (x, y, z) => x != y && x != z && y != z, } } } /// Determine if all of the "punctuation" characters for the options API are valid. #[inline(always)] #[allow(clippy::if_same_then_else)] // reason="all are different logic conditions" #[allow(clippy::needless_bool)] // reason="not needless depending on the format condition" pub const fn is_valid_options_punctuation(format: u128, exponent: u8, decimal_point: u8) -> bool { // All the checks against optional characters with mandatory are fine: // if they're not 0, then they can't overlap, and mandatory can't be 0. if !is_valid_control(format, decimal_point) || !is_valid_control(format, exponent) { // Must be in the valid range. false } else if decimal_point == exponent { // Can't have overlapping characters. false } else if cfg!(feature = "format") && digit_separator(format) == decimal_point { false } else if cfg!(feature = "format") && digit_separator(format) == exponent { false } else if cfg!(feature = "format") && base_prefix(format) == decimal_point { false } else if cfg!(feature = "format") && base_prefix(format) == exponent { false } else if cfg!(feature = "format") && base_suffix(format) == decimal_point { false } else if cfg!(feature = "format") && base_suffix(format) == exponent { false } else { true } } /// Determine if the radix is valid. pub const fn is_valid_radix(radix: u32) -> bool { if cfg!(feature = "radix") { radix >= 2 && radix <= 36 } else if cfg!(feature = "power-of-two") { matches!(radix, 2 | 4 | 8 | 10 | 16 | 32) } else { radix == 10 } } lexical-util-1.0.6/src/iterator.rs000064400000000000000000000344361046102023000152240ustar 00000000000000//! Specialized iterator traits. //! //! The traits are for iterables containing bytes, and provide optimizations //! which then can be used for contiguous or non-contiguous iterables, //! including containers or iterators of any kind. #![cfg(feature = "parse")] use core::mem; // Re-export our digit iterators. #[cfg(not(feature = "format"))] pub use crate::noskip::{AsBytes, Bytes}; #[cfg(feature = "format")] pub use crate::skip::{AsBytes, Bytes}; /// A trait for working with iterables of bytes. /// /// These iterators can either be contiguous or not contiguous and provide /// methods for reading data and accessing underlying data. The readers /// can either be contiguous or non-contiguous, although performance and /// some API methods may not be available for both. /// /// # Safety /// /// Safe if [`set_cursor`] is set to an index <= [`buffer_length`], so no /// out-of-bounds reads can occur. Also, [`get_buffer`] must return a slice of /// initialized bytes. The caller must also ensure that any calls that increment /// the cursor, such as [`step_by_unchecked`], [`step_unchecked`], and /// [`peek_many_unchecked`] never exceed [`buffer_length`] as well. /// /// [`set_cursor`]: `Iter::set_cursor` /// [`buffer_length`]: `Iter::buffer_length` /// [`get_buffer`]: `Iter::get_buffer` /// [`step_by_unchecked`]: `Iter::step_by_unchecked` /// [`step_unchecked`]: `Iter::step_unchecked` /// [`peek_many_unchecked`]: `Iter::peek_many_unchecked` #[cfg(feature = "parse")] pub unsafe trait Iter<'a> { /// Determine if the buffer is contiguous in memory. const IS_CONTIGUOUS: bool; // CURSORS // ------- /// Get a ptr to the current start of the buffer. #[inline(always)] fn as_ptr(&self) -> *const u8 { self.as_slice().as_ptr() } /// Get a slice to the current start of the buffer. #[inline(always)] fn as_slice(&self) -> &'a [u8] { debug_assert!(self.cursor() <= self.buffer_length()); // SAFETY: safe since index must be in range. unsafe { self.get_buffer().get_unchecked(self.cursor()..) } } /// Get a slice to the full underlying contiguous buffer, fn get_buffer(&self) -> &'a [u8]; /// Get the total number of elements in the underlying buffer. #[inline(always)] fn buffer_length(&self) -> usize { self.get_buffer().len() } /// Get if no bytes are available in the buffer. /// /// This operators on the underlying buffer: that is, /// it returns if [`as_slice`] would return an empty slice. /// /// [as_slice]: Iter::as_slice #[inline(always)] fn is_buffer_empty(&self) -> bool { self.cursor() >= self.get_buffer().len() } /// Get the current index of the iterator in the slice. fn cursor(&self) -> usize; /// Set the current index of the iterator in the slice. /// /// This is **NOT** the current position of the iterator, /// since iterators may skip digits: this is the cursor /// in the underlying buffer. For example, if `slc[2]` is /// skipped, `set_cursor(3)` would be the 3rd element in /// the iterator, not the 4th. /// /// # Safety /// /// Safe if `index <= self.buffer_length()`. Although this /// won't affect safety, the caller also should be careful it /// does not set the cursor within skipped characters /// since this could affect correctness: an iterator that /// only accepts non-consecutive digit separators would /// pass if the cursor was set between the two. unsafe fn set_cursor(&mut self, index: usize); /// Get the current number of digits returned by the iterator. /// /// For contiguous iterators, this can include the sign character, decimal /// point, and the exponent sign (that is, it is always the cursor). For /// non-contiguous iterators, this must always be the only the number of /// digits returned. /// /// This is never used for indexing but will be used for API detection. fn current_count(&self) -> usize; // PROPERTIES /// Determine if the buffer is contiguous. #[inline(always)] fn is_contiguous(&self) -> bool { Self::IS_CONTIGUOUS } /// Get the next value available without consuming it. /// /// This does **NOT** skip digits, and directly fetches the item /// from the underlying buffer. #[inline(always)] fn first(&self) -> Option<&'a u8> { self.get_buffer().get(self.cursor()) } /// Check if the next element is a given value. #[inline(always)] fn first_is_cased(&self, value: u8) -> bool { Some(&value) == self.first() } /// Check if the next element is a given value without case sensitivity. #[inline(always)] fn first_is_uncased(&self, value: u8) -> bool { if let Some(&c) = self.first() { c.eq_ignore_ascii_case(&value) } else { false } } /// Check if the next item in buffer is a given value with optional case /// sensitivity. #[inline(always)] fn first_is(&self, value: u8, is_cased: bool) -> bool { if is_cased { self.first_is_cased(value) } else { self.first_is_uncased(value) } } // STEP BY // ------- /// Advance the internal slice by `N` elements. /// /// This does not advance the iterator by `N` elements for /// non-contiguous iterators: this just advances the internal, /// underlying buffer. This is useful for multi-digit optimizations /// for contiguous iterators. /// /// This does not increment the count of items: returns: this only /// increments the index, not the total digits returned. You must use /// this carefully: if stepping over a digit, you must then call /// [`increment_count`] afterwards or else the internal count will /// be incorrect. /// /// [`increment_count`]: DigitsIter::increment_count /// /// # Panics /// /// This will panic if the buffer advances for non-contiguous /// iterators if the current byte is a digit separator, or if the /// count is more than 1. /// /// # Safety /// /// As long as the iterator is at least `N` elements, this /// is safe. unsafe fn step_by_unchecked(&mut self, count: usize); /// Advance the internal slice by 1 element. /// /// /// This does not increment the count of items: returns: this only /// increments the index, not the total digits returned. You must /// use this carefully: if stepping over a digit, you must then call /// [`increment_count`] afterwards or else the internal count will /// be incorrect. /// /// [`increment_count`]: DigitsIter::increment_count /// /// # Panics /// /// This will panic if the buffer advances for non-contiguous /// iterators if the current byte is a digit separator. /// /// # Safety /// /// Safe as long as the iterator is not empty. #[inline(always)] unsafe fn step_unchecked(&mut self) { debug_assert!(!self.as_slice().is_empty()); // SAFETY: safe if `self.index < self.buffer_length()`. unsafe { self.step_by_unchecked(1) }; } // READ // ---- /// Read a value of a difference type from the iterator. /// /// This does **not** advance the internal state of the iterator. /// This can only be implemented for contiguous iterators: non- /// contiguous iterators **MUST** panic. /// /// # Panics /// /// If the iterator is a non-contiguous iterator. /// /// # Safety /// /// Safe as long as the number of the buffer is contains as least as /// many bytes as the size of V. This must be unimplemented for /// non-contiguous iterators. #[inline(always)] unsafe fn peek_many_unchecked(&self) -> V { unimplemented!(); } /// Try to read a the next four bytes as a u32. /// /// This does not advance the internal state of the iterator. #[inline(always)] fn peek_u32(&self) -> Option { if Self::IS_CONTIGUOUS && self.as_slice().len() >= mem::size_of::() { // SAFETY: safe since we've guaranteed the buffer is greater than // the number of elements read. u32 is valid for all bit patterns unsafe { Some(self.peek_many_unchecked()) } } else { None } } /// Try to read the next eight bytes as a u64. /// /// This does not advance the internal state of the iterator. #[inline(always)] fn peek_u64(&self) -> Option { if Self::IS_CONTIGUOUS && self.as_slice().len() >= mem::size_of::() { // SAFETY: safe since we've guaranteed the buffer is greater than // the number of elements read. u64 is valid for all bit patterns unsafe { Some(self.peek_many_unchecked()) } } else { None } } } /// Iterator over a contiguous block of bytes. /// /// This allows us to convert to-and-from-slices, raw pointers, and /// peek/query the data from either end cheaply. /// /// A default implementation is provided for slice iterators. /// This trait **should never** return `null` from `as_ptr`, or be /// implemented for non-contiguous data. pub trait DigitsIter<'a>: Iterator + Iter<'a> { /// Get if the iterator cannot return any more elements. /// /// This may advance the internal iterator state, but not /// modify the next returned value. /// /// If this is an iterator, this is based on the number of items /// left to be returned. We do not necessarly know the length of /// the buffer. If this is a non-contiguous iterator, this **MUST** /// advance the state until it knows a value can be returned. /// /// Any incorrect implementations of this affect all safety invariants /// for the rest of the trait. For contiguous iterators, this can be /// as simple as checking if `self.cursor >= self.slc.len()`, but for /// non-contiguous iterators you **MUST** advance to the next element /// to be returned, then check to see if a value exists. The safest /// implementation is always to check if `self.peek().is_none()` and /// ensure [`peek`] is always safe. /// /// If you would like to see if the cursor is at the end of the buffer, /// see [`is_buffer_empty`] instead. /// /// [is_buffer_empty]: Iter::is_buffer_empty /// [peek]: DigitsIter::peek #[inline(always)] #[allow(clippy::wrong_self_convention)] // reason="required for peeking next item" fn is_consumed(&mut self) -> bool { self.peek().is_none() } /// Increment the number of digits that have been returned by the iterator. /// /// For contiguous iterators, this is a no-op. For non-contiguous iterators, /// this increments the count by 1. fn increment_count(&mut self); /// Peek the next value of the iterator, without consuming it. /// /// Note that this can modify the internal state, by skipping digits /// for iterators that find the first non-zero value, etc. We optimize /// this for the case where we have contiguous iterators, since /// non-contiguous iterators already have a major performance penalty. fn peek(&mut self) -> Option; /// Peek the next value of the iterator, and step only if it exists. #[inline(always)] fn try_read(&mut self) -> Option { if let Some(value) = self.peek() { // SAFETY: the slice cannot be empty because we peeked a value. unsafe { self.step_unchecked() }; Some(value) } else { None } } /// Check if the next element is a given value. #[inline(always)] fn peek_is_cased(&mut self, value: u8) -> bool { Some(&value) == self.peek() } /// Check if the next element is a given value without case sensitivity. #[inline(always)] fn peek_is_uncased(&mut self, value: u8) -> bool { if let Some(&c) = self.peek() { c.eq_ignore_ascii_case(&value) } else { false } } /// Check if the next element is a given value with optional case /// sensitivity. #[inline(always)] fn peek_is(&mut self, value: u8, is_cased: bool) -> bool { if is_cased { self.peek_is_cased(value) } else { self.peek_is_uncased(value) } } /// Peek the next value and consume it if the read value matches the /// expected one. #[inline(always)] fn read_if bool>(&mut self, pred: Pred) -> Option { // NOTE: This was implemented to remove usage of unsafe throughout to code // base, however, performance was really not up to scratch. I'm not sure // the cause of this. if let Some(&peeked) = self.peek() { if pred(peeked) { // SAFETY: the slice cannot be empty because we peeked a value. unsafe { self.step_unchecked() }; Some(peeked) } else { None } } else { None } } /// Read a value if the value matches the provided one. #[inline(always)] fn read_if_value_cased(&mut self, value: u8) -> Option { if self.peek() == Some(&value) { // SAFETY: the slice cannot be empty because we peeked a value. unsafe { self.step_unchecked() }; Some(value) } else { None } } /// Read a value if the value matches the provided one without case /// sensitivity. #[inline(always)] fn read_if_value_uncased(&mut self, value: u8) -> Option { self.read_if(|x| x.eq_ignore_ascii_case(&value)) } /// Read a value if the value matches the provided one. #[inline(always)] fn read_if_value(&mut self, value: u8, is_cased: bool) -> Option { if is_cased { self.read_if_value_cased(value) } else { self.read_if_value_uncased(value) } } /// Skip zeros from the start of the iterator #[inline(always)] fn skip_zeros(&mut self) -> usize { let start = self.current_count(); while self.read_if_value_cased(b'0').is_some() { self.increment_count(); } self.current_count() - start } /// Determine if the character is a digit. fn is_digit(&self, value: u8) -> bool; } lexical-util-1.0.6/src/lib.rs000064400000000000000000000151371046102023000141360ustar 00000000000000//! Shared utilities for lexical conversion routines. //! //! These are not meant to be used publicly for any numeric //! conversion routines, but provide optimized math routines, //! format packed struct definitions, and custom iterators //! for all workspaces. //! //! # Features //! //! * `std` - Use the standard library. //! * `power-of-two` - Add support for parsing power-of-two integer strings. //! * `radix` - Add support for strings of any radix. //! * `write-integers` - Add support for writing integers. //! * `write-floats` - Add support for writing floats. //! * `parse-integers` - Add support for parsing integers. //! * `parse-floats` - Add support for parsing floats. //! * `compact` - Reduce code size at the cost of performance. //! //! # Note //! //! None of this is considered a public API: any of the implementation //! details may change release-to-release without major or minor version //! changes. Use internal implementation details at your own risk. //! //! lexical-util mainly exists as an implementation detail for //! lexical-core, although its API is stable. If you would like to use //! a high-level API that writes to and parses from `String` and `&str`, //! respectively, please look at [lexical](https://crates.io/crates/lexical) //! instead. If you would like an API that supports multiple numeric //! conversions, please look at [lexical-core](https://crates.io/crates/lexical-core) //! instead. //! //! # Version Support //! //! The minimum, standard, required version is 1.63.0, for const generic //! support. Older versions of lexical support older Rust versions. //! //! # Safety Guarantees //! //! The only major sources of unsafe code are wrapped in the `iterator.rs`, //! `skip.rs`, and `noskip.rs`. These are fully encapsulated into standalone //! traits to clearly define safety invariants and localize any unsafety to //! 1 or 2 lines of code. //! //! The core, unsafe trait is `DigitsIter` and `Iter`, both which expect //! to be backed by a contiguous block of memory (a slice) but may skip //! bytes internally. To guarantee safety, for non-skip iterators you //! must implement [DigitsIter::is_consumed][is_consumed] correctly. //! //! This must correctly determine if there are any elements left in the //! iterator. If the buffer is contiguous, this can just be `index == //! self.len()`, but for a non-contiguous iterator it must skip any digits to //! advance to the element next to be returned or the iterator itself will be //! unsafe. **ALL** other safety invariants depend on this being implemented //! correctly. //! //! To see if the cursor is at the end of the buffer, use //! [is_buffer_empty][is_buffer_empty]. //! //! Any iterators must be peekable: you must be able to read and return the next //! value without advancing the iterator past that point. For iterators that //! skip bytes, this means advancing to the next element to be returned and //! returning that value. //! //! For examples of how to safely implement skip iterators, you can do something //! like: //! //! ```rust,ignore //! impl<_> DigitsIter<_> for MyIter { //! fn peek(&mut self) -> Option { //! loop { //! let value = self.bytes.get(self.index)?; //! if value != &b'.' { //! return value; //! } //! self.index += 1; //! } //! } //! } //! ``` //! //! Then, [next](core::iter::Iterator::next) will be implemented in terms //! of [peek], incrementing the position in the cursor just after the value. //! The next iteration of peek will step to the correct byte to return. //! //! ```rust,ignore //! impl<_> Iterator for MyIter { //! type Item = &'a u8; //! //! fn next(&mut self) -> Option { //! let value = self.peek()?; //! self.index += 1; //! Some(value) //! } //! } //! ``` //! //! [is_buffer_empty]: //! [is_consumed]: //! [peek]: // FIXME: Implement clippy/allow reasons once we drop support for 1.80.0 and below // Clippy reasons were stabilized in 1.81.0. // We want to have the same safety guarantees as Rust core, // so we allow unused unsafe to clearly document safety guarantees. #![allow(unused_unsafe)] #![cfg_attr(feature = "lint", warn(unsafe_op_in_unsafe_fn))] #![cfg_attr(not(feature = "std"), no_std)] #![deny( clippy::doc_markdown, clippy::unnecessary_safety_comment, clippy::semicolon_if_nothing_returned, clippy::unwrap_used, clippy::as_underscore, clippy::doc_markdown )] #![allow( // used when concepts are logically separate clippy::match_same_arms, // loss of precision is intentional clippy::integer_division, // mathematical names use 1-character identifiers clippy::min_ident_chars, // these are not cryptographically secure contexts clippy::integer_division_remainder_used, // this can be intentional clippy::module_name_repetitions, // this is intentional: already passing a pointer and need performance clippy::needless_pass_by_value, // we use this for inline formatting for unsafe blocks clippy::semicolon_inside_block, )] // Ensure our features are properly enabled. This means no parse without // parse support, etc. #[cfg(all(feature = "parse", not(any(feature = "parse-integers", feature = "parse-floats"))))] compile_error!( "Do not use the `parse` feature directly. Use `parse-integers` and/or `parse-floats` instead." ); #[cfg(all(feature = "write", not(any(feature = "write-integers", feature = "write-floats"))))] compile_error!( "Do not use the `write` feature directly. Use `write-integers` and/or `write-floats` instead." ); #[cfg(all(feature = "integers", not(any(feature = "write-integers", feature = "parse-integers"))))] compile_error!("Do not use the `integers` feature directly. Use `write-integers` and/or `parse-integers` instead."); #[cfg(all(feature = "floats", not(any(feature = "write-floats", feature = "parse-floats"))))] compile_error!( "Do not use the `floats` feature directly. Use `write-floats` and/or `parse-floats` instead." ); pub mod algorithm; pub mod ascii; pub mod assert; pub mod bf16; pub mod constants; pub mod digit; pub mod div128; pub mod error; pub mod extended_float; pub mod f16; pub mod format; pub mod iterator; pub mod mul; pub mod num; pub mod options; pub mod result; pub mod step; mod api; mod feature_format; mod format_builder; mod format_flags; mod noskip; mod not_feature_format; mod numtypes; mod skip; lexical-util-1.0.6/src/mul.rs000064400000000000000000000031001046102023000141500ustar 00000000000000//! Fast multiplication routines. use crate::num::{as_cast, UnsignedInteger}; /// Multiply two unsigned, integral values, and return the hi and lo product. /// /// The `full` type is the full type size, while the `half` type is the type /// with exactly half the bits. #[inline(always)] pub fn mul(x: Full, y: Full) -> (Full, Full) where Full: UnsignedInteger, Half: UnsignedInteger, { // Extract high-and-low masks. let x1 = x >> Half::BITS as i32; let x0 = x & as_cast(Half::MAX); let y1 = y >> Half::BITS as i32; let y0 = y & as_cast(Half::MAX); let w0 = x0 * y0; let tmp = (x1 * y0) + (w0 >> Half::BITS as i32); let w1 = tmp & as_cast(Half::MAX); let w2 = tmp >> Half::BITS as i32; let w1 = w1 + x0 * y1; let hi = (x1 * y1) + w2 + (w1 >> Half::BITS as i32); let lo = x.wrapping_mul(y); (hi, lo) } /// Multiply two unsigned, integral values, and return the hi product. /// /// The `full` type is the full type size, while the `half` type is the type /// with exactly half the bits. #[inline(always)] pub fn mulhi(x: Full, y: Full) -> Full where Full: UnsignedInteger, Half: UnsignedInteger, { // Extract high-and-low masks. let x1 = x >> Half::BITS as i32; let x0 = x & as_cast(Half::MAX); let y1 = y >> Half::BITS as i32; let y0 = y & as_cast(Half::MAX); let w0 = x0 * y0; let m = (x0 * y1) + (w0 >> Half::BITS as i32); let w1 = m & as_cast(Half::MAX); let w2 = m >> Half::BITS as i32; let w3 = (x1 * y0 + w1) >> Half::BITS as i32; x1 * y1 + w2 + w3 } lexical-util-1.0.6/src/noskip.rs000064400000000000000000000202411046102023000146630ustar 00000000000000//! An iterator over a slice. //! //! This iterator has both the length of the original slice, as //! well as the current position of the iterator in the buffer. #![cfg(all(feature = "parse", not(feature = "format")))] use core::{mem, ptr}; use crate::digit::char_is_digit_const; use crate::format::NumberFormat; use crate::iterator::{DigitsIter, Iter}; // AS DIGITS // --------- /// Trait to simplify creation of a `Bytes` object. pub trait AsBytes<'a> { /// Create `Bytes` from object. fn bytes(&'a self) -> Bytes<'a, __>; } impl<'a> AsBytes<'a> for [u8] { #[inline(always)] fn bytes(&'a self) -> Bytes<'a, __> { Bytes::new(self) } } // DIGITS // ------ /// Slice iterator that stores the original length of the slice. #[derive(Clone)] pub struct Bytes<'a, const __: u128> { /// The raw slice for the iterator. slc: &'a [u8], /// Current index of the iterator in the slice. index: usize, } impl<'a, const __: u128> Bytes<'a, __> { /// Create new byte object. #[inline(always)] pub const fn new(slc: &'a [u8]) -> Self { Self { slc, index: 0, } } /// Initialize the slice from raw parts. /// /// # Safety /// /// This is safe if and only if the index is <= `slc.len()`. /// For this reason, since it's easy to get wrong, we only /// expose it to `DigitsIterator` and nothing else. #[inline(always)] #[allow(clippy::assertions_on_constants)] // reason="ensuring safety invariants are valid" const unsafe fn from_parts(slc: &'a [u8], index: usize) -> Self { debug_assert!(index <= slc.len()); debug_assert!(Self::IS_CONTIGUOUS); Self { slc, index, } } /// Get iterator over integer digits. #[inline(always)] pub fn integer_iter<'b>(&'b mut self) -> DigitsIterator<'a, 'b, __> { DigitsIterator { byte: self, } } /// Get iterator over fraction digits. #[inline(always)] pub fn fraction_iter<'b>(&'b mut self) -> DigitsIterator<'a, 'b, __> { DigitsIterator { byte: self, } } /// Get iterator over exponent digits. #[inline(always)] pub fn exponent_iter<'b>(&'b mut self) -> DigitsIterator<'a, 'b, __> { DigitsIterator { byte: self, } } /// Get iterator over special floating point values. #[inline(always)] pub fn special_iter<'b>(&'b mut self) -> DigitsIterator<'a, 'b, __> { DigitsIterator { byte: self, } } } unsafe impl<'a, const __: u128> Iter<'a> for Bytes<'a, __> { const IS_CONTIGUOUS: bool = true; #[inline(always)] fn get_buffer(&self) -> &'a [u8] { self.slc } /// Get the current index of the iterator in the slice. #[inline(always)] fn cursor(&self) -> usize { self.index } /// Set the current index of the iterator in the slice. /// /// # Safety /// /// Safe if `index <= self.buffer_length()`. #[inline(always)] unsafe fn set_cursor(&mut self, index: usize) { debug_assert!(index <= self.buffer_length()); self.index = index; } /// Get the current number of digits returned by the iterator. /// /// For contiguous iterators, this can include the sign character, decimal /// point, and the exponent sign (that is, it is always the cursor). For /// non-contiguous iterators, this must always be the only the number of /// digits returned. #[inline(always)] fn current_count(&self) -> usize { self.index } #[inline(always)] #[allow(clippy::assertions_on_constants)] // reason="ensuring safety invariants are valid" unsafe fn step_by_unchecked(&mut self, count: usize) { assert!(Self::IS_CONTIGUOUS); debug_assert!(self.as_slice().len() >= count); self.index += count; } #[inline(always)] #[allow(clippy::assertions_on_constants)] // reason="ensuring safety invariants are valid" unsafe fn peek_many_unchecked(&self) -> V { debug_assert!(Self::IS_CONTIGUOUS); debug_assert!(self.as_slice().len() >= mem::size_of::()); // SAFETY: safe as long as the slice has at least count elements. unsafe { ptr::read_unaligned::(self.as_ptr() as *const _) } } } // DIGITS ITERATOR // --------------- /// Slice iterator that stores the original length of the slice. pub struct DigitsIterator<'a: 'b, 'b, const __: u128> { /// The internal byte object for the no-skip iterator. byte: &'b mut Bytes<'a, __>, } impl<'a: 'b, 'b, const __: u128> DigitsIterator<'a, 'b, __> { /// Create a new digits iterator from the bytes underlying item. #[inline(always)] pub fn new(byte: &'b mut Bytes<'a, __>) -> Self { Self { byte, } } /// Take the first N digits from the iterator. /// /// This only takes the digits if we have a contiguous iterator. /// It takes the digits, validating the bounds, and then advanced /// the iterators state. #[cfg_attr(not(feature = "compact"), inline(always))] #[allow(clippy::assertions_on_constants)] // reason="ensuring safety invariants are valid" pub fn take_n(&mut self, n: usize) -> Option> { debug_assert!(Self::IS_CONTIGUOUS); let end = self.byte.slc.len().min(n + self.cursor()); // NOTE: The compiler should be able to optimize this out. let slc: &[u8] = &self.byte.slc[..end]; // SAFETY: Safe since we just ensured the underlying slice has that count // elements, so both the underlying slice for this and this **MUST** // have at least count elements. We do static checking on the bounds for this. unsafe { let byte: Bytes<'_, __> = Bytes::from_parts(slc, self.cursor()); unsafe { self.set_cursor(end) }; Some(byte) } } } unsafe impl<'a: 'b, 'b, const __: u128> Iter<'a> for DigitsIterator<'a, 'b, __> { const IS_CONTIGUOUS: bool = Bytes::<'a, __>::IS_CONTIGUOUS; #[inline(always)] fn get_buffer(&self) -> &'a [u8] { self.byte.get_buffer() } #[inline(always)] fn cursor(&self) -> usize { self.byte.cursor() } #[inline(always)] unsafe fn set_cursor(&mut self, index: usize) { debug_assert!(index <= self.buffer_length()); // SAFETY: safe if `index <= self.buffer_length()`. unsafe { self.byte.set_cursor(index) }; } #[inline(always)] fn current_count(&self) -> usize { self.byte.current_count() } #[inline(always)] unsafe fn step_by_unchecked(&mut self, count: usize) { debug_assert!(self.as_slice().len() >= count); // SAFETY: safe as long as `slc.len() >= count`. unsafe { self.byte.step_by_unchecked(count) } } #[inline(always)] unsafe fn peek_many_unchecked(&self) -> V { debug_assert!(self.as_slice().len() >= mem::size_of::()); // SAFETY: safe as long as the slice has at least count elements. unsafe { self.byte.peek_many_unchecked() } } } impl<'a: 'b, 'b, const FORMAT: u128> DigitsIter<'a> for DigitsIterator<'a, 'b, FORMAT> { #[inline(always)] fn is_consumed(&mut self) -> bool { self.is_buffer_empty() } // Always a no-op #[inline(always)] fn increment_count(&mut self) { } #[inline(always)] fn peek(&mut self) -> Option<::Item> { self.byte.slc.get(self.byte.index) } /// Determine if the character is a digit. #[inline(always)] fn is_digit(&self, value: u8) -> bool { let format = NumberFormat::<{ FORMAT }> {}; char_is_digit_const(value, format.mantissa_radix()) } } impl<'a: 'b, 'b, const __: u128> Iterator for DigitsIterator<'a, 'b, __> { type Item = &'a u8; #[inline(always)] fn next(&mut self) -> Option { let value = self.byte.slc.get(self.byte.index)?; self.byte.index += 1; Some(value) } } impl<'a: 'b, 'b, const __: u128> ExactSizeIterator for DigitsIterator<'a, 'b, __> { #[inline(always)] fn len(&self) -> usize { self.buffer_length() - self.cursor() } } lexical-util-1.0.6/src/not_feature_format.rs000064400000000000000000000550541046102023000172550ustar 00000000000000//! Bare bones implementation of the format packed struct without feature //! `format`. //! //! See `feature_format` for detailed documentation. #![cfg(not(feature = "format"))] use crate::error::Error; use crate::format_builder::NumberFormatBuilder; use crate::format_flags as flags; /// Wrapper for the 128-bit packed struct. /// /// The following values are explicitly set, and therefore not configurable: /// 1. required_integer_digits /// 2. required_fraction_digits /// 3. required_exponent_digits /// 4. required_mantissa_digits /// 5. required_digits /// 6. no_positive_mantissa_sign /// 7. required_mantissa_sign /// 8. no_exponent_notation /// 9. no_positive_exponent_sign /// 10. required_exponent_sign /// 11. no_exponent_without_fraction /// 12. no_special /// 13. case_sensitive_special /// 14. no_integer_leading_zeros /// 15. no_float_leading_zeros /// 16. required_exponent_notation /// 17. case_sensitive_exponent /// 18. case_sensitive_base_prefix /// 19. case_sensitive_base_suffix /// 20. integer_internal_digit_separator /// 21. fraction_internal_digit_separator /// 22. exponent_internal_digit_separator /// 23. internal_digit_separator /// 24. integer_leading_digit_separator /// 25. fraction_leading_digit_separator /// 26. exponent_leading_digit_separator /// 27. leading_digit_separator /// 28. integer_trailing_digit_separator /// 29. fraction_trailing_digit_separator /// 30. exponent_trailing_digit_separator /// 31. trailing_digit_separator /// 32. integer_consecutive_digit_separator /// 33. fraction_consecutive_digit_separator /// 34. exponent_consecutive_digit_separator /// 35. consecutive_digit_separator /// 36. special_digit_separator /// 37. digit_separator /// 38. base_prefix /// 39. base_suffix /// 40. exponent_base /// 41. exponent_radix /// /// See `NumberFormatBuilder` for the `FORMAT` fields /// for the packed struct. #[doc(hidden)] pub struct NumberFormat; impl NumberFormat { // CONSTRUCTORS /// Create new instance (for methods and validation). pub const fn new() -> Self { Self {} } // VALIDATION /// Determine if the number format is valid. pub const fn is_valid(&self) -> bool { self.error().is_success() } /// Get the error type from the format. pub const fn error(&self) -> Error { let valid_flags = flags::REQUIRED_EXPONENT_DIGITS | flags::REQUIRED_MANTISSA_DIGITS; if !flags::is_valid_radix(self.mantissa_radix()) { Error::InvalidMantissaRadix } else if !flags::is_valid_radix(self.exponent_base()) { Error::InvalidExponentBase } else if !flags::is_valid_radix(self.exponent_radix()) { Error::InvalidExponentRadix } else if !flags::is_valid_digit_separator(FORMAT) { Error::InvalidDigitSeparator } else if !flags::is_valid_base_prefix(FORMAT) { Error::InvalidBasePrefix } else if !flags::is_valid_base_suffix(FORMAT) { Error::InvalidBaseSuffix } else if !flags::is_valid_punctuation(FORMAT) { Error::InvalidPunctuation } else if self.flags() != valid_flags { Error::InvalidFlags } else { Error::Success } } // NON-DIGIT SEPARATOR FLAGS & MASKS /// If digits are required before the decimal point. pub const REQUIRED_INTEGER_DIGITS: bool = false; /// Get if digits are required before the decimal point. #[inline(always)] pub const fn required_integer_digits(&self) -> bool { Self::REQUIRED_INTEGER_DIGITS } /// If digits are required after the decimal point. pub const REQUIRED_FRACTION_DIGITS: bool = false; /// Get if digits are required after the decimal point. #[inline(always)] pub const fn required_fraction_digits(&self) -> bool { Self::REQUIRED_FRACTION_DIGITS } /// If digits are required after the exponent character. pub const REQUIRED_EXPONENT_DIGITS: bool = true; /// Get if digits are required after the exponent character. #[inline(always)] pub const fn required_exponent_digits(&self) -> bool { Self::REQUIRED_EXPONENT_DIGITS } /// If significant digits are required. pub const REQUIRED_MANTISSA_DIGITS: bool = true; /// Get if significant digits are required. #[inline(always)] pub const fn required_mantissa_digits(&self) -> bool { Self::REQUIRED_MANTISSA_DIGITS } /// If at least 1 digit in the number is required. pub const REQUIRED_DIGITS: bool = true; /// Get if at least 1 digit in the number is required. #[inline(always)] pub const fn required_digits(&self) -> bool { Self::REQUIRED_DIGITS } /// If a positive sign before the mantissa is not allowed. pub const NO_POSITIVE_MANTISSA_SIGN: bool = false; /// Get if a positive sign before the mantissa is not allowed. #[inline(always)] pub const fn no_positive_mantissa_sign(&self) -> bool { Self::NO_POSITIVE_MANTISSA_SIGN } /// If a sign symbol before the mantissa is required. pub const REQUIRED_MANTISSA_SIGN: bool = false; /// Get if a sign symbol before the mantissa is required. #[inline(always)] pub const fn required_mantissa_sign(&self) -> bool { Self::REQUIRED_MANTISSA_SIGN } /// If exponent notation is not allowed. pub const NO_EXPONENT_NOTATION: bool = false; /// Get if exponent notation is not allowed. #[inline(always)] pub const fn no_exponent_notation(&self) -> bool { Self::NO_EXPONENT_NOTATION } /// If a positive sign before the exponent is not allowed. pub const NO_POSITIVE_EXPONENT_SIGN: bool = false; /// Get if a positive sign before the exponent is not allowed. #[inline(always)] pub const fn no_positive_exponent_sign(&self) -> bool { Self::NO_POSITIVE_EXPONENT_SIGN } /// If a sign symbol before the exponent is required. pub const REQUIRED_EXPONENT_SIGN: bool = false; /// Get if a sign symbol before the exponent is required. #[inline(always)] pub const fn required_exponent_sign(&self) -> bool { Self::REQUIRED_EXPONENT_SIGN } /// If an exponent without fraction is not allowed. pub const NO_EXPONENT_WITHOUT_FRACTION: bool = false; /// Get if an exponent without fraction is not allowed. #[inline(always)] pub const fn no_exponent_without_fraction(&self) -> bool { Self::NO_EXPONENT_WITHOUT_FRACTION } /// If special (non-finite) values are not allowed. pub const NO_SPECIAL: bool = false; /// Get if special (non-finite) values are not allowed. #[inline(always)] pub const fn no_special(&self) -> bool { Self::NO_SPECIAL } /// If special (non-finite) values are case-sensitive. pub const CASE_SENSITIVE_SPECIAL: bool = false; /// Get if special (non-finite) values are case-sensitive. #[inline(always)] pub const fn case_sensitive_special(&self) -> bool { Self::CASE_SENSITIVE_SPECIAL } /// If leading zeros before an integer are not allowed. pub const NO_INTEGER_LEADING_ZEROS: bool = false; /// Get if leading zeros before an integer are not allowed. #[inline(always)] pub const fn no_integer_leading_zeros(&self) -> bool { Self::NO_INTEGER_LEADING_ZEROS } /// If leading zeros before a float are not allowed. pub const NO_FLOAT_LEADING_ZEROS: bool = false; /// Get if leading zeros before a float are not allowed. #[inline(always)] pub const fn no_float_leading_zeros(&self) -> bool { Self::NO_FLOAT_LEADING_ZEROS } /// If exponent notation is required. pub const REQUIRED_EXPONENT_NOTATION: bool = false; /// Get if exponent notation is required. #[inline(always)] pub const fn required_exponent_notation(&self) -> bool { Self::REQUIRED_EXPONENT_NOTATION } /// If exponent characters are case-sensitive. pub const CASE_SENSITIVE_EXPONENT: bool = false; /// Get if exponent characters are case-sensitive. #[inline(always)] pub const fn case_sensitive_exponent(&self) -> bool { Self::CASE_SENSITIVE_EXPONENT } /// If base prefixes are case-sensitive. pub const CASE_SENSITIVE_BASE_PREFIX: bool = false; /// Get if base prefixes are case-sensitive. #[inline(always)] pub const fn case_sensitive_base_prefix(&self) -> bool { Self::CASE_SENSITIVE_BASE_PREFIX } /// If base suffixes are case-sensitive. pub const CASE_SENSITIVE_BASE_SUFFIX: bool = false; /// Get if base suffixes are case-sensitive. #[inline(always)] pub const fn case_sensitive_base_suffix(&self) -> bool { Self::CASE_SENSITIVE_BASE_SUFFIX } // DIGIT SEPARATOR FLAGS & MASKS // If digit separators are allowed between integer digits. /// /// This will not consider an input of only the digit separator /// to be a valid separator: the digit separator must be surrounded by /// digits. pub const INTEGER_INTERNAL_DIGIT_SEPARATOR: bool = false; /// Get if digit separators are allowed between integer digits. /// /// This will not consider an input of only the digit separator /// to be a valid separator: the digit separator must be surrounded by /// digits. #[inline(always)] pub const fn integer_internal_digit_separator(&self) -> bool { Self::INTEGER_INTERNAL_DIGIT_SEPARATOR } /// If digit separators are allowed between fraction digits. /// /// This will not consider an input of only the digit separator /// to be a valid separator: the digit separator must be surrounded by /// digits. pub const FRACTION_INTERNAL_DIGIT_SEPARATOR: bool = false; /// Get if digit separators are allowed between fraction digits. /// /// This will not consider an input of only the digit separator /// to be a valid separator: the digit separator must be surrounded by /// digits. #[inline(always)] pub const fn fraction_internal_digit_separator(&self) -> bool { Self::FRACTION_INTERNAL_DIGIT_SEPARATOR } /// If digit separators are allowed between exponent digits. /// /// This will not consider an input of only the digit separator /// to be a valid separator: the digit separator must be surrounded by /// digits. pub const EXPONENT_INTERNAL_DIGIT_SEPARATOR: bool = false; /// Get if digit separators are allowed between exponent digits. /// /// This will not consider an input of only the digit separator /// to be a valid separator: the digit separator must be surrounded by /// digits. #[inline(always)] pub const fn exponent_internal_digit_separator(&self) -> bool { Self::EXPONENT_INTERNAL_DIGIT_SEPARATOR } /// If digit separators are allowed between digits. /// /// This will not consider an input of only the digit separator /// to be a valid separator: the digit separator must be surrounded by /// digits. pub const INTERNAL_DIGIT_SEPARATOR: bool = false; /// Get if digit separators are allowed between digits. /// /// This will not consider an input of only the digit separator /// to be a valid separator: the digit separator must be surrounded by /// digits. #[inline(always)] pub const fn internal_digit_separator(&self) -> bool { Self::INTERNAL_DIGIT_SEPARATOR } /// If a digit separator is allowed before any integer digits. /// /// This will consider an input of only the digit separator /// to be a identical to empty input. pub const INTEGER_LEADING_DIGIT_SEPARATOR: bool = false; /// Get if a digit separator is allowed before any integer digits. /// /// This will consider an input of only the digit separator /// to be a identical to empty input. #[inline(always)] pub const fn integer_leading_digit_separator(&self) -> bool { Self::INTEGER_LEADING_DIGIT_SEPARATOR } /// If a digit separator is allowed before any integer digits. /// /// This will consider an input of only the digit separator /// to be a identical to empty input. pub const FRACTION_LEADING_DIGIT_SEPARATOR: bool = false; /// Get if a digit separator is allowed before any fraction digits. /// /// This will consider an input of only the digit separator /// to be a identical to empty input. #[inline(always)] pub const fn fraction_leading_digit_separator(&self) -> bool { Self::FRACTION_LEADING_DIGIT_SEPARATOR } /// If a digit separator is allowed before any exponent digits. /// /// This will consider an input of only the digit separator /// to be a identical to empty input. pub const EXPONENT_LEADING_DIGIT_SEPARATOR: bool = false; /// Get if a digit separator is allowed before any exponent digits. /// /// This will consider an input of only the digit separator /// to be a identical to empty input. #[inline(always)] pub const fn exponent_leading_digit_separator(&self) -> bool { Self::EXPONENT_LEADING_DIGIT_SEPARATOR } /// If a digit separator is allowed before any digits. /// /// This will consider an input of only the digit separator /// to be a identical to empty input. pub const LEADING_DIGIT_SEPARATOR: bool = false; /// Get if a digit separator is allowed before any digits. /// /// This will consider an input of only the digit separator /// to be a identical to empty input. #[inline(always)] pub const fn leading_digit_separator(&self) -> bool { Self::LEADING_DIGIT_SEPARATOR } /// If a digit separator is allowed after any integer digits. /// /// This will consider an input of only the digit separator /// to be a identical to empty input. pub const INTEGER_TRAILING_DIGIT_SEPARATOR: bool = false; /// Get if a digit separator is allowed after any integer digits. /// /// This will consider an input of only the digit separator /// to be a identical to empty input. #[inline(always)] pub const fn integer_trailing_digit_separator(&self) -> bool { Self::INTEGER_TRAILING_DIGIT_SEPARATOR } /// If a digit separator is allowed after any fraction digits. /// /// This will consider an input of only the digit separator /// to be a identical to empty input. pub const FRACTION_TRAILING_DIGIT_SEPARATOR: bool = false; /// Get if a digit separator is allowed after any fraction digits. /// /// This will consider an input of only the digit separator /// to be a identical to empty input. #[inline(always)] pub const fn fraction_trailing_digit_separator(&self) -> bool { Self::FRACTION_TRAILING_DIGIT_SEPARATOR } /// If a digit separator is allowed after any exponent digits. /// /// This will consider an input of only the digit separator /// to be a identical to empty input. pub const EXPONENT_TRAILING_DIGIT_SEPARATOR: bool = false; /// Get if a digit separator is allowed after any exponent digits. /// /// This will consider an input of only the digit separator /// to be a identical to empty input. #[inline(always)] pub const fn exponent_trailing_digit_separator(&self) -> bool { Self::EXPONENT_TRAILING_DIGIT_SEPARATOR } /// If a digit separator is allowed after any digits. /// /// This will consider an input of only the digit separator /// to be a identical to empty input. pub const TRAILING_DIGIT_SEPARATOR: bool = false; /// Get if a digit separator is allowed after any digits. /// /// This will consider an input of only the digit separator /// to be a identical to empty input. #[inline(always)] pub const fn trailing_digit_separator(&self) -> bool { Self::TRAILING_DIGIT_SEPARATOR } /// If multiple consecutive integer digit separators are allowed. pub const INTEGER_CONSECUTIVE_DIGIT_SEPARATOR: bool = false; /// Get if multiple consecutive integer digit separators are allowed. #[inline(always)] pub const fn integer_consecutive_digit_separator(&self) -> bool { Self::INTEGER_CONSECUTIVE_DIGIT_SEPARATOR } /// If multiple consecutive fraction digit separators are allowed. pub const FRACTION_CONSECUTIVE_DIGIT_SEPARATOR: bool = false; /// Get if multiple consecutive fraction digit separators are allowed. #[inline(always)] pub const fn fraction_consecutive_digit_separator(&self) -> bool { Self::FRACTION_CONSECUTIVE_DIGIT_SEPARATOR } /// If multiple consecutive exponent digit separators are allowed. pub const EXPONENT_CONSECUTIVE_DIGIT_SEPARATOR: bool = false; /// Get if multiple consecutive exponent digit separators are allowed. #[inline(always)] pub const fn exponent_consecutive_digit_separator(&self) -> bool { Self::EXPONENT_CONSECUTIVE_DIGIT_SEPARATOR } /// If multiple consecutive digit separators are allowed. pub const CONSECUTIVE_DIGIT_SEPARATOR: bool = false; /// Get if multiple consecutive digit separators are allowed. #[inline(always)] pub const fn consecutive_digit_separator(&self) -> bool { Self::CONSECUTIVE_DIGIT_SEPARATOR } /// If any digit separators are allowed in special (non-finite) values. pub const SPECIAL_DIGIT_SEPARATOR: bool = false; /// Get if any digit separators are allowed in special (non-finite) values. #[inline(always)] pub const fn special_digit_separator(&self) -> bool { Self::SPECIAL_DIGIT_SEPARATOR } // CHARACTERS /// The digit separator character in the packed struct. pub const DIGIT_SEPARATOR: u8 = 0; /// Get the digit separator character. /// /// If the digit separator is 0, digit separators are not allowed. #[inline(always)] pub const fn digit_separator(&self) -> u8 { Self::DIGIT_SEPARATOR } /// The base prefix character in the packed struct. pub const BASE_PREFIX: u8 = 0; /// Get the character for the base prefix. /// /// If the base prefix is 0, base prefixes are not allowed. /// The number will have then have the format `0$base_prefix...`. /// For example, a hex base prefix would be `0x`. Base prefixes are /// always optional. #[inline(always)] pub const fn base_prefix(&self) -> u8 { Self::BASE_PREFIX } /// Get if the format has a base prefix. #[inline(always)] pub const fn has_base_prefix(&self) -> bool { false } /// The base suffix character in the packed struct. pub const BASE_SUFFIX: u8 = 0; /// Character for the base suffix. /// /// If not provided, base suffixes are not allowed. /// The number will have then have the format `...$base_suffix`. /// For example, a hex base prefix would be `0x`. Base prefixes are /// always optional. #[inline(always)] pub const fn base_suffix(&self) -> u8 { Self::BASE_SUFFIX } /// Get if the format has a base suffix. #[inline(always)] pub const fn has_base_suffix(&self) -> bool { false } // RADIX /// The radix for the significant digits in the packed struct. pub const MANTISSA_RADIX: u32 = flags::mantissa_radix(FORMAT); /// Get the radix for the mantissa digits. #[inline(always)] pub const fn mantissa_radix(&self) -> u32 { Self::MANTISSA_RADIX } /// The radix for the significant digits in the packed struct. /// Alias for `MANTISSA_RADIX`. pub const RADIX: u32 = Self::MANTISSA_RADIX; /// Get the radix for the significant digits. #[inline(always)] pub const fn radix(&self) -> u32 { Self::RADIX } /// Get the radix**2 for the significant digits. #[inline(always)] pub const fn radix2(&self) -> u32 { self.radix().wrapping_mul(self.radix()) } /// Get the radix**4 for the significant digits. #[inline(always)] pub const fn radix4(&self) -> u32 { self.radix2().wrapping_mul(self.radix2()) } /// Get the radix*** for the significant digits. #[inline(always)] pub const fn radix8(&self) -> u32 { self.radix4().wrapping_mul(self.radix4()) } /// The base for the exponent. pub const EXPONENT_BASE: u32 = flags::exponent_base(FORMAT); /// Get the base for the exponent. /// /// IE, a base of 2 means we have `mantissa * 2^exponent`. /// If not provided, it defaults to `radix`. #[inline(always)] pub const fn exponent_base(&self) -> u32 { Self::EXPONENT_BASE } /// The radix for the exponent digits. pub const EXPONENT_RADIX: u32 = flags::exponent_radix(FORMAT); /// Get the radix for the exponent digits. #[inline(always)] pub const fn exponent_radix(&self) -> u32 { Self::EXPONENT_RADIX } // FLAGS /// Get the flags from the number format. #[inline(always)] pub const fn flags(&self) -> u128 { FORMAT & flags::FLAG_MASK } /// Get the interface flags from the number format. #[inline(always)] pub const fn interface_flags(&self) -> u128 { FORMAT & flags::INTERFACE_FLAG_MASK } /// Get the digit separator flags from the number format. #[inline(always)] pub const fn digit_separator_flags(&self) -> u128 { FORMAT & flags::DIGIT_SEPARATOR_FLAG_MASK } /// Get the exponent flags from the number format. #[inline(always)] pub const fn exponent_flags(&self) -> u128 { FORMAT & flags::EXPONENT_FLAG_MASK } /// Get the integer digit separator flags from the number format. #[inline(always)] pub const fn integer_digit_separator_flags(&self) -> u128 { FORMAT & flags::INTEGER_DIGIT_SEPARATOR_FLAG_MASK } /// Get the fraction digit separator flags from the number format. #[inline(always)] pub const fn fraction_digit_separator_flags(&self) -> u128 { FORMAT & flags::FRACTION_DIGIT_SEPARATOR_FLAG_MASK } /// Get the exponent digit separator flags from the number format. #[inline(always)] pub const fn exponent_digit_separator_flags(&self) -> u128 { FORMAT & flags::EXPONENT_DIGIT_SEPARATOR_FLAG_MASK } // BUILDER /// Get the number format builder from the format. #[inline] pub const fn builder() -> NumberFormatBuilder { NumberFormatBuilder::new() } /// Get the number format builder from the format. #[inline] pub const fn rebuild() -> NumberFormatBuilder { NumberFormatBuilder::rebuild(FORMAT) } } impl Default for NumberFormat { fn default() -> Self { Self::new() } } lexical-util-1.0.6/src/num.rs000064400000000000000000001152611046102023000141660ustar 00000000000000//! Utilities for Rust numbers. //! //! These traits define useful properties, methods, associated //! types, and trait bounds, and conversions for working with //! numbers in generic code. #![cfg_attr(any(), rustfmt::skip)] use core::{fmt, mem, ops}; #[cfg(feature = "f16")] use crate::bf16::bf16; #[cfg(feature = "f16")] use crate::f16::f16; // AS PRIMITIVE // ------------ /// Type that can be converted to primitive with `as`. pub trait AsPrimitive: Copy + PartialEq + PartialOrd + Send + Sync + Sized { fn as_u8(self) -> u8; fn as_u16(self) -> u16; fn as_u32(self) -> u32; fn as_u64(self) -> u64; fn as_u128(self) -> u128; fn as_usize(self) -> usize; fn as_i8(self) -> i8; fn as_i16(self) -> i16; fn as_i32(self) -> i32; fn as_i64(self) -> i64; fn as_i128(self) -> i128; fn as_isize(self) -> isize; fn as_f32(self) -> f32; fn as_f64(self) -> f64; fn from_u32(value: u32) -> Self; fn from_u64(value: u64) -> Self; #[cfg(feature = "f16")] fn as_f16(self) -> f16; #[cfg(feature = "f16")] fn as_bf16(self) -> bf16; } macro_rules! as_primitive { ($($t:ty)*) => ($( impl AsPrimitive for $t { #[inline(always)] fn as_u8(self) -> u8 { self as u8 } #[inline(always)] fn as_u16(self) -> u16 { self as u16 } #[inline(always)] fn as_u32(self) -> u32 { self as u32 } #[inline(always)] fn as_u64(self) -> u64 { self as u64 } #[inline(always)] fn as_u128(self) -> u128 { self as u128 } #[inline(always)] fn as_usize(self) -> usize { self as usize } #[inline(always)] fn as_i8(self) -> i8 { self as i8 } #[inline(always)] fn as_i16(self) -> i16 { self as i16 } #[inline(always)] fn as_i32(self) -> i32 { self as i32 } #[inline(always)] fn as_i64(self) -> i64 { self as i64 } #[inline(always)] fn as_i128(self) -> i128 { self as i128 } #[inline(always)] fn as_isize(self) -> isize { self as isize } #[inline(always)] fn as_f32(self) -> f32 { self as f32 } #[inline(always)] fn as_f64(self) -> f64 { self as f64 } #[inline(always)] fn from_u32(value: u32) -> Self { value as Self } #[inline(always)] fn from_u64(value: u64) -> Self { value as Self } #[cfg(feature = "f16")] #[inline(always)] fn as_f16(self) -> f16 { f16::from_f32(self as f32) } #[cfg(feature = "f16")] #[inline(always)] fn as_bf16(self) -> bf16 { bf16::from_f32(self as f32) } } )*) } as_primitive! { u8 u16 u32 u64 u128 usize i8 i16 i32 i64 i128 isize f32 f64 } #[cfg(feature = "f16")] macro_rules! half_as_primitive { ($($t:ty)*) => ($( impl AsPrimitive for $t { #[inline(always)] fn as_u8(self) -> u8 { self.as_f32() as u8 } #[inline(always)] fn as_u16(self) -> u16 { self.as_f32() as u16 } #[inline(always)] fn as_u32(self) -> u32 { self.as_f32() as u32 } #[inline(always)] fn as_u64(self) -> u64 { self.as_f32() as u64 } #[inline(always)] fn as_u128(self) -> u128 { self.as_f32() as u128 } #[inline(always)] fn as_usize(self) -> usize { self.as_f32() as usize } #[inline(always)] fn as_i8(self) -> i8 { self.as_f32() as i8 } #[inline(always)] fn as_i16(self) -> i16 { self.as_f32() as i16 } #[inline(always)] fn as_i32(self) -> i32 { self.as_f32() as i32 } #[inline(always)] fn as_i64(self) -> i64 { self.as_f32() as i64 } #[inline(always)] fn as_i128(self) -> i128 { self.as_f32() as i128 } #[inline(always)] fn as_isize(self) -> isize { self.as_f32() as isize } #[inline(always)] fn as_f32(self) -> f32 { self.as_f32() as f32 } #[inline(always)] fn as_f64(self) -> f64 { self.as_f32() as f64 } #[inline(always)] #[allow(clippy::as_underscore)] // reason="intentionally used in a generic sense" fn from_u32(value: u32) -> Self { Self::from_f32(value as _) } #[inline(always)] fn from_u64(value: u64) -> Self { _ = value; unimplemented!() } #[inline(always)] fn as_f16(self) -> f16 { f16::from_f32(self.as_f32()) } #[inline(always)] fn as_bf16(self) -> bf16 { bf16::from_f32(self.as_f32()) } } )*) } #[cfg(feature = "f16")] half_as_primitive! { f16 bf16 } // AS CAST // ------- /// An interface for casting between machine scalars. pub trait AsCast: AsPrimitive { /// Creates a number from another value that can be converted into /// a primitive via the `AsPrimitive` trait. fn as_cast(n: N) -> Self; } /// Allows the high-level conversion of generic types as if `as` was used. #[inline(always)] pub fn as_cast(t: T) -> U { U::as_cast(t) } macro_rules! as_cast { ($($t:ty, $meth:ident ; )*) => ($( impl AsCast for $t { #[inline(always)] #[allow(clippy::as_underscore)] // reason="intentional due to generic API" fn as_cast(n: N) -> $t { n.$meth() as _ } } )*); } as_cast!( u8, as_u8 ; u16, as_u16 ; u32, as_u32 ; u64, as_u64 ; u128, as_u128 ; usize, as_usize ; i8, as_i8 ; i16, as_i16 ; i32, as_i32 ; i64, as_i64 ; i128, as_i128 ; isize, as_isize ; f32, as_f32 ; f64, as_f64 ; ); #[cfg(feature = "f16")] as_cast!( f16, as_f16 ; bf16, as_bf16 ; ); // PRIMITIVE // --------- /// Primitive type trait (which all have static lifetimes). pub trait Primitive: 'static + fmt::Debug + fmt::Display + AsCast {} macro_rules! primitive { ($($t:ty)*) => ($( impl Primitive for $t {} )*) } primitive! { u8 u16 u32 u64 u128 usize i8 i16 i32 i64 i128 isize f32 f64 } #[cfg(feature = "f16")] primitive! { f16 bf16 } // NUMBER // ------ /// Numerical type trait. pub trait Number: Default + Primitive + // Operations ops::Add + ops::AddAssign + ops::Div + ops::DivAssign + ops::Mul + ops::MulAssign + ops::Rem + ops::RemAssign + ops::Sub + ops::SubAssign { /// If the number is a signed type. const IS_SIGNED: bool; } macro_rules! number_impl { ($($t:tt $is_signed:literal ; )*) => ($( impl Number for $t { const IS_SIGNED: bool = $is_signed; } )*) } number_impl! { u8 false ; u16 false ; u32 false ; u64 false ; u128 false ; usize false ; i8 true ; i16 true ; i32 true ; i64 true ; i128 true ; isize true ; f32 true ; f64 true ; // f128 true } #[cfg(feature = "f16")] number_impl! { f16 true ; bf16 true ; } // INTEGER // ------- /// Defines a trait that supports integral operations. pub trait Integer: // Basic Number + Eq + Ord + // Operations ops::BitAnd + ops::BitAndAssign + ops::BitOr + ops::BitOrAssign + ops::BitXor + ops::BitXorAssign + ops::Not + ops::Shl + ops::Shl + ops::ShlAssign + ops::Shr + ops::ShrAssign + { // CONSTANTS const ZERO: Self; const ONE: Self; const TWO: Self; const MAX: Self; const MIN: Self; const BITS: usize; // FUNCTIONS (INHERITED) fn leading_zeros(self) -> u32; fn trailing_zeros(self) -> u32; fn pow(self, exp: u32) -> Self; fn checked_pow(self, exp: u32) -> Option; fn overflowing_pow(self, exp: u32) -> (Self, bool); fn checked_add(self, i: Self) -> Option; fn checked_sub(self, i: Self) -> Option; fn checked_mul(self, i: Self) -> Option; fn overflowing_add(self, i: Self) -> (Self, bool); fn overflowing_sub(self, i: Self) -> (Self, bool); fn overflowing_mul(self, i: Self) -> (Self, bool); fn wrapping_add(self, i: Self) -> Self; fn wrapping_sub(self, i: Self) -> Self; fn wrapping_mul(self, i: Self) -> Self; fn wrapping_neg(self) -> Self; fn saturating_add(self, i: Self) -> Self; fn saturating_sub(self, i: Self) -> Self; fn saturating_mul(self, i: Self) -> Self; /// Get the fast ceiling of the quotient from integer division. /// Not safe, since the remainder can easily overflow. #[inline(always)] fn ceil_divmod(self, y: Self) -> (Self, i32) { let q = self / y; let r = self % y; match r == Self::ZERO { true => (q, i32::as_cast(r)), false => (q + Self::ONE, i32::as_cast(r) - i32::as_cast(y)) } } /// Get the fast ceiling of the quotient from integer division. /// Not safe, since the remainder can easily overflow. #[inline(always)] fn ceil_div(self, y: Self) -> Self { self.ceil_divmod(y).0 } /// Get the fast ceiling modulus from integer division. /// Not safe, since the remainder can easily overflow. #[inline(always)] fn ceil_mod(self, y: Self) -> i32 { self.ceil_divmod(y).1 } // PROPERTIES /// Get the number of bits in a value. #[inline(always)] fn bit_length(self) -> u32 { Self::BITS as u32 - self.leading_zeros() } /// Returns true if the least-significant bit is odd. #[inline(always)] fn is_odd(self) -> bool { self & Self::ONE == Self::ONE } /// Returns true if the least-significant bit is even. #[inline(always)] fn is_even(self) -> bool { !self.is_odd() } /// Get the maximum number of digits before the slice will overflow. /// /// This is effectively the floor(log(2**BITS-1, radix)), but we can /// try to go a bit lower without worrying too much. #[inline(always)] fn overflow_digits(radix: u32) -> usize { // this is heavily optimized for base10 and it's a way under estimate // that said, it's fast and works. if radix <= 16 { mem::size_of::() * 2 - Self::IS_SIGNED as usize } else { // way under approximation but always works and is fast mem::size_of::() } } } macro_rules! integer_impl { ($($t:tt)*) => ($( impl Integer for $t { const ZERO: $t = 0; const ONE: $t = 1; const TWO: $t = 2; const MAX: $t = $t::MAX; const MIN: $t = $t::MIN; const BITS: usize = $t::BITS as usize; #[inline(always)] fn leading_zeros(self) -> u32 { $t::leading_zeros(self) } #[inline(always)] fn trailing_zeros(self) -> u32 { $t::trailing_zeros(self) } #[inline(always)] fn checked_add(self, i: Self) -> Option { $t::checked_add(self, i) } #[inline(always)] fn checked_sub(self, i: Self) -> Option { $t::checked_sub(self, i) } #[inline(always)] fn checked_mul(self, i: Self) -> Option { $t::checked_mul(self, i) } #[inline(always)] fn overflowing_add(self, i: Self) -> (Self, bool) { $t::overflowing_add(self, i) } #[inline(always)] fn overflowing_sub(self, i: Self) -> (Self, bool) { $t::overflowing_sub(self, i) } #[inline(always)] fn overflowing_mul(self, i: Self) -> (Self, bool) { $t::overflowing_mul(self, i) } #[inline(always)] fn wrapping_add(self, i: Self) -> Self { $t::wrapping_add(self, i) } #[inline(always)] fn wrapping_sub(self, i: Self) -> Self { $t::wrapping_sub(self, i) } #[inline(always)] fn wrapping_mul(self, i: Self) -> Self { $t::wrapping_mul(self, i) } #[inline(always)] fn wrapping_neg(self) -> Self { $t::wrapping_neg(self) } #[inline(always)] fn pow(self, exp: u32) -> Self { Self::pow(self, exp) } #[inline(always)] fn checked_pow(self, exp: u32) -> Option { Self::checked_pow(self, exp) } #[inline(always)] fn overflowing_pow(self, exp: u32) -> (Self, bool) { Self::overflowing_pow(self, exp) } #[inline(always)] fn saturating_add(self, i: Self) -> Self { $t::saturating_add(self, i) } #[inline(always)] fn saturating_sub(self, i: Self) -> Self { $t::saturating_sub(self, i) } #[inline(always)] fn saturating_mul(self, i: Self) -> Self { $t::saturating_mul(self, i) } } )*) } integer_impl! { u8 u16 u32 u64 u128 i8 i16 i32 i64 i128 usize isize } // SIGNED INTEGER // -------------- /// Defines a trait that supports signed integral operations. pub trait SignedInteger: Integer + ops::Neg {} macro_rules! signed_integer_impl { ($($t:tt)*) => ($( impl SignedInteger for $t {} )*) } signed_integer_impl! { i8 i16 i32 i64 i128 isize } // UNSIGNED INTEGER // ---------------- /// Defines a trait that supports unsigned integral operations. pub trait UnsignedInteger: Integer {} macro_rules! unsigned_integer_impl { ($($t:ty)*) => ($( impl UnsignedInteger for $t {} )*) } unsigned_integer_impl! { u8 u16 u32 u64 u128 usize } // FLOAT // ----- /// Float information for native float types. #[cfg(feature = "floats")] pub trait Float: Number + ops::Neg { /// Unsigned type of the same size. type Unsigned: UnsignedInteger; // CONSTANTS const ZERO: Self; const ONE: Self; const TWO: Self; const MAX: Self; const MIN: Self; const INFINITY: Self; const NEG_INFINITY: Self; const NAN: Self; const BITS: usize; /// Bitmask for the sign bit. const SIGN_MASK: Self::Unsigned; /// Bitmask for the exponent, including the hidden bit. const EXPONENT_MASK: Self::Unsigned; /// Bitmask for the hidden bit in exponent, which is an implicit 1 in the /// fraction. const HIDDEN_BIT_MASK: Self::Unsigned; /// Bitmask for the mantissa (fraction), excluding the hidden bit. const MANTISSA_MASK: Self::Unsigned; /// Mask to determine if a full-carry occurred (1 in bit above hidden bit). const CARRY_MASK: Self::Unsigned; // PROPERTIES // The following constants can be calculated as follows: // - `INFINITY_BITS`: EXPONENT_MASK // - `NEGATIVE_INFINITY_BITS`: INFINITY_BITS | SIGN_MASK // - `EXPONENT_BIAS`: `2^(EXPONENT_SIZE-1) - 1 + MANTISSA_SIZE` // - `DENORMAL_EXPONENT`: `1 - EXPONENT_BIAS` // - `MAX_EXPONENT`: `2^EXPONENT_SIZE - 1 - EXPONENT_BIAS` /// Positive infinity as bits. const INFINITY_BITS: Self::Unsigned; /// Positive infinity as bits. const NEGATIVE_INFINITY_BITS: Self::Unsigned; /// Size of the exponent. const EXPONENT_SIZE: i32; /// Size of the significand (mantissa) without hidden bit. const MANTISSA_SIZE: i32; /// Bias of the exponent. const EXPONENT_BIAS: i32; /// Exponent portion of a denormal float. const DENORMAL_EXPONENT: i32; /// Maximum exponent value in float. const MAX_EXPONENT: i32; // FUNCTIONS (INHERITED) // Re-export the to and from bits methods. fn to_bits(self) -> Self::Unsigned; fn from_bits(u: Self::Unsigned) -> Self; fn ln(self) -> Self; fn floor(self) -> Self; fn is_sign_positive(self) -> bool; fn is_sign_negative(self) -> bool; /// Returns true if the float is a denormal. #[inline(always)] fn is_denormal(self) -> bool { self.to_bits() & Self::EXPONENT_MASK == Self::Unsigned::ZERO } /// Returns true if the float is a NaN or Infinite. #[inline(always)] fn is_special(self) -> bool { self.to_bits() & Self::EXPONENT_MASK == Self::EXPONENT_MASK } /// Returns true if the float is NaN. #[inline(always)] fn is_nan(self) -> bool { self.is_special() && (self.to_bits() & Self::MANTISSA_MASK) != Self::Unsigned::ZERO } /// Returns true if the float is infinite. #[inline(always)] fn is_inf(self) -> bool { self.is_special() && (self.to_bits() & Self::MANTISSA_MASK) == Self::Unsigned::ZERO } /// Returns true if the float's least-significant mantissa bit is odd. #[inline(always)] fn is_odd(self) -> bool { self.to_bits().is_odd() } /// Returns true if the float's least-significant mantissa bit is even. #[inline(always)] fn is_even(self) -> bool { !self.is_odd() } /// Returns true if the float needs a negative sign when serializing it. /// /// This is true if it's `-0.0` or it's below 0 and not NaN. But inf values /// need the sign. #[inline(always)] fn needs_negative_sign(self) -> bool { self.is_sign_negative() && !self.is_nan() } /// Get exponent component from the float. #[inline(always)] fn exponent(self) -> i32 { if self.is_denormal() { return Self::DENORMAL_EXPONENT; } let bits = self.to_bits(); let biased_e = i32::as_cast((bits & Self::EXPONENT_MASK) >> Self::MANTISSA_SIZE).as_i32(); biased_e - Self::EXPONENT_BIAS } /// Get mantissa (significand) component from float. #[inline(always)] fn mantissa(self) -> Self::Unsigned { let bits = self.to_bits(); let s = bits & Self::MANTISSA_MASK; if !self.is_denormal() { s + Self::HIDDEN_BIT_MASK } else { s } } /// Get next greater float. #[inline(always)] fn next(self) -> Self { let bits = self.to_bits(); if self.is_sign_negative() && self == Self::ZERO { // -0.0 Self::ZERO } else if bits == Self::INFINITY_BITS { Self::from_bits(Self::INFINITY_BITS) } else if self.is_sign_negative() { Self::from_bits(bits.saturating_sub(Self::Unsigned::ONE)) } else { Self::from_bits(bits.saturating_add(Self::Unsigned::ONE)) } } /// Get next greater float for a positive float. /// Value must be >= 0.0 and < INFINITY. #[inline(always)] fn next_positive(self) -> Self { debug_assert!(self.is_sign_positive() && !self.is_inf()); Self::from_bits(self.to_bits() + Self::Unsigned::ONE) } /// Get previous greater float, such that `self.prev().next() == self`. #[inline(always)] fn prev(self) -> Self { let bits = self.to_bits(); if self.is_sign_positive() && self == Self::ZERO { // +0.0 -Self::ZERO } else if bits == Self::NEGATIVE_INFINITY_BITS { Self::from_bits(Self::NEGATIVE_INFINITY_BITS) } else if self.is_sign_negative() { Self::from_bits(bits.saturating_add(Self::Unsigned::ONE)) } else { Self::from_bits(bits.saturating_sub(Self::Unsigned::ONE)) } } /// Get previous greater float for a positive float. /// Value must be > 0.0. #[inline(always)] fn prev_positive(self) -> Self { debug_assert!(self.is_sign_positive() && self != Self::ZERO); Self::from_bits(self.to_bits() - Self::Unsigned::ONE) } /// Round a positive number to even. #[inline(always)] fn round_positive_even(self) -> Self { if self.mantissa().is_odd() { self.next_positive() } else { self } } /// Get the max of two finite numbers. #[inline(always)] fn max_finite(self, f: Self) -> Self { debug_assert!(!self.is_special() && !f.is_special(), "max_finite self={} f={}", self, f); if self < f { f } else { self } } /// Get the min of two finite numbers. #[inline(always)] fn min_finite(self, f: Self) -> Self { debug_assert!(!self.is_special() && !f.is_special(), "min_finite self={} f={}", self, f); if self < f { self } else { f } } } /// Define the float literals. #[cfg(feature = "floats")] macro_rules! float_literals { ($float:ty) => { const ZERO: $float = 0.0; const ONE: $float = 1.0; const TWO: $float = 2.0; const MAX: $float = <$float>::MAX; const MIN: $float = <$float>::MIN; const INFINITY: $float = <$float>::INFINITY; const NEG_INFINITY: $float = <$float>::NEG_INFINITY; const NAN: $float = <$float>::NAN; const BITS: usize = mem::size_of::<$float>() * 8; }; } /// Define the float masks. #[cfg(feature = "floats")] macro_rules! float_masks { ( float => $float:ty,sign_mask => $sign:literal,exponent_mask => $exponent:literal,hidden_bit_mask => $hidden:literal,mantissa_mask => $mantissa:literal, ) => { const SIGN_MASK: <$float>::Unsigned = $sign; const EXPONENT_MASK: <$float>::Unsigned = $exponent; const HIDDEN_BIT_MASK: <$float>::Unsigned = $hidden; const MANTISSA_MASK: <$float>::Unsigned = $mantissa; // The carry mask is always 1 bit above the hidden bit. const CARRY_MASK: <$float>::Unsigned = $hidden << 1; // Infinity is always every exponent bit set. const INFINITY_BITS: <$float>::Unsigned = $exponent; // Negative infinity is just infinity + sign. const NEGATIVE_INFINITY_BITS: <$float>::Unsigned = $exponent | $sign; }; } // Due to missing specifics or types for the following float types, // `Float` is not yet fully implemented for: // - f128 #[cfg(feature = "f16")] macro_rules! float_one { ($f:ident) => { (($f::EXPONENT_BIAS - $f::MANTISSA_SIZE) as u16) << $f::MANTISSA_SIZE }; } #[cfg(feature = "f16")] macro_rules! float_two { ($f:ident) => { (($f::EXPONENT_BIAS - $f::MANTISSA_SIZE + 1) as u16) << $f::MANTISSA_SIZE }; } #[cfg(feature = "f16")] macro_rules! float_max { ($f:ident) => { ($f::EXPONENT_MASK ^ $f::HIDDEN_BIT_MASK) | $f::MANTISSA_MASK }; } #[cfg(feature = "f16")] macro_rules! float_min { ($f:ident) => { $f::MAX.to_bits() | $f::SIGN_MASK }; } #[cfg(feature = "f16")] macro_rules! float_nan { ($f:ident) => { $f::EXPONENT_MASK | ($f::HIDDEN_BIT_MASK >> 1) }; } #[cfg(feature = "f16")] impl Float for f16 { type Unsigned = u16; const ZERO: Self = Self::from_bits(0); const ONE: Self = Self::from_bits(float_one!(Self)); const TWO: Self = Self::from_bits(float_two!(Self)); const MAX: Self = Self::from_bits(float_max!(Self)); const MIN: Self = Self::from_bits(float_min!(Self)); const INFINITY: Self = Self::from_bits(Self::INFINITY_BITS); const NEG_INFINITY: Self = Self::from_bits(Self::NEGATIVE_INFINITY_BITS); const NAN: Self = Self::from_bits(float_nan!(Self)); const BITS: usize = mem::size_of::() * 8; float_masks!( float => Self, sign_mask => 0x8000, exponent_mask => 0x7C00, hidden_bit_mask => 0x0400, mantissa_mask => 0x03FF, ); const EXPONENT_SIZE: i32 = 5; const MANTISSA_SIZE: i32 = 10; const EXPONENT_BIAS: i32 = 15 + Self::MANTISSA_SIZE; const DENORMAL_EXPONENT: i32 = 1 - Self::EXPONENT_BIAS; const MAX_EXPONENT: i32 = 0x1F - Self::EXPONENT_BIAS; #[inline(always)] fn to_bits(self) -> u16 { f16::to_bits(self) } #[inline(always)] fn from_bits(u: u16) -> f16 { f16::from_bits(u) } #[inline(always)] fn ln(self) -> f16 { f16::from_f32(self.as_f32().ln()) } #[inline(always)] fn floor(self) -> f16 { f16::from_f32(self.as_f32().floor()) } #[inline(always)] fn is_sign_positive(self) -> bool { self.to_bits() & Self::SIGN_MASK == 0 } #[inline(always)] fn is_sign_negative(self) -> bool { !self.is_sign_positive() } } #[cfg(feature = "f16")] impl Float for bf16 { type Unsigned = u16; const ZERO: Self = Self::from_bits(0); const ONE: Self = Self::from_bits(float_one!(Self)); const TWO: Self = Self::from_bits(float_two!(Self)); const MAX: Self = Self::from_bits(float_max!(Self)); const MIN: Self = Self::from_bits(float_min!(Self)); const INFINITY: Self = Self::from_bits(Self::INFINITY_BITS); const NEG_INFINITY: Self = Self::from_bits(Self::NEGATIVE_INFINITY_BITS); const NAN: Self = Self::from_bits(float_nan!(Self)); const BITS: usize = mem::size_of::() * 8; float_masks!( float => Self, sign_mask => 0x8000, exponent_mask => 0x7F80, hidden_bit_mask => 0x0080, mantissa_mask => 0x007F, ); const EXPONENT_SIZE: i32 = 8; const MANTISSA_SIZE: i32 = 7; const EXPONENT_BIAS: i32 = 127 + Self::MANTISSA_SIZE; const DENORMAL_EXPONENT: i32 = 1 - Self::EXPONENT_BIAS; const MAX_EXPONENT: i32 = 0xFF - Self::EXPONENT_BIAS; #[inline(always)] fn to_bits(self) -> u16 { bf16::to_bits(self) } #[inline(always)] fn from_bits(u: u16) -> bf16 { bf16::from_bits(u) } #[inline(always)] fn ln(self) -> bf16 { bf16::from_f32(self.as_f32().ln()) } #[inline(always)] fn floor(self) -> bf16 { bf16::from_f32(self.as_f32().floor()) } #[inline(always)] fn is_sign_positive(self) -> bool { self.to_bits() & Self::SIGN_MASK == 0 } #[inline(always)] fn is_sign_negative(self) -> bool { !self.is_sign_positive() } } #[cfg(feature = "floats")] impl Float for f32 { type Unsigned = u32; float_literals!(f32); float_masks!( float => Self, sign_mask => 0x80000000, exponent_mask => 0x7F800000, hidden_bit_mask => 0x00800000, mantissa_mask => 0x007FFFFF, ); const EXPONENT_SIZE: i32 = 8; const MANTISSA_SIZE: i32 = 23; const EXPONENT_BIAS: i32 = 127 + Self::MANTISSA_SIZE; const DENORMAL_EXPONENT: i32 = 1 - Self::EXPONENT_BIAS; const MAX_EXPONENT: i32 = 0xFF - Self::EXPONENT_BIAS; #[inline(always)] fn to_bits(self) -> u32 { f32::to_bits(self) } #[inline(always)] fn from_bits(u: u32) -> f32 { f32::from_bits(u) } #[inline(always)] fn ln(self) -> f32 { #[cfg(feature = "std")] return f32::ln(self); #[cfg(not(feature = "std"))] return logf(self); } #[inline(always)] fn floor(self) -> f32 { #[cfg(feature = "std")] return f32::floor(self); #[cfg(not(feature = "std"))] return floorf(self); } #[inline(always)] fn is_sign_positive(self) -> bool { f32::is_sign_positive(self) } #[inline(always)] fn is_sign_negative(self) -> bool { f32::is_sign_negative(self) } } #[cfg(feature = "floats")] impl Float for f64 { type Unsigned = u64; float_literals!(f64); float_masks!( float => Self, sign_mask => 0x8000000000000000, exponent_mask => 0x7FF0000000000000, hidden_bit_mask => 0x0010000000000000, mantissa_mask => 0x000FFFFFFFFFFFFF, ); const EXPONENT_SIZE: i32 = 11; const MANTISSA_SIZE: i32 = 52; const EXPONENT_BIAS: i32 = 1023 + Self::MANTISSA_SIZE; const DENORMAL_EXPONENT: i32 = 1 - Self::EXPONENT_BIAS; const MAX_EXPONENT: i32 = 0x7FF - Self::EXPONENT_BIAS; #[inline(always)] fn to_bits(self) -> u64 { f64::to_bits(self) } #[inline(always)] fn from_bits(u: u64) -> f64 { f64::from_bits(u) } #[inline(always)] fn ln(self) -> f64 { #[cfg(feature = "std")] return f64::ln(self); #[cfg(not(feature = "std"))] return logd(self); } #[inline(always)] fn floor(self) -> f64 { #[cfg(feature = "std")] return f64::floor(self); #[cfg(not(feature = "std"))] return floord(self); } #[inline(always)] fn is_sign_positive(self) -> bool { f64::is_sign_positive(self) } #[inline(always)] fn is_sign_negative(self) -> bool { f64::is_sign_negative(self) } } // #[cfg(feature = "f128")] // impl Float for f128 { // type Unsigned = u128; // float_literals!(f128); // float_masks!( // float => Self, // sign_mask => 0x80000000000000000000000000000000, // exponent_mask => 0x7FFF0000000000000000000000000000, // hidden_bit_mask => 0x00010000000000000000000000000000, // mantissa_mask => 0x0000FFFFFFFFFFFFFFFFFFFFFFFFFFFF, // ); // const EXPONENT_SIZE: i32 = 15; // const MANTISSA_SIZE: i32 = 112; // const EXPONENT_BIAS: i32 = 16383 + Self::MANTISSA_SIZE; // const DENORMAL_EXPONENT: i32 = 1 - Self::EXPONENT_BIAS; // const MAX_EXPONENT: i32 = 0x7FFF - Self::EXPONENT_BIAS; // } // FLOAT HELPERS // ------------- // These are adapted from libm, a port of musl libc's libm to Rust. // libm can be found online [here](https://github.com/rust-lang/libm), // and is similarly licensed under an Apache2.0/MIT license /// # Safety /// /// Safe as long as `e` is properly initialized. #[cfg(all(not(feature = "std"), feature = "floats"))] macro_rules! volatile { ($e:expr) => { // SAFETY: safe as long as `$e` has been properly initialized. unsafe { core::ptr::read_volatile(&$e); } }; } /// Floor (f64) /// /// Finds the nearest integer less than or equal to `x`. #[cfg(all(not(feature = "std"), feature = "floats"))] fn floord(x: f64) -> f64 { const TOINT: f64 = 1. / f64::EPSILON; let ui = x.to_bits(); let e = ((ui >> 52) & 0x7ff) as i32; if (e >= 0x3ff + 52) || (x == 0.) { return x; } /* y = int(x) - x, where int(x) is an integer neighbor of x */ let y = if (ui >> 63) != 0 { x - TOINT + TOINT - x } else { x + TOINT - TOINT - x }; /* special case because of non-nearest rounding modes */ if e < 0x3ff { volatile!(y); return if (ui >> 63) != 0 { -1. } else { 0. }; } if y > 0. { x + y - 1. } else { x + y } } /// Floor (f32) /// /// Finds the nearest integer less than or equal to `x`. #[cfg(all(not(feature = "std"), feature = "floats"))] fn floorf(x: f32) -> f32 { let mut ui = x.to_bits(); let e = (((ui >> 23) as i32) & 0xff) - 0x7f; if e >= 23 { return x; } if e >= 0 { let m: u32 = 0x007fffff >> e; if (ui & m) == 0 { return x; } volatile!(x + f32::from_bits(0x7b800000)); if ui >> 31 != 0 { ui += m; } ui &= !m; } else { volatile!(x + f32::from_bits(0x7b800000)); if ui >> 31 == 0 { ui = 0; } else if ui << 1 != 0 { return -1.0; } } f32::from_bits(ui) } /* origin: FreeBSD /usr/src/lib/msun/src/e_log.c */ /* * ==================================================== * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. * * Developed at SunSoft, a Sun Microsystems, Inc. business. * Permission to use, copy, modify, and distribute this * software is freely granted, provided that this notice * is preserved. * ==================================================== */ /* log(x) * Return the logarithm of x * * Method : * 1. Argument Reduction: find k and f such that * x = 2^k * (1+f), * where sqrt(2)/2 < 1+f < sqrt(2) . * * 2. Approximation of log(1+f). * Let s = f/(2+f) ; based on log(1+f) = log(1+s) - log(1-s) * = 2s + 2/3 s**3 + 2/5 s**5 + ....., * = 2s + s*R * We use a special Remez algorithm on [0,0.1716] to generate * a polynomial of degree 14 to approximate R The maximum error * of this polynomial approximation is bounded by 2**-58.45. In * other words, * 2 4 6 8 10 12 14 * R(z) ~ Lg1*s +Lg2*s +Lg3*s +Lg4*s +Lg5*s +Lg6*s +Lg7*s * (the values of Lg1 to Lg7 are listed in the program) * and * | 2 14 | -58.45 * | Lg1*s +...+Lg7*s - R(z) | <= 2 * | | * Note that 2s = f - s*f = f - hfsq + s*hfsq, where hfsq = f*f/2. * In order to guarantee error in log below 1ulp, we compute log * by * log(1+f) = f - s*(f - R) (if f is not too large) * log(1+f) = f - (hfsq - s*(hfsq+R)). (better accuracy) * * 3. Finally, log(x) = k*ln2 + log(1+f). * = k*ln2_hi+(f-(hfsq-(s*(hfsq+R)+k*ln2_lo))) * Here ln2 is split into two floating point number: * ln2_hi + ln2_lo, * where n*ln2_hi is always exact for |n| < 2000. * * Special cases: * log(x) is NaN with signal if x < 0 (including -INF) ; * log(+INF) is +INF; log(0) is -INF with signal; * log(NaN) is that NaN with no signal. * * Accuracy: * according to an error analysis, the error is always less than * 1 ulp (unit in the last place). * * Constants: * The hexadecimal values are the intended ones for the following * constants. The decimal values may be used, provided that the * compiler will convert from decimal to binary accurately enough * to produce the hexadecimal values shown. */ #[allow(clippy::eq_op, clippy::excessive_precision)] // reason="values need to be exact under all conditions" #[cfg(all(not(feature = "std"), feature = "floats"))] fn logd(mut x: f64) -> f64 { const LN2_HI: f64 = 6.93147180369123816490e-01; /* 3fe62e42 fee00000 */ const LN2_LO: f64 = 1.90821492927058770002e-10; /* 3dea39ef 35793c76 */ const LG1: f64 = 6.666666666666735130e-01; /* 3FE55555 55555593 */ const LG2: f64 = 3.999999999940941908e-01; /* 3FD99999 9997FA04 */ const LG3: f64 = 2.857142874366239149e-01; /* 3FD24924 94229359 */ const LG4: f64 = 2.222219843214978396e-01; /* 3FCC71C5 1D8E78AF */ const LG5: f64 = 1.818357216161805012e-01; /* 3FC74664 96CB03DE */ const LG6: f64 = 1.531383769920937332e-01; /* 3FC39A09 D078C69F */ const LG7: f64 = 1.479819860511658591e-01; /* 3FC2F112 DF3E5244 */ let x1p54 = f64::from_bits(0x4350000000000000); // 0x1p54 === 2 ^ 54 let mut ui = x.to_bits(); let mut hx: u32 = (ui >> 32) as u32; let mut k: i32 = 0; if (hx < 0x00100000) || ((hx >> 31) != 0) { /* x < 2**-126 */ if ui << 1 == 0 { return -1. / (x * x); /* log(+-0)=-inf */ } if hx >> 31 != 0 { return (x - x) / 0.0; /* log(-#) = NaN */ } /* subnormal number, scale x up */ k -= 54; x *= x1p54; ui = x.to_bits(); hx = (ui >> 32) as u32; } else if hx >= 0x7ff00000 { return x; } else if hx == 0x3ff00000 && ui << 32 == 0 { return 0.; } /* reduce x into [sqrt(2)/2, sqrt(2)] */ hx += 0x3ff00000 - 0x3fe6a09e; k += ((hx >> 20) as i32) - 0x3ff; hx = (hx & 0x000fffff) + 0x3fe6a09e; ui = ((hx as u64) << 32) | (ui & 0xffffffff); x = f64::from_bits(ui); let f: f64 = x - 1.0; let hfsq: f64 = 0.5 * f * f; let s: f64 = f / (2.0 + f); let z: f64 = s * s; let w: f64 = z * z; let t1: f64 = w * (LG2 + w * (LG4 + w * LG6)); let t2: f64 = z * (LG1 + w * (LG3 + w * (LG5 + w * LG7))); let r: f64 = t2 + t1; let dk: f64 = k as f64; s * (hfsq + r) + dk * LN2_LO - hfsq + f + dk * LN2_HI } /* origin: FreeBSD /usr/src/lib/msun/src/e_logf.c */ /* * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. */ /* * ==================================================== * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. * * Developed at SunPro, a Sun Microsystems, Inc. business. * Permission to use, copy, modify, and distribute this * software is freely granted, provided that this notice * is preserved. * ==================================================== */ #[allow(clippy::eq_op, clippy::excessive_precision)] // reason="values need to be exact under all conditions" #[cfg(all(not(feature = "std"), feature = "floats"))] fn logf(mut x: f32) -> f32 { const LN2_HI: f32 = 6.9313812256e-01; /* 0x3f317180 */ const LN2_LO: f32 = 9.0580006145e-06; /* 0x3717f7d1 */ /* |(log(1+s)-log(1-s))/s - Lg(s)| < 2**-34.24 (~[-4.95e-11, 4.97e-11]). */ const LG1: f32 = 0.66666662693; /* 0xaaaaaa.0p-24 */ const LG2: f32 = 0.40000972152; /* 0xccce13.0p-25 */ const LG3: f32 = 0.28498786688; /* 0x91e9ee.0p-25 */ const LG4: f32 = 0.24279078841; /* 0xf89e26.0p-26 */ let x1p25 = f32::from_bits(0x4c000000); // 0x1p25f === 2 ^ 25 let mut ix = x.to_bits(); let mut k = 0i32; if (ix < 0x00800000) || ((ix >> 31) != 0) { /* x < 2**-126 */ if ix << 1 == 0 { return -1. / (x * x); /* log(+-0)=-inf */ } if (ix >> 31) != 0 { return (x - x) / 0.; /* log(-#) = NaN */ } /* subnormal number, scale up x */ k -= 25; x *= x1p25; ix = x.to_bits(); } else if ix >= 0x7f800000 { return x; } else if ix == 0x3f800000 { return 0.; } /* reduce x into [sqrt(2)/2, sqrt(2)] */ ix += 0x3f800000 - 0x3f3504f3; k += ((ix >> 23) as i32) - 0x7f; ix = (ix & 0x007fffff) + 0x3f3504f3; x = f32::from_bits(ix); let f = x - 1.; let s = f / (2. + f); let z = s * s; let w = z * z; let t1 = w * (LG2 + w * LG4); let t2 = z * (LG1 + w * LG3); let r = t2 + t1; let hfsq = 0.5 * f * f; let dk = k as f32; s * (hfsq + r) + dk * LN2_LO - hfsq + f + dk * LN2_HI } lexical-util-1.0.6/src/numtypes.rs000064400000000000000000000030151046102023000152440ustar 00000000000000//! Utilties for defining custom numeric types. //! //! This defines primarily macros intended to be used when //! defining your own types. #![cfg(feature = "f16")] #![doc(hidden)] /// Implement the reference and op assign variants of a trait. macro_rules! op_impl { ($t:ty, $trait:ident, $assign:ident, $op:ident, $op_assign:ident) => { impl $trait<&$t> for $t { type Output = ::Output; #[inline(always)] fn $op(self, rhs: &Self) -> Self::Output { self.$op(*rhs) } } impl $assign for $t { #[inline(always)] fn $op_assign(&mut self, other: Self) { *self = self.$op(other); } } impl $assign<&$t> for $t { #[inline(always)] fn $op_assign(&mut self, other: &Self) { *self = self.$op(other); } } }; } pub(crate) use op_impl; macro_rules! ref_impl { ($t:ty, $trait:ident, $op:ident) => { impl $trait for &$t { type Output = <$t as $trait>::Output; #[inline(always)] fn $op(self) -> Self::Output { $trait::$op(*self) } } }; } pub(crate) use ref_impl; macro_rules! from_impl { ($to:ty, $from:ty, $op:ident) => { impl From<$from> for $to { #[inline(always)] fn from(value: $from) -> Self { Self::$op(value) } } }; } pub(crate) use from_impl; lexical-util-1.0.6/src/options.rs000064400000000000000000000107141046102023000150570ustar 00000000000000//! Shared traits for the options API. #[cfg(feature = "write")] use crate::constants::FormattedSize; // TRAITS // ------ /// Shared trait for all writer options. #[cfg(feature = "write")] pub trait WriteOptions: Default { /// Determine if the options are valid. fn is_valid(&self) -> bool; /// Get an upper bound on the buffer size. fn buffer_size(&self) -> usize; } /// Shared trait for all parser options. #[cfg(feature = "parse")] pub trait ParseOptions: Default { /// Determine if the options are valid. fn is_valid(&self) -> bool; } // PRE-DEFINED CONSTANTS // --------------------- // The following constants have the following signifiers: // ${X}_LITERAL - Applies to all literal values for that language. // ${X}_STRING - Applies to all string values for that language. // ${X} - Applies to all values for that language. // ${X}_(NAN|INF|INFINITY) - Applies to only a single special value. // IF it's not defined, all values are the default. macro_rules! literal { ($name:ident, $value:ident) => { pub const $name: Option<&[u8]> = $value; }; ($name:ident, $value:literal) => { pub const $name: Option<&[u8]> = Some($value); }; } literal!(RUST_LITERAL, None); // RUST_STRING literal!(PYTHON_LITERAL, None); // PYTHON_STRING literal!(CXX_LITERAL_NAN, b"NAN"); literal!(CXX_LITERAL_INF, b"INFINITY"); literal!(CXX_LITERAL_INFINITY, b"INFINITY"); // CXX_STRING literal!(C_LITERAL_NAN, b"NAN"); literal!(C_LITERAL_INF, b"INFINITY"); literal!(C_LITERAL_INFINITY, b"INFINITY"); // RUBY_LITERAL literal!(RUBY_LITERAL_NAN, b"NaN"); literal!(RUBY_LITERAL_INF, b"Infinity"); literal!(RUBY_STRING_NONE, None); // C_STRING literal!(SWIFT_LITERAL, None); // SWIFT_STRING literal!(GO_LITERAL, None); // GO_STRING literal!(HASKELL_LITERAL, None); literal!(HASKELL_STRING_INF, b"Infinity"); literal!(HASKELL_STRING_INFINITY, b"Infinity"); literal!(JAVASCRIPT_INF, b"Infinity"); literal!(JAVASCRIPT_INFINITY, b"Infinity"); literal!(PERL_LITERAL, None); // PERL_STRING literal!(PHP_LITERAL_NAN, b"NAN"); literal!(PHP_LITERAL_INF, b"INF"); literal!(PHP_LITERAL_INFINITY, b"INF"); // PHP_STRING literal!(JAVA_LITERAL, None); literal!(JAVA_STRING_INF, b"Infinity"); literal!(JAVA_STRING_INFINITY, b"Infinity"); literal!(R_LITERAL_INF, b"Inf"); literal!(R_LITERAL_INFINITY, b"Inf"); // R_STRING literal!(KOTLIN_LITERAL, None); literal!(KOTLIN_STRING_INF, b"Infinity"); literal!(KOTLIN_STRING_INFINITY, b"Infinity"); literal!(JULIA_LITERAL_INF, b"Inf"); literal!(JULIA_LITERAL_INFINITY, b"Inf"); // JULIA_STRING literal!(CSHARP_LITERAL, None); literal!(CSHARP_STRING_INF, b"Infinity"); literal!(CSHARP_STRING_INFINITY, b"Infinity"); literal!(KAWA, None); literal!(GAMBITC, None); literal!(GUILE, None); literal!(CLOJURE_LITERAL, None); literal!(CLOJURE_STRING_INF, b"Infinity"); literal!(CLOJURE_STRING_INFINITY, b"Infinity"); literal!(ERLANG_LITERAL_NAN, b"nan"); literal!(ERLANG_STRING, None); literal!(ELM_LITERAL, None); literal!(ELM_STRING_NAN, None); literal!(ELM_STRING_INF, b"Infinity"); literal!(ELM_STRING_INFINITY, b"Infinity"); literal!(SCALA_LITERAL, None); literal!(SCALA_STRING_INF, b"Infinity"); literal!(SCALA_STRING_INFINITY, b"Infinity"); literal!(ELIXIR, None); literal!(FORTRAN_LITERAL, None); // FORTRAN_STRING literal!(D_LITERAL, None); // D_STRING literal!(COFFEESCRIPT_INF, b"Infinity"); literal!(COFFEESCRIPT_INFINITY, b"Infinity"); literal!(COBOL, None); literal!(FSHARP_LITERAL_NAN, b"nan"); literal!(FSHARP_LITERAL_INF, b"infinity"); literal!(FSHARP_LITERAL_INFINITY, b"infinity"); // FSHARP_STRING literal!(VB_LITERAL, None); literal!(VB_STRING_INF, None); literal!(VB_STRING_INFINITY, None); literal!(OCAML_LITERAL_NAN, b"nan"); literal!(OCAML_LITERAL_INF, b"infinity"); literal!(OCAML_LITERAL_INFINITY, b"infinity"); // OCAML_STRING literal!(OBJECTIVEC, None); literal!(REASONML_LITERAL_NAN, b"nan"); literal!(REASONML_LITERAL_INF, b"infinity"); literal!(REASONML_LITERAL_INFINITY, b"infinity"); // REASONML_STRING literal!(MATLAB_LITERAL_INF, b"inf"); literal!(MATLAB_LITERAL_INFINITY, b"Inf"); // MATLAB_STRING literal!(ZIG_LITERAL, None); // ZIG_STRING literal!(SAGE_LITERAL_INF, b"infinity"); literal!(SAGE_LITERAL_INFINITY, b"Infinity"); // SAGE_STRING literal!(JSON, None); literal!(TOML, None); literal!(YAML, None); literal!(XML_INF, None); literal!(XML_INFINITY, None); literal!(SQLITE, None); literal!(POSTGRESQL, None); literal!(MYSQL, None); literal!(MONGODB_INF, b"Infinity"); literal!(MONGODB_INFINITY, b"Infinity"); lexical-util-1.0.6/src/result.rs000064400000000000000000000003021046102023000146720ustar 00000000000000//! Result type for numeric parsing functions. use core::result; use crate::error; /// A specialized Result type for lexical operations. pub type Result = result::Result; lexical-util-1.0.6/src/skip.rs000064400000000000000000001416221046102023000143350ustar 00000000000000//! An iterator that skips values equal to a provided value. //! //! Iterators over a contiguous slice, returning all values //! except for those matching the provided skip value. //! //! # Complexity //! //! Although superficially quite simple, the level of complexity //! introduced by digit separators can be quite complex, due //! the number of permutations during parsing. //! //! We can consume any combinations of of \[0,3\] items from the following set: //! - \[l\]eading digit separators, where digit separators occur before //! digits. //! - \[i\]nternal digit separators, where digit separators occur between //! digits. //! - \[t\]railing digit separators, where digit separators occur after //! digits. //! //! In addition to those combinations, we can also have: //! - \[c\]onsecutive digit separators, which allows two digit separators to //! be adjacent. //! //! # Shorthand //! //! We will use the term consumer to denote a function that consumes digits, //! splitting an input buffer at an index, where the leading section contains //! valid input digits, and the trailing section contains invalid characters. //! Due to the number of combinations for consumers, we use the following //! shorthand to denote consumers: //! - `no`, does not use a digit separator. //! - `l`, consumes leading digit separators. //! - `i`, consumes internal digit separators. //! - `t`, consumes trailing digit separators. //! - `c`, consumes consecutive digit separators. //! //! The `next`/`iter` algorithms are therefore named `next_x`, where `x` //! represents the shorthand name of the consumer, in sorted order. //! For example, `next_ilt` means that consumer can skip internal, //! leading, and trailing digit separators, but not consecutive ones. #![cfg(all(feature = "format", feature = "parse"))] use core::{mem, ptr}; use crate::digit::char_is_digit_const; use crate::format::NumberFormat; use crate::format_flags as flags; use crate::iterator::{DigitsIter, Iter}; // IS_ILTC // ------- // NOTE: The compiler optimizes all these methods pretty well: it's as // efficient or almost as efficient as optimized assembly without unsafe // code, especially since we have to do bounds checking // before and the compiler can determine all cases correctly. /// Helpers to get the next or previous elements for checks. /// /// This has the non-consecutive iterator variants as well /// as the consecutive ones. The consecutive ones will iteratively /// process all digits. macro_rules! indexing { (@next $self:ident, $index:expr) => { $index.wrapping_add(1) }; (@nextc $self:ident, $index:expr) => {{ let mut index = $index; let slc = $self.byte.slc; while slc.get(index.wrapping_add(1)).map_or(false, |&x| $self.is_digit_separator(x)) { index = index.wrapping_add(1); } index.wrapping_add(1) }}; (@prev $self:ident, $index:expr) => { $index.wrapping_sub(1) }; (@prevc $self:ident, $index:expr) => {{ let mut index = $index; let slc = $self.byte.slc; while slc.get(index.wrapping_sub(1)).map_or(false, |&x| $self.is_digit_separator(x)) { index = index.wrapping_sub(1); } index.wrapping_sub(1) }}; } /// Determine if a single digit separator is internal. /// /// # Examples /// /// - `1__1_23`- invalid /// - `1_1__23`- invalid /// - `1_1_23`- valid /// - `11_x23`- invalid /// - `_1123`- invalid /// - `+_1123`- invalid /// - `_+1123`- invalid /// - `1123_`- invalid /// - `1123_.`- invalid /// - `112_3.`- valid /// /// # Preconditions /// /// Assumes `slc[index]` is a digit separator. macro_rules! is_i { (@first $self:ident, $index:expr) => {{ // NOTE: The conditions here then are that: // - `index - 1` is a digit // - `index + 1` is a digit let prev = indexing!(@prev $self, $index); let next = indexing!(@next $self, $index); let slc = $self.byte.slc; slc.get(prev).map_or(false, |&x| $self.is_digit(x)) && slc.get(next).map_or(false, |&x| $self.is_digit(x)) }}; (@first $self:ident) => { is_i!(@first $self, $self.byte.index) }; (@internal $self:ident, $index:expr) => {{ // NOTE: We must have validated `prev`, so this just checks `next`. // NOTE: The conditions here then are that: // - `index + 1` is a digit let next = indexing!(@next $self, $index); let slc = $self.byte.slc; slc.get(next).map_or(false, |&x| $self.is_digit(x)) }}; (@internal $self:ident) => { is_i!(@internal $self, $self.byte.index) }; } /// Determine if consecutive digit separators are internal. /// /// # Examples /// /// - `1__1_23`- valid /// - `1_1__23`- valid /// - `1_1_23`- valid /// - `11_x23`- invalid /// - `_1123`- invalid /// - `+_1123`- invalid /// - `_+1123`- invalid /// - `1123_`- invalid /// - `1123_.`- invalid /// - `112_3.`- valid /// /// # Preconditions /// /// Assumes `slc[index]` is a digit separator. macro_rules! is_ic { (@first $self:ident, $index:expr) => {{ // NOTE: The conditions here then are that: // - `index - 1` is a digit after consuming digit separators // - `index + 1` is a digit after consuming digit separators let prev = indexing!(@prevc $self, $index); let next = indexing!(@nextc $self, $index); let slc = $self.byte.slc; slc.get(prev).map_or(false, |&x| $self.is_digit(x)) && slc.get(next).map_or(false, |&x| $self.is_digit(x)) }}; (@first $self:ident) => { is_ic!(@first $self, $self.byte.index) }; (@internal $self:ident, $index:expr) => {{ // NOTE: We must have validated `prev`, so this just checks `next`. // NOTE: The conditions here then are that: // - `index + 1` is a digit after consuming digit separators let next = indexing!(@nextc $self, $index); let slc = $self.byte.slc; slc.get(next).map_or(false, |&x| $self.is_digit(x)) }}; (@internal $self:ident) => { is_ic!(@internal $self, $self.byte.index) }; } /// Determine if a single digit separator is leading. /// /// # Examples /// /// - `__123`- invalid /// - `+__123`- invalid /// - `._123`- valid /// - `_+123`- valid /// - `_123`- valid /// - `+_123`- valid /// /// Having a subsequent sign character is fine since it might /// be part of a partial parser. /// /// # Preconditions /// /// Assumes `slc[index]` is a digit separator. macro_rules! is_l { (@first $self:ident, $index:expr) => {{ // NOTE: The conditions here then are that: // - `index - 1` is not a digit // - `index - 1` is not a digit separator // - `index + 1` is not a digit separator let prev = indexing!(@prev $self, $index); let next = indexing!(@next $self, $index); let slc = $self.byte.slc; slc.get(prev).map_or(true, |&x| !$self.is_digit(x) && !$self.is_digit_separator(x)) && slc.get(next).map_or(true, |&x| !$self.is_digit_separator(x)) }}; (@first $self:ident) => { is_l!(@first $self, $self.byte.index) }; (@internal $self:ident, $index:expr) => {{ // NOTE: Previous must have been a digit so this cannot be valid. false }}; (@internal $self:ident) => { is_l!(@internal $self, $self.byte.index) }; } /// Determine if one or more digit separators are leading. /// /// # Examples /// /// - `__123`- valid /// - `+__123`- valid /// - `+__+123`- valid /// - `+__.123`- valid /// - `._123`- valid /// - `_+123`- invalid /// - `_123`- valid /// - `+_123`- valid /// /// Having a subsequent sign character is fine since it might /// be part of a partial parser. /// /// # Preconditions /// /// Assumes `slc[index]` is a digit separator. macro_rules! is_lc { (@first $self:ident, $index:expr) => {{ // NOTE: The conditions here then are that: // - `index - 1` is not a digit after removing digit separators let prev = indexing!(@prevc $self, $index); let slc = $self.byte.slc; slc.get(prev).map_or(true, |&x| !$self.is_digit(x)) }}; (@first $self:ident) => { is_lc!(@first $self, $self.byte.index) }; (@internal $self:ident, $index:expr) => {{ // NOTE: Previous must have been a digit so this cannot be valid. false }}; (@internal $self:ident) => { is_lc!(@internal $self, $self.byte.index) }; } /// Determine if a single digit separator is trailing. /// /// # Examples /// /// - `123_`- valid /// - `123__`- invalid /// - `123_.`- valid /// - `123__.`- invalid /// - `123_1`- invalid /// - `123__1`- invalid /// - _: valid /// - _+: valid /// - 1_+: valid /// /// Having a subsequent sign character is fine since it might /// be part of a partial parser. /// /// # Preconditions /// /// Assumes `slc[index]` is a digit separator. macro_rules! is_t { (@first $self:ident, $index:expr) => {{ // NOTE: The conditions here then are that: // - `index + 1` is not a digit // - `index + 1` is not a digit separator // - `index - 1` is not a digit separator let prev = indexing!(@prev $self, $index); let next = indexing!(@next $self, $index); let slc = $self.byte.slc; slc.get(next).map_or(true, |&x| !$self.is_digit(x) && !$self.is_digit_separator(x)) && slc.get(prev).map_or(true, |&x| !$self.is_digit_separator(x)) }}; (@first $self:ident) => { is_t!(@first $self, $self.byte.index) }; (@internal $self:ident, $index:expr) => {{ // NOTE: We must have validated `prev`, so this just checks `next`. // NOTE: The conditions here then are that: // - `index + 1` is not a digit // - `index + 1` is not a digit separator let next = indexing!(@next $self, $index); let slc = $self.byte.slc; slc.get(next).map_or(true, |&x| !$self.is_digit(x) && !$self.is_digit_separator(x)) }}; (@internal $self:ident) => { is_t!(@internal $self, $self.byte.index) }; } /// Determine if one or more digit separators are trailing. /// /// # Examples /// /// - `123_`- valid /// - `123__`- valid /// - `123_.`- valid /// - `123__.`- valid /// - `123_1`- invalid /// - `123__1`- invalid /// /// # Preconditions /// /// Assumes `slc[index]` is a digit separator. macro_rules! is_tc { (@first $self:ident, $index:expr) => {{ // NOTE: The conditions here then are that: // - `index + 1` is not a digit let next = indexing!(@nextc $self, $index); let slc = $self.byte.slc; slc.get(next).map_or(true, |&x| !$self.is_digit(x)) }}; (@first $self:ident) => { is_tc!(@first $self, $self.byte.index) }; (@internal $self:ident, $index:expr) => { // NOTE: This is already optimized for the first case. is_tc!(@first $self, $index) }; (@internal $self:ident) => { is_tc!(@internal $self, $self.byte.index) }; } /// Determine if the digit separator is leading or internal. /// /// # Examples /// /// - `__123`- invalid /// - `+__123`- invalid /// - `._123`- valid /// - `_+123`- valid /// - `_123`- valid /// - `+_123`- valid /// - `+1_23`- valid /// - `+1__23`- invalid /// - `+123_`- invalid /// - `+123__`- invalid /// - _: valid /// - _+: valid /// - 1_+: invalid /// /// # Preconditions /// /// Assumes `slc[index]` is a digit separator. macro_rules! is_il { (@first $self:ident, $index:expr) => {{ // NOTE: The conditions here then are that: // - `index + 1` is a digit // - `index + 1` is not a digit separator // - `index - 1` is not a digit separator // // # Logic // // If the previous character is a digit, then the // next character must be a digit. If the previous // character is not a digit, then the subsequent character can // be anything besides a digit separator let prev = indexing!(@prev $self, $index); let next = indexing!(@next $self, $index); let slc = $self.byte.slc; if slc.get(prev).map_or(false, |&x| $self.is_digit(x)) { slc.get(next).map_or(false, |&x| $self.is_digit(x)) } else { slc.get(prev).map_or(true, |&x| !$self.is_digit_separator(x)) } }}; (@first $self:ident) => { is_il!(@first $self, $self.byte.index) }; (@internal $self:ident, $index:expr) => {{ // NOTE: We must have validated `prev`, so this just checks `next`. // NOTE: The conditions here then are that: // - `index + 1` is a digit let next = indexing!(@next $self, $index); let slc = $self.byte.slc; slc.get(next).map_or(false, |&x| $self.is_digit(x)) }}; (@internal $self:ident) => { is_il!(@internal $self, $self.byte.index) }; } /// Determine if consecutive digit separators are leading or internal. /// /// # Examples /// /// - `__123`- valid /// - `+__123`- valid /// - `._123`- valid /// - `_+123`- valid /// - `_123`- valid /// - `+_123`- valid /// - `+1_23`- valid /// - `+1__23`- valid /// - `+123_`- invalid /// - `+123__`- invalid /// - _: valid /// - _+: valid /// - 1_+: invalid /// /// # Preconditions /// /// Assumes `slc[index]` is a digit separator. macro_rules! is_ilc { (@first $self:ident, $index:expr) => {{ // NOTE: The conditions here then are that: // - `index + 1` is a digit after consuming digit separators // // # Logic // // We also need to consider the case where it's empty, // that is, the previous one wasn't a digit if we don't // have a digit. let prev = indexing!(@prevc $self, $index); let next = indexing!(@nextc $self, $index); let slc = $self.byte.slc; slc.get(next).map_or(false, |&x| $self.is_digit(x)) || slc.get(prev).map_or(true, |&x| !$self.is_digit(x)) }}; (@first $self:ident) => { is_ilc!(@first $self, $self.byte.index) }; (@internal $self:ident, $index:expr) => {{ // NOTE: The conditions here then are that: // - `index + 1` is a digit after consuming digit separators let next = indexing!(@nextc $self, $index); let slc = $self.byte.slc; slc.get(next).map_or(true, |&x| $self.is_digit(x)) }}; (@internal $self:ident) => { is_ilc!(@internal $self, $self.byte.index) }; } /// Determine if the digit separator is internal or trailing. /// /// # Examples /// /// - `__123`- valid /// - `+__123`- valid /// - `._123`- valid /// - `_+123`- valid /// - `_123`- valid /// - `+_123`- valid /// - `+1_23`- valid /// - `+1__23`- valid /// - `+123_`- invalid /// - `+123__`- invalid /// - _: valid /// - _+: valid /// - 1_+: invalid /// /// # Preconditions /// /// Assumes `slc[index]` is a digit separator. macro_rules! is_it { (@first$self:ident, $index:expr) => {{ // NOTE: The conditions here then are that: // - `index - 1` is a digit // - `index - 1` is not a digit separator // - `index + 1` is not a digit separator // // # Logic // // If the previous character is not a digit, there cannot // be a digit for a following character. If the previous // character is a digit, then the following one must be // a digit as well. let prev = indexing!(@prev $self, $index); let next = indexing!(@next $self, $index); let slc = $self.byte.slc; if slc.get(prev).map_or(false, |&x| $self.is_digit(x)) { // Have a digit, any character besides a digit separator is valid slc.get(next).map_or(true, |&x| !$self.is_digit_separator(x)) } else { // Not a digit, so we cannot have a digit or a digit separator slc.get(next).map_or(true, |&x| !$self.is_digit(x) && !$self.is_digit_separator(x)) } }}; (@first$self:ident) => { is_it!(@first $self, $self.byte.index) }; (@internal $self:ident, $index:expr) => {{ // NOTE: We must have validated `prev`, so this just checks `next`. // NOTE: The conditions here then are that: // - `index + 1` is not a digit separator // Since we've previously had a digit, this is guaranteed to // be internal or trailing. let next = indexing!(@next $self, $index); let slc = $self.byte.slc; slc.get(next).map_or(true, |&x| !$self.is_digit_separator(x)) }}; (@internal $self:ident) => { is_it!(@internal $self, $self.byte.index) }; } /// Determine if consecutive digit separators are internal or trailing. /// /// # Examples /// /// - `__123`- invalid /// - `+__123`- invalid /// - `._123`- invalid /// - `_+123`- invalid /// - `_123`- invalid /// - `+_123`- invalid /// - `+1_23`- valid /// - `+1__23`- valid /// - `+123_`- valid /// - `+123__`- valid /// - _: valid /// - _+: valid /// - 1_+: valid /// /// # Preconditions /// /// Assumes `slc[index]` is a digit separator. macro_rules! is_itc { (@first $self:ident, $index:expr) => {{ // NOTE: The conditions here then are that: // - `index - 1` is not a digit after consuming digit separators // // # Logic // // We also need to consider the case where it's empty, // that is, the previous one wasn't a digit if we don't // have a digit. let prev = indexing!(@prevc $self, $index); let next = indexing!(@nextc $self, $index); let slc = $self.byte.slc; slc.get(prev).map_or(false, |&x| !$self.is_digit(x)) || slc.get(next).map_or(true, |&x| !$self.is_digit(x)) }}; (@first $self:ident) => { is_itc!(@first $self, $self.byte.index) }; (@internal $self:ident, $index:expr) => { // NOTE: Previous must have been a digit so this must be valid. true }; (@internal $self:ident) => { is_itc!(@internal $self, $self.byte.index) }; } /// Determine if the digit separator is leading or trailing. /// /// # Examples /// /// - `__123`- invalid /// - `+__123`- invalid /// - `._123`- valid /// - `_+123`- valid /// - `_123`- valid /// - `+_123`- valid /// - `+1_23`- invalid /// - `+1__23`- invalid /// - `+123_`- valid /// - `+123__`- invalid /// - _: valid /// - _+: valid /// - 1_+: valid /// /// # Preconditions /// /// Assumes `slc[index]` is a digit separator. macro_rules! is_lt { (@first $self:ident, $index:expr) => {{ // NOTE: The conditions here then are that: // - not (`index - 1` is a digit and `index + 1` is a digit) // - `index - 1` is not a digit separator // - `index + 1` is not a digit separator let prev = indexing!(@prev $self, $index); let next = indexing!(@next $self, $index); let slc = $self.byte.slc; let prev_value = slc.get(prev); let next_value = slc.get(next); let is_prev_sep = prev_value.map_or(false, |&x| $self.is_digit_separator(x)); let is_prev_dig = prev_value.map_or(false, |&x| $self.is_digit(x)); let is_next_sep = next_value.map_or(false, |&x| $self.is_digit_separator(x)); let is_next_dig = next_value.map_or(false, |&x| $self.is_digit(x)); !is_prev_sep && !is_next_sep && !(is_prev_dig && is_next_dig) }}; (@first $self:ident) => { is_lt!(@first $self, $self.byte.index) }; (@internal $self:ident, $index:expr) => {{ // NOTE: We must have validated `prev`, so this just checks `next`. // NOTE: The conditions here then are that: // - `index + 1` is not a digit // - `index + 1` is not a digit separator let next = indexing!(@next $self, $index); let slc = $self.byte.slc; slc.get(next).map_or(true, |&x| !$self.is_digit(x) && !$self.is_digit_separator(x)) }}; (@internal $self:ident) => { is_lt!(@internal $self, $self.byte.index) }; } /// Determine if consecutive digit separators are leading or trailing. /// /// # Examples /// /// - `__123`- valid /// - `+__123`- valid /// - `._123`- valid /// - `_+123`- valid /// - `_123`- valid /// - `+_123`- valid /// - `+1_23`- invalid /// - `+1__23`- invalid /// - `+123_`- valid /// - `+123__`- valid /// - _: valid /// - _+: valid /// - 1_+: valid /// /// # Preconditions /// /// Assumes `slc[index]` is a digit separator. macro_rules! is_ltc { (@first $self:ident, $index:expr) => {{ // NOTE: The conditions here then are that (after consuming separators): // - not (`index - 1` is a digit and `index + 1` is a digit) let prev = indexing!(@prevc $self, $index); let next = indexing!(@nextc $self, $index); let slc = $self.byte.slc; !(slc.get(prev).map_or(false, |&x| $self.is_digit(x)) && slc.get(next).map_or(false, |&x| $self.is_digit(x))) }}; (@first $self:ident) => { is_ltc!(@first $self, $self.byte.index) }; (@internal $self:ident, $index:expr) => {{ // NOTE: We must have validated `prev`, so this just checks `next`. // NOTE: The conditions here then are that: // - `index + 1` is not a digit let next = indexing!(@nextc $self, $index); let slc = $self.byte.slc; slc.get(next).map_or(true, |&x| !$self.is_digit(x)) }}; (@internal $self:ident) => { is_ltc!(@internal $self, $self.byte.index) }; } /// Determine if a single digit separator is internal, leading, or trailing. /// /// # Examples /// /// - `__123`- invalid /// - `+__123`- invalid /// - `._123`- valid /// - `_+123`- valid /// - `_123`- valid /// - `+_123`- valid /// - `+1_23`- valid /// - `+1__23`- invalid /// - `+123_`- valid /// - `+123__`- invalid /// - _: valid /// - _+: valid /// - 1_+: valid /// /// # Preconditions /// /// Assumes `slc[index]` is a digit separator. macro_rules! is_ilt { (@first $self:ident, $index:expr) => {{ // NOTE: The conditions here then are that: // - `index + 1` is not a digit separator // - `index - 1` is not a digit separator let prev = indexing!(@prev $self, $index); let next = indexing!(@next $self, $index); let slc = $self.byte.slc; !slc.get(next).map_or(false, |&x| $self.is_digit_separator(x)) && !slc.get(prev).map_or(false, |&x| $self.is_digit_separator(x)) }}; (@first $self:ident) => { is_ilt!(@first $self, $self.byte.index) }; (@internal $self:ident, $index:expr) => {{ // NOTE: We must have validated `prev`, so this just checks `next`. // NOTE: The conditions here then are that: // - `index + 1` is not a digit separator let next = indexing!(@next $self, $index); let slc = $self.byte.slc; slc.get(next).map_or(true, |&x| !$self.is_digit_separator(x)) }}; (@internal $self:ident) => { is_ilt!(@internal $self, $self.byte.index) }; } /// Determine if consecutive digit separators are internal, leading, or /// trailing. /// /// This is always true. /// /// # Examples /// /// - `__123`- valid /// - `+__123`- valid /// - `._123`- valid /// - `_+123`- valid /// - `_123`- valid /// - `+_123`- valid /// - `+1_23`- valid /// - `+1__23`- valid /// - `+123_`- valid /// - `+123__`- valid /// - _: valid /// - _+: valid /// - 1_+: valid /// /// # Preconditions /// /// Assumes `slc[index]` is a digit separator. macro_rules! is_iltc { (@first $self:ident, $index:expr) => { true }; (@first $self:ident) => { is_iltc!(@first $self, $self.byte.index) }; (@internal $self:ident, $index:expr) => { true }; (@internal $self:ident) => { is_iltc!(@internal $self, $self.byte.index) }; } // PEEK // ---- /// Consumes 1 or more digit separators. /// Peeks the next token that's not a digit separator. macro_rules! peek_1 { ($self:ident, $is_skip:ident) => {{ // This will consume a single, non-consecutive digit separators. let index = $self.cursor(); let buffer = $self.get_buffer(); let value = buffer.get(index)?; let is_digit_separator = $self.is_digit_separator(*value); // NOTE: We can do some pretty major optimizations for internal values, // since we can check the location and don't need to check previous values. if is_digit_separator { // NOTE: This cannot iteratively search for the next value, // or else the consecutive digit separator has no effect (#96). let is_skip = if $self.current_count() == 0 { $is_skip!(@first $self) } else { $is_skip!(@internal $self) }; if is_skip { // SAFETY: Safe since `index < buffer.len()`, so `index + 1 <= buffer.len()`` unsafe { $self.set_cursor(index + 1) }; buffer.get(index + 1) } else { Some(value) } } else { // Have 1 of 2 conditions: // 1. A non-digit separator character. // 2. A digit separator that is not valid in the context. Some(value) } }}; } /// Consumes 1 or more digit separators. /// Peeks the next token that's not a digit separator. macro_rules! peek_n { ($self:ident, $is_skip:ident) => {{ // This will consume consecutive digit separators. let mut index = $self.cursor(); let buffer = $self.get_buffer(); let value = buffer.get(index)?; let is_digit_separator = $self.is_digit_separator(*value); // NOTE: We can do some pretty major optimizations for internal values, // since we can check the location and don't need to check previous values. if is_digit_separator { let is_skip = if $self.current_count() == 0 { $is_skip!(@first $self) } else { $is_skip!(@internal $self) }; if is_skip { // Have a skippable digit separator: keep incrementing until we find // a non-digit separator character. Don't need any complex checks // here, since we've already done them above. index += 1; while index < buffer.len() && buffer.get(index).map_or(false, |&x| $self.is_digit_separator(x)) { index += 1; } // SAFETY: Safe since `index <= buffer.len()`. unsafe { $self.set_cursor(index) }; buffer.get(index) } else { Some(value) } } else { // Have 1 of 2 conditions: // 1. A non-digit separator character. // 2. A digit separator that is not valid in the context. Some(value) } }}; } /// Consumes no digit separators and peeks the next value. macro_rules! peek_noskip { ($self:ident) => { $self.byte.slc.get($self.byte.index) }; } /// Consumes at most 1 leading digit separator and peeks the next value. macro_rules! peek_l { ($self:ident) => { peek_1!($self, is_l) }; } /// Consumes at most 1 internal digit separator and peeks the next value. macro_rules! peek_i { ($self:ident) => { peek_1!($self, is_i) }; } /// Consumes at most 1 trailing digit separator and peeks the next value. macro_rules! peek_t { ($self:ident) => { peek_1!($self, is_t) }; } /// Consumes at most 1 internal/leading digit separator and peeks the next /// value. macro_rules! peek_il { ($self:ident) => { peek_1!($self, is_il) }; } /// Consumes at most 1 internal/trailing digit separator and peeks the next /// value. macro_rules! peek_it { ($self:ident) => { peek_1!($self, is_it) }; } /// Consumes at most 1 leading/trailing digit separator and peeks the next /// value. macro_rules! peek_lt { ($self:ident) => { peek_1!($self, is_lt) }; } /// Consumes at most 1 digit separator and peeks the next value. macro_rules! peek_ilt { ($self:ident) => { peek_1!($self, is_ilt) }; } /// Consumes 1 or more leading digit separators and peeks the next value. macro_rules! peek_lc { ($self:ident) => { peek_n!($self, is_lc) }; } /// Consumes 1 or more internal digit separators and peeks the next value. macro_rules! peek_ic { ($self:ident) => { peek_n!($self, is_ic) }; } /// Consumes 1 or more trailing digit separators and peeks the next value. macro_rules! peek_tc { ($self:ident) => { peek_n!($self, is_tc) }; } /// Consumes 1 or more internal/leading digit separators and peeks the next /// value. macro_rules! peek_ilc { ($self:ident) => { peek_n!($self, is_ilc) }; } /// Consumes 1 or more internal/trailing digit separators and peeks the next /// value. macro_rules! peek_itc { ($self:ident) => { peek_n!($self, is_itc) }; } /// Consumes 1 or more leading/trailing digit separators and peeks the next /// value. macro_rules! peek_ltc { ($self:ident) => { peek_n!($self, is_ltc) }; } /// Consumes 1 or more digit separators and peeks the next value. macro_rules! peek_iltc { ($self:ident) => { peek_n!($self, is_iltc) }; } // AS DIGITS // --------- /// Trait to simplify creation of a `Bytes` object. pub trait AsBytes<'a> { /// Create `Bytes` from object. fn bytes(&'a self) -> Bytes<'a, FORMAT>; } impl<'a> AsBytes<'a> for [u8] { #[inline(always)] fn bytes(&'a self) -> Bytes<'a, FORMAT> { Bytes::new(self) } } // DIGITS // ------ /// Slice iterator that skips characters matching a given value. /// /// This wraps an iterator over a contiguous block of memory, /// and only returns values that are not equal to skip. /// /// The format allows us to dictate the actual behavior of /// the iterator: in what contexts does it skip digit separators. /// /// `FORMAT` is required to tell us what the digit separator is, and where /// the digit separators are allowed, as well tell us the radix. /// The radix is required to allow us to differentiate digit from /// non-digit characters (see [`DigitSeparators`](/docs/DigitSeparators.md) /// for a detailed explanation on why). #[derive(Clone)] pub struct Bytes<'a, const FORMAT: u128> { /// The raw slice for the iterator. slc: &'a [u8], /// Current index of the iterator in the slice. index: usize, /// The current count of integer digits returned by the iterator. /// This is only used if the iterator is not contiguous. integer_count: usize, /// The current count of fraction digits returned by the iterator. /// This is only used if the iterator is not contiguous. fraction_count: usize, /// The current count of exponent digits returned by the iterator. /// This is only used if the iterator is not contiguous. exponent_count: usize, } impl<'a, const FORMAT: u128> Bytes<'a, FORMAT> { /// Create new byte object. #[inline(always)] pub const fn new(slc: &'a [u8]) -> Self { Self { slc, index: 0, integer_count: 0, fraction_count: 0, exponent_count: 0, } } /// Initialize the slice from raw parts. /// /// # Safety /// This is safe if and only if the index is <= `slc.len()`. /// For this reason, since it's easy to get wrong, we only /// expose it to our `DigitsIterator`s and nothing else. /// /// This is only ever used for contiguous iterators. However, /// it's not guaranteed to only valid for our contiguous /// iterators. #[inline(always)] const unsafe fn from_parts(slc: &'a [u8], index: usize) -> Self { debug_assert!(index <= slc.len()); Self { slc, index, integer_count: 0, fraction_count: 0, exponent_count: 0, } } /// Get iterator over integer digits. #[inline(always)] pub fn integer_iter<'b>(&'b mut self) -> IntegerDigitsIterator<'a, 'b, FORMAT> { IntegerDigitsIterator { byte: self, } } /// Get iterator over fraction digits. #[inline(always)] pub fn fraction_iter<'b>(&'b mut self) -> FractionDigitsIterator<'a, 'b, FORMAT> { FractionDigitsIterator { byte: self, } } /// Get iterator over exponent digits. #[inline(always)] pub fn exponent_iter<'b>(&'b mut self) -> ExponentDigitsIterator<'a, 'b, FORMAT> { ExponentDigitsIterator { byte: self, } } /// Get iterator over special floating point values. #[inline(always)] pub fn special_iter<'b>(&'b mut self) -> SpecialDigitsIterator<'a, 'b, FORMAT> { SpecialDigitsIterator { byte: self, } } /// Internal implementation that handles if it's contiguous. /// /// # Safety /// /// Safe if the buffer has at least `N` elements. #[inline(always)] unsafe fn step_by_unchecked_impl(&mut self, count: usize, is_contiguous: bool) { // NOTE: THIS IS NOT a duplicate calling `step_by_unchecked` from a digits // iterator on the byte, since they can have different contiguousness. if is_contiguous { // Contiguous, can skip most of these checks. debug_assert!(self.as_slice().len() >= count); } else { // Since this isn't contiguous, it only works // if the value is in the range `[0, 1]`. // We also need to make sure the **current** value // isn't a digit separator. let format = NumberFormat::<{ FORMAT }> {}; debug_assert!(self.as_slice().len() >= count); debug_assert!(count == 0 || count == 1); debug_assert!( count == 0 || self.slc.get(self.index) != Some(&format.digit_separator()) ); } self.index += count; } /// Internal implementation that handles if it's contiguous. /// /// If it's contiguous or not does not affect the safety guarantees, /// however, it can affect correctness. /// /// # Safety /// /// Safe if the buffer has at least `size_of::` elements. #[inline(always)] unsafe fn peek_many_unchecked_impl(&self, is_contiguous: bool) -> V { // NOTE: THIS IS NOT a duplicate calling `peek_many_unchecked` from a digits // iterator on the byte, since they can have different contiguousness. debug_assert!(is_contiguous); debug_assert!(self.as_slice().len() >= mem::size_of::()); let slc = self.as_slice(); // SAFETY: safe as long as the slice has at least count elements. unsafe { ptr::read_unaligned::(slc.as_ptr() as *const _) } } } unsafe impl<'a, const FORMAT: u128> Iter<'a> for Bytes<'a, FORMAT> { /// If each yielded value is adjacent in memory. const IS_CONTIGUOUS: bool = NumberFormat::<{ FORMAT }>::DIGIT_SEPARATOR == 0; #[inline(always)] fn get_buffer(&self) -> &'a [u8] { self.slc } /// Get the current index of the iterator in the slice. #[inline(always)] fn cursor(&self) -> usize { self.index } /// Set the current index of the iterator in the slice. /// /// # Safety /// /// Safe if `index <= self.buffer_length()`. #[inline(always)] unsafe fn set_cursor(&mut self, index: usize) { debug_assert!(index <= self.buffer_length()); self.index = index; } /// Get the current number of digits returned by the iterator. /// /// For contiguous iterators, this can include the sign character, decimal /// point, and the exponent sign (that is, it is always the cursor). For /// non-contiguous iterators, this must always be the only the number of /// digits returned. #[inline(always)] fn current_count(&self) -> usize { // If the buffer is contiguous, then we don't need to track the // number of values: the current index is enough. if Self::IS_CONTIGUOUS { self.index } else { self.integer_count + self.fraction_count + self.exponent_count } } #[inline(always)] unsafe fn step_by_unchecked(&mut self, count: usize) { // SAFETY: Safe if the buffer has at least `N` elements. unsafe { self.step_by_unchecked_impl(count, Self::IS_CONTIGUOUS) } } #[inline(always)] unsafe fn peek_many_unchecked(&self) -> V { // SAFETY: Safe if the buffer has at least `size_of::` elements. unsafe { self.peek_many_unchecked_impl(Self::IS_CONTIGUOUS) } } } // ITERATOR HELPERS // ---------------- /// Create skip iterator definition. macro_rules! skip_iterator { ($iterator:ident, $doc:literal) => { #[doc = $doc] pub struct $iterator<'a: 'b, 'b, const FORMAT: u128> { /// The internal byte object for the skip iterator. byte: &'b mut Bytes<'a, FORMAT>, } }; } macro_rules! is_sign { () => { pub const fn is_sign(&self, value: u8) -> bool { matches!(value, b'+' | b'-') } }; } macro_rules! is_digit_separator { ($format:ident) => { /// Determine if the character is a digit separator. pub const fn is_digit_separator(&self, value: u8) -> bool { let format = NumberFormat::<{ $format }> {}; let digit_separator = format.digit_separator(); if digit_separator == 0 { // Check at compile time if we have an invalid digit separator. // b'\x00', or the NUL character, is this invalid value. false } else { value == digit_separator } } }; } /// Create impl block for skip iterator. macro_rules! skip_iterator_impl { ($iterator:ident, $radix_cb:ident) => { impl<'a: 'b, 'b, const FORMAT: u128> $iterator<'a, 'b, FORMAT> { is_sign!(); is_digit_separator!(FORMAT); /// Create a new digits iterator from the bytes underlying item. #[inline(always)] pub fn new(byte: &'b mut Bytes<'a, FORMAT>) -> Self { Self { byte, } } /// Take the first N digits from the iterator. /// /// This only takes the digits if we have a contiguous iterator. /// It takes the digits, validating the bounds, and then advanced /// the iterators state. It does not support non-contiguous iterators /// since we would lose information on the count. #[cfg_attr(not(feature = "compact"), inline(always))] #[allow(clippy::assertions_on_constants)] // reason="ensuring safety invariants are valid" pub fn take_n(&mut self, n: usize) -> Option> { if Self::IS_CONTIGUOUS { let end = self.byte.slc.len().min(n + self.cursor()); // NOTE: The compiler should be able to optimize this out. let slc: &[u8] = &self.byte.slc[..end]; // SAFETY: Safe since we just ensured the underlying slice has that count // elements, so both the underlying slice for this and this **MUST** // have at least count elements. We do static checking on the bounds for this. unsafe { let byte: Bytes<'_, FORMAT> = Bytes::from_parts(slc, self.cursor()); unsafe { self.set_cursor(end) }; Some(byte) } } else { None } } } }; } /// Create impl Iterator block for skip iterator. macro_rules! skip_iterator_iterator_impl { ($iterator:ident) => { impl<'a: 'b, 'b, const FORMAT: u128> Iterator for $iterator<'a, 'b, FORMAT> { type Item = &'a u8; #[inline(always)] fn next(&mut self) -> Option { // Peek will handle everything properly internally. let value = self.peek()?; // Increment the index so we know not to re-fetch it. self.byte.index += 1; // NOTE: Only increment the count if it's not contiguous, otherwise, // this is an unnecessary performance penalty. We also need // to check if it's a digit, which adds on additional cost but // there's not much else we can do. Hopefully the previous inlining // checks will minimize the performance hit. if !Self::IS_CONTIGUOUS && self.is_digit(*value) { self.increment_count(); } Some(value) } } }; } /// Create base methods for the Iter block of a skip iterator. macro_rules! skip_iterator_iter_base { ($format:ident, $mask:ident, $count:ident) => { // It's contiguous if we don't skip over any values. // IE, the digit separator flags for the iterator over // the digits doesn't skip any values. const IS_CONTIGUOUS: bool = $format & flags::$mask == 0; #[inline(always)] fn get_buffer(&self) -> &'a [u8] { self.byte.get_buffer() } #[inline(always)] fn cursor(&self) -> usize { self.byte.cursor() } #[inline(always)] unsafe fn set_cursor(&mut self, index: usize) { debug_assert!(index <= self.buffer_length()); // SAFETY: safe if `index <= self.buffer_length()`. unsafe { self.byte.set_cursor(index) }; } /// Get the current number of digits returned by the iterator. /// /// For contiguous iterators, this can include the sign character, decimal /// point, and the exponent sign (that is, it is always the cursor). For /// non-contiguous iterators, this must always be the only the number of /// digits returned. #[inline(always)] fn current_count(&self) -> usize { if Self::IS_CONTIGUOUS { self.byte.current_count() } else { self.byte.$count } } #[inline(always)] unsafe fn step_by_unchecked(&mut self, count: usize) { // SAFETY: Safe if the buffer has at least `N` elements. unsafe { self.byte.step_by_unchecked_impl(count, Self::IS_CONTIGUOUS) } } #[inline(always)] unsafe fn peek_many_unchecked(&self) -> V { // SAFETY: Safe if the buffer has at least `size_of::` elements. unsafe { self.byte.peek_many_unchecked_impl(Self::IS_CONTIGUOUS) } } }; } /// Create base methods for the `DigitsIter` block of a skip iterator. macro_rules! skip_iterator_digits_iter_base { () => { #[inline(always)] fn is_consumed(&mut self) -> bool { self.peek().is_none() } }; } /// Create impl `ByteIter` block for skip iterator. macro_rules! skip_iterator_bytesiter_impl { ($iterator:ident, $mask:ident, $count:ident, $i:ident, $l:ident, $t:ident, $c:ident) => { unsafe impl<'a: 'b, 'b, const FORMAT: u128> Iter<'a> for $iterator<'a, 'b, FORMAT> { skip_iterator_iter_base!(FORMAT, $mask, $count); } impl<'a: 'b, 'b, const FORMAT: u128> DigitsIter<'a> for $iterator<'a, 'b, FORMAT> { skip_iterator_digits_iter_base!(); /// Increment the number of digits that have been returned by the iterator. /// /// For contiguous iterators, this is a no-op. For non-contiguous iterators, /// this increments the count by 1. #[inline(always)] fn increment_count(&mut self) { self.byte.$count += 1; } /// Peek the next value of the iterator, without consuming it. /// /// Note that this can modify the internal state, by skipping digits /// for iterators that find the first non-zero value, etc. We optimize /// this for the case where we have contiguous iterators, since /// non-contiguous iterators already have a major performance penalty. /// /// Checking if the character is a digit in the `next()` implementation /// after skipping characters can: /// 1. Likely be optimized out due to the use of macros and inlining. /// 2. Is a small amount of overhead compared to the branching on /// characters, #[inline(always)] fn peek(&mut self) -> Option<::Item> { let format = NumberFormat::<{ FORMAT }> {}; const I: u128 = flags::$i; const L: u128 = flags::$l; const T: u128 = flags::$t; const C: u128 = flags::$c; const IL: u128 = I | L; const IT: u128 = I | T; const LT: u128 = L | T; const ILT: u128 = I | L | T; const IC: u128 = I | C; const LC: u128 = L | C; const TC: u128 = T | C; const ILC: u128 = IL | C; const ITC: u128 = IT | C; const LTC: u128 = LT | C; const ILTC: u128 = ILT | C; match format.digit_separator_flags() & flags::$mask { 0 => peek_noskip!(self), I => peek_i!(self), L => peek_l!(self), T => peek_t!(self), IL => peek_il!(self), IT => peek_it!(self), LT => peek_lt!(self), ILT => peek_ilt!(self), IC => peek_ic!(self), LC => peek_lc!(self), TC => peek_tc!(self), ILC => peek_ilc!(self), ITC => peek_itc!(self), LTC => peek_ltc!(self), ILTC => peek_iltc!(self), _ => unreachable!(), } } /// Determine if the character is a digit. #[inline(always)] fn is_digit(&self, value: u8) -> bool { let format = NumberFormat::<{ FORMAT }> {}; char_is_digit_const(value, format.mantissa_radix()) } } }; } // INTEGER DIGITS ITERATOR // ----------------------- skip_iterator!(IntegerDigitsIterator, "Iterator that skips over digit separators in the integer."); skip_iterator_impl!(IntegerDigitsIterator, mantissa_radix); skip_iterator_iterator_impl!(IntegerDigitsIterator); skip_iterator_bytesiter_impl!( IntegerDigitsIterator, INTEGER_DIGIT_SEPARATOR_FLAG_MASK, integer_count, INTEGER_INTERNAL_DIGIT_SEPARATOR, INTEGER_LEADING_DIGIT_SEPARATOR, INTEGER_TRAILING_DIGIT_SEPARATOR, INTEGER_CONSECUTIVE_DIGIT_SEPARATOR ); // FRACTION DIGITS ITERATOR // ------------------------ skip_iterator!( FractionDigitsIterator, "Iterator that skips over digit separators in the fraction." ); skip_iterator_impl!(FractionDigitsIterator, mantissa_radix); skip_iterator_iterator_impl!(FractionDigitsIterator); skip_iterator_bytesiter_impl!( FractionDigitsIterator, FRACTION_DIGIT_SEPARATOR_FLAG_MASK, fraction_count, FRACTION_INTERNAL_DIGIT_SEPARATOR, FRACTION_LEADING_DIGIT_SEPARATOR, FRACTION_TRAILING_DIGIT_SEPARATOR, FRACTION_CONSECUTIVE_DIGIT_SEPARATOR ); // EXPONENT DIGITS ITERATOR // ------------------------ skip_iterator!( ExponentDigitsIterator, "Iterator that skips over digit separators in the exponent." ); skip_iterator_impl!(ExponentDigitsIterator, exponent_radix); skip_iterator_iterator_impl!(ExponentDigitsIterator); skip_iterator_bytesiter_impl!( ExponentDigitsIterator, EXPONENT_DIGIT_SEPARATOR_FLAG_MASK, exponent_count, EXPONENT_INTERNAL_DIGIT_SEPARATOR, EXPONENT_LEADING_DIGIT_SEPARATOR, EXPONENT_TRAILING_DIGIT_SEPARATOR, EXPONENT_CONSECUTIVE_DIGIT_SEPARATOR ); // SPECIAL DIGITS ITERATOR // ----------------------- skip_iterator!( SpecialDigitsIterator, "Iterator that skips over digit separators in special floats." ); skip_iterator_iterator_impl!(SpecialDigitsIterator); impl<'a: 'b, 'b, const FORMAT: u128> SpecialDigitsIterator<'a, 'b, FORMAT> { is_sign!(); is_digit_separator!(FORMAT); } unsafe impl<'a: 'b, 'b, const FORMAT: u128> Iter<'a> for SpecialDigitsIterator<'a, 'b, FORMAT> { skip_iterator_iter_base!(FORMAT, SPECIAL_DIGIT_SEPARATOR, integer_count); } impl<'a: 'b, 'b, const FORMAT: u128> DigitsIter<'a> for SpecialDigitsIterator<'a, 'b, FORMAT> { skip_iterator_digits_iter_base!(); // Always a no-op. #[inline(always)] fn increment_count(&mut self) { } /// Peek the next value of the iterator, without consuming it. #[inline(always)] fn peek(&mut self) -> Option<::Item> { let format = NumberFormat::<{ FORMAT }> {}; if format.special_digit_separator() { peek_iltc!(self) } else { peek_noskip!(self) } } /// Determine if the character is a digit. #[inline(always)] fn is_digit(&self, value: u8) -> bool { let format = NumberFormat::<{ FORMAT }> {}; char_is_digit_const(value, format.mantissa_radix()) } } lexical-util-1.0.6/src/step.rs000064400000000000000000001177151046102023000143500ustar 00000000000000//! The maximum digits that can be held in a u64 for a given radix without //! overflow. //! //! This is useful for 128-bit division and operations, since it can //! reduces the number of inefficient, non-native operations. //! //! # Generation //! //! See [`etc/step.py`] for the script to generate the divisors and the //! constants, and the division algorithm. //! //! [`etc/step.py`]: https://github.com/Alexhuszagh/rust-lexical/blob/main/lexical-util/etc/step.py #![cfg(any(feature = "parse", feature = "write"))] // NOTE: // Fallback radixes use 1 for the value to avoid infinite loops, // but allowing them in `const fn`. /// Get the maximum number of digits that can be processed without overflowing. /// /// Calculate the maximum number of digits that can always be processed /// without overflowing for a given type. For example, 19 digits can /// always be processed for a decimal string for `u64` without overflowing. #[inline(always)] #[allow(clippy::needless_return)] // reason="required depending on our radix configuration" pub const fn min_step(radix: u32, bits: usize, is_signed: bool) -> usize { // NOTE: to avoid branching when w don't need it, we use the compile logic #[cfg(feature = "radix")] { return match radix { 2 => min_step_2(bits, is_signed), 3 => min_step_3(bits, is_signed), 4 => min_step_4(bits, is_signed), 5 => min_step_5(bits, is_signed), 6 => min_step_6(bits, is_signed), 7 => min_step_7(bits, is_signed), 8 => min_step_8(bits, is_signed), 9 => min_step_9(bits, is_signed), 10 => min_step_10(bits, is_signed), 11 => min_step_11(bits, is_signed), 12 => min_step_12(bits, is_signed), 13 => min_step_13(bits, is_signed), 14 => min_step_14(bits, is_signed), 15 => min_step_15(bits, is_signed), 16 => min_step_16(bits, is_signed), 17 => min_step_17(bits, is_signed), 18 => min_step_18(bits, is_signed), 19 => min_step_19(bits, is_signed), 20 => min_step_20(bits, is_signed), 21 => min_step_21(bits, is_signed), 22 => min_step_22(bits, is_signed), 23 => min_step_23(bits, is_signed), 24 => min_step_24(bits, is_signed), 25 => min_step_25(bits, is_signed), 26 => min_step_26(bits, is_signed), 27 => min_step_27(bits, is_signed), 28 => min_step_28(bits, is_signed), 29 => min_step_29(bits, is_signed), 30 => min_step_30(bits, is_signed), 31 => min_step_31(bits, is_signed), 32 => min_step_32(bits, is_signed), 33 => min_step_33(bits, is_signed), 34 => min_step_34(bits, is_signed), 35 => min_step_35(bits, is_signed), 36 => min_step_36(bits, is_signed), _ => 1, }; } #[cfg(all(feature = "power-of-two", not(feature = "radix")))] { return match radix { 2 => min_step_2(bits, is_signed), 4 => min_step_4(bits, is_signed), 8 => min_step_8(bits, is_signed), 10 => min_step_10(bits, is_signed), 16 => min_step_16(bits, is_signed), 32 => min_step_32(bits, is_signed), _ => 1, }; } #[cfg(not(feature = "power-of-two"))] { _ = radix; return min_step_10(bits, is_signed); } } /// Get the maximum number of digits that can be processed without overflowing. /// /// Calculate the maximum number of digits that can be processed /// without always overflowing for a given type. For example, 20 digits can /// be processed for a decimal string for `u64` without overflowing, but /// it may overflow. #[inline(always)] #[allow(clippy::needless_return)] // reason="required depending on our radix configuration" pub const fn max_step(radix: u32, bits: usize, is_signed: bool) -> usize { #[cfg(feature = "radix")] { return match radix { 2 => max_step_2(bits, is_signed), 3 => max_step_3(bits, is_signed), 4 => max_step_4(bits, is_signed), 5 => max_step_5(bits, is_signed), 6 => max_step_6(bits, is_signed), 7 => max_step_7(bits, is_signed), 8 => max_step_8(bits, is_signed), 9 => max_step_9(bits, is_signed), 10 => max_step_10(bits, is_signed), 11 => max_step_11(bits, is_signed), 12 => max_step_12(bits, is_signed), 13 => max_step_13(bits, is_signed), 14 => max_step_14(bits, is_signed), 15 => max_step_15(bits, is_signed), 16 => max_step_16(bits, is_signed), 17 => max_step_17(bits, is_signed), 18 => max_step_18(bits, is_signed), 19 => max_step_19(bits, is_signed), 20 => max_step_20(bits, is_signed), 21 => max_step_21(bits, is_signed), 22 => max_step_22(bits, is_signed), 23 => max_step_23(bits, is_signed), 24 => max_step_24(bits, is_signed), 25 => max_step_25(bits, is_signed), 26 => max_step_26(bits, is_signed), 27 => max_step_27(bits, is_signed), 28 => max_step_28(bits, is_signed), 29 => max_step_29(bits, is_signed), 30 => max_step_30(bits, is_signed), 31 => max_step_31(bits, is_signed), 32 => max_step_32(bits, is_signed), 33 => max_step_33(bits, is_signed), 34 => max_step_34(bits, is_signed), 35 => max_step_35(bits, is_signed), 36 => max_step_36(bits, is_signed), _ => 1, }; } #[cfg(all(feature = "power-of-two", not(feature = "radix")))] { return match radix { 2 => max_step_2(bits, is_signed), 4 => max_step_4(bits, is_signed), 8 => max_step_8(bits, is_signed), 10 => max_step_10(bits, is_signed), 16 => max_step_16(bits, is_signed), 32 => max_step_32(bits, is_signed), _ => 1, }; } #[cfg(not(feature = "power-of-two"))] { _ = radix; return max_step_10(bits, is_signed); } } /// Calculate the number of digits that can be processed without overflowing a /// u64. Helper function since this is used for 128-bit division. #[inline(always)] pub const fn u64_step(radix: u32) -> usize { min_step(radix, 64, false) } // AUTO-GENERATED // These functions were auto-generated by `etc/step.py`. // Do not edit them unless there is a good reason to. // Preferably, edit the source code to generate the constants. // // NOTE: For the fallthrough value for types (in case of adding short // or wider type support in the future), use 1 so it doesn't infinitely // recurse. Under normal circumstances, this will never be called. #[inline(always)] #[cfg_attr(not(feature = "power-of-two"), allow(dead_code))] const fn max_step_2(bits: usize, is_signed: bool) -> usize { match bits { 8 if is_signed => 7, 8 if !is_signed => 8, 16 if is_signed => 15, 16 if !is_signed => 16, 32 if is_signed => 31, 32 if !is_signed => 32, 64 if is_signed => 63, 64 if !is_signed => 64, 128 if is_signed => 127, 128 if !is_signed => 128, _ => 1, } } #[inline(always)] #[cfg_attr(not(feature = "power-of-two"), allow(dead_code))] const fn min_step_2(bits: usize, is_signed: bool) -> usize { match bits { 8 if is_signed => 7, 8 if !is_signed => 8, 16 if is_signed => 15, 16 if !is_signed => 16, 32 if is_signed => 31, 32 if !is_signed => 32, 64 if is_signed => 63, 64 if !is_signed => 64, 128 if is_signed => 127, 128 if !is_signed => 128, _ => 1, } } #[inline(always)] #[cfg_attr(not(feature = "radix"), allow(dead_code))] const fn max_step_3(bits: usize, is_signed: bool) -> usize { match bits { 8 if is_signed => 5, 8 if !is_signed => 6, 16 if is_signed => 10, 16 if !is_signed => 11, 32 if is_signed => 20, 32 if !is_signed => 21, 64 if is_signed => 40, 64 if !is_signed => 41, 128 if is_signed => 81, 128 if !is_signed => 81, _ => 1, } } #[inline(always)] #[cfg_attr(not(feature = "radix"), allow(dead_code))] const fn min_step_3(bits: usize, is_signed: bool) -> usize { match bits { 8 if is_signed => 4, 8 if !is_signed => 5, 16 if is_signed => 9, 16 if !is_signed => 10, 32 if is_signed => 19, 32 if !is_signed => 20, 64 if is_signed => 39, 64 if !is_signed => 40, 128 if is_signed => 80, 128 if !is_signed => 80, _ => 1, } } #[inline(always)] #[cfg_attr(not(feature = "power-of-two"), allow(dead_code))] const fn max_step_4(bits: usize, is_signed: bool) -> usize { match bits { 8 if is_signed => 4, 8 if !is_signed => 4, 16 if is_signed => 8, 16 if !is_signed => 8, 32 if is_signed => 16, 32 if !is_signed => 16, 64 if is_signed => 32, 64 if !is_signed => 32, 128 if is_signed => 64, 128 if !is_signed => 64, _ => 1, } } #[inline(always)] #[cfg_attr(not(feature = "power-of-two"), allow(dead_code))] const fn min_step_4(bits: usize, is_signed: bool) -> usize { match bits { 8 if is_signed => 3, 8 if !is_signed => 4, 16 if is_signed => 7, 16 if !is_signed => 8, 32 if is_signed => 15, 32 if !is_signed => 16, 64 if is_signed => 31, 64 if !is_signed => 32, 128 if is_signed => 63, 128 if !is_signed => 64, _ => 1, } } #[inline(always)] #[cfg_attr(not(feature = "radix"), allow(dead_code))] const fn max_step_5(bits: usize, is_signed: bool) -> usize { match bits { 8 if is_signed => 4, 8 if !is_signed => 4, 16 if is_signed => 7, 16 if !is_signed => 7, 32 if is_signed => 14, 32 if !is_signed => 14, 64 if is_signed => 28, 64 if !is_signed => 28, 128 if is_signed => 55, 128 if !is_signed => 56, _ => 1, } } #[inline(always)] #[cfg_attr(not(feature = "radix"), allow(dead_code))] const fn min_step_5(bits: usize, is_signed: bool) -> usize { match bits { 8 if is_signed => 3, 8 if !is_signed => 3, 16 if is_signed => 6, 16 if !is_signed => 6, 32 if is_signed => 13, 32 if !is_signed => 13, 64 if is_signed => 27, 64 if !is_signed => 27, 128 if is_signed => 54, 128 if !is_signed => 55, _ => 1, } } #[inline(always)] #[cfg_attr(not(feature = "radix"), allow(dead_code))] const fn max_step_6(bits: usize, is_signed: bool) -> usize { match bits { 8 if is_signed => 3, 8 if !is_signed => 4, 16 if is_signed => 6, 16 if !is_signed => 7, 32 if is_signed => 12, 32 if !is_signed => 13, 64 if is_signed => 25, 64 if !is_signed => 25, 128 if is_signed => 50, 128 if !is_signed => 50, _ => 1, } } #[inline(always)] #[cfg_attr(not(feature = "radix"), allow(dead_code))] const fn min_step_6(bits: usize, is_signed: bool) -> usize { match bits { 8 if is_signed => 2, 8 if !is_signed => 3, 16 if is_signed => 5, 16 if !is_signed => 6, 32 if is_signed => 11, 32 if !is_signed => 12, 64 if is_signed => 24, 64 if !is_signed => 24, 128 if is_signed => 49, 128 if !is_signed => 49, _ => 1, } } #[inline(always)] #[cfg_attr(not(feature = "radix"), allow(dead_code))] const fn max_step_7(bits: usize, is_signed: bool) -> usize { match bits { 8 if is_signed => 3, 8 if !is_signed => 3, 16 if is_signed => 6, 16 if !is_signed => 6, 32 if is_signed => 12, 32 if !is_signed => 12, 64 if is_signed => 23, 64 if !is_signed => 23, 128 if is_signed => 46, 128 if !is_signed => 46, _ => 1, } } #[inline(always)] #[cfg_attr(not(feature = "radix"), allow(dead_code))] const fn min_step_7(bits: usize, is_signed: bool) -> usize { match bits { 8 if is_signed => 2, 8 if !is_signed => 2, 16 if is_signed => 5, 16 if !is_signed => 5, 32 if is_signed => 11, 32 if !is_signed => 11, 64 if is_signed => 22, 64 if !is_signed => 22, 128 if is_signed => 45, 128 if !is_signed => 45, _ => 1, } } #[inline(always)] #[cfg_attr(not(feature = "power-of-two"), allow(dead_code))] const fn max_step_8(bits: usize, is_signed: bool) -> usize { match bits { 8 if is_signed => 3, 8 if !is_signed => 3, 16 if is_signed => 5, 16 if !is_signed => 6, 32 if is_signed => 11, 32 if !is_signed => 11, 64 if is_signed => 21, 64 if !is_signed => 22, 128 if is_signed => 43, 128 if !is_signed => 43, _ => 1, } } #[inline(always)] #[cfg_attr(not(feature = "power-of-two"), allow(dead_code))] const fn min_step_8(bits: usize, is_signed: bool) -> usize { match bits { 8 if is_signed => 2, 8 if !is_signed => 2, 16 if is_signed => 5, 16 if !is_signed => 5, 32 if is_signed => 10, 32 if !is_signed => 10, 64 if is_signed => 21, 64 if !is_signed => 21, 128 if is_signed => 42, 128 if !is_signed => 42, _ => 1, } } #[inline(always)] #[cfg_attr(not(feature = "radix"), allow(dead_code))] const fn max_step_9(bits: usize, is_signed: bool) -> usize { match bits { 8 if is_signed => 3, 8 if !is_signed => 3, 16 if is_signed => 5, 16 if !is_signed => 6, 32 if is_signed => 10, 32 if !is_signed => 11, 64 if is_signed => 20, 64 if !is_signed => 21, 128 if is_signed => 41, 128 if !is_signed => 41, _ => 1, } } #[inline(always)] #[cfg_attr(not(feature = "radix"), allow(dead_code))] const fn min_step_9(bits: usize, is_signed: bool) -> usize { match bits { 8 if is_signed => 2, 8 if !is_signed => 2, 16 if is_signed => 4, 16 if !is_signed => 5, 32 if is_signed => 9, 32 if !is_signed => 10, 64 if is_signed => 19, 64 if !is_signed => 20, 128 if is_signed => 40, 128 if !is_signed => 40, _ => 1, } } #[inline(always)] const fn max_step_10(bits: usize, is_signed: bool) -> usize { match bits { 8 if is_signed => 3, 8 if !is_signed => 3, 16 if is_signed => 5, 16 if !is_signed => 5, 32 if is_signed => 10, 32 if !is_signed => 10, 64 if is_signed => 19, 64 if !is_signed => 20, 128 if is_signed => 39, 128 if !is_signed => 39, _ => 1, } } #[inline(always)] const fn min_step_10(bits: usize, is_signed: bool) -> usize { match bits { 8 if is_signed => 2, 8 if !is_signed => 2, 16 if is_signed => 4, 16 if !is_signed => 4, 32 if is_signed => 9, 32 if !is_signed => 9, 64 if is_signed => 18, 64 if !is_signed => 19, 128 if is_signed => 38, 128 if !is_signed => 38, _ => 1, } } #[inline(always)] #[cfg_attr(not(feature = "radix"), allow(dead_code))] const fn max_step_11(bits: usize, is_signed: bool) -> usize { match bits { 8 if is_signed => 3, 8 if !is_signed => 3, 16 if is_signed => 5, 16 if !is_signed => 5, 32 if is_signed => 9, 32 if !is_signed => 10, 64 if is_signed => 19, 64 if !is_signed => 19, 128 if is_signed => 37, 128 if !is_signed => 38, _ => 1, } } #[inline(always)] #[cfg_attr(not(feature = "radix"), allow(dead_code))] const fn min_step_11(bits: usize, is_signed: bool) -> usize { match bits { 8 if is_signed => 2, 8 if !is_signed => 2, 16 if is_signed => 4, 16 if !is_signed => 4, 32 if is_signed => 8, 32 if !is_signed => 9, 64 if is_signed => 18, 64 if !is_signed => 18, 128 if is_signed => 36, 128 if !is_signed => 37, _ => 1, } } #[inline(always)] #[cfg_attr(not(feature = "radix"), allow(dead_code))] const fn max_step_12(bits: usize, is_signed: bool) -> usize { match bits { 8 if is_signed => 2, 8 if !is_signed => 3, 16 if is_signed => 5, 16 if !is_signed => 5, 32 if is_signed => 9, 32 if !is_signed => 9, 64 if is_signed => 18, 64 if !is_signed => 18, 128 if is_signed => 36, 128 if !is_signed => 36, _ => 1, } } #[inline(always)] #[cfg_attr(not(feature = "radix"), allow(dead_code))] const fn min_step_12(bits: usize, is_signed: bool) -> usize { match bits { 8 if is_signed => 1, 8 if !is_signed => 2, 16 if is_signed => 4, 16 if !is_signed => 4, 32 if is_signed => 8, 32 if !is_signed => 8, 64 if is_signed => 17, 64 if !is_signed => 17, 128 if is_signed => 35, 128 if !is_signed => 35, _ => 1, } } #[inline(always)] #[cfg_attr(not(feature = "radix"), allow(dead_code))] const fn max_step_13(bits: usize, is_signed: bool) -> usize { match bits { 8 if is_signed => 2, 8 if !is_signed => 3, 16 if is_signed => 5, 16 if !is_signed => 5, 32 if is_signed => 9, 32 if !is_signed => 9, 64 if is_signed => 18, 64 if !is_signed => 18, 128 if is_signed => 35, 128 if !is_signed => 35, _ => 1, } } #[inline(always)] #[cfg_attr(not(feature = "radix"), allow(dead_code))] const fn min_step_13(bits: usize, is_signed: bool) -> usize { match bits { 8 if is_signed => 1, 8 if !is_signed => 2, 16 if is_signed => 4, 16 if !is_signed => 4, 32 if is_signed => 8, 32 if !is_signed => 8, 64 if is_signed => 17, 64 if !is_signed => 17, 128 if is_signed => 34, 128 if !is_signed => 34, _ => 1, } } #[inline(always)] #[cfg_attr(not(feature = "radix"), allow(dead_code))] const fn max_step_14(bits: usize, is_signed: bool) -> usize { match bits { 8 if is_signed => 2, 8 if !is_signed => 3, 16 if is_signed => 4, 16 if !is_signed => 5, 32 if is_signed => 9, 32 if !is_signed => 9, 64 if is_signed => 17, 64 if !is_signed => 17, 128 if is_signed => 34, 128 if !is_signed => 34, _ => 1, } } #[inline(always)] #[cfg_attr(not(feature = "radix"), allow(dead_code))] const fn min_step_14(bits: usize, is_signed: bool) -> usize { match bits { 8 if is_signed => 1, 8 if !is_signed => 2, 16 if is_signed => 3, 16 if !is_signed => 4, 32 if is_signed => 8, 32 if !is_signed => 8, 64 if is_signed => 16, 64 if !is_signed => 16, 128 if is_signed => 33, 128 if !is_signed => 33, _ => 1, } } #[inline(always)] #[cfg_attr(not(feature = "radix"), allow(dead_code))] const fn max_step_15(bits: usize, is_signed: bool) -> usize { match bits { 8 if is_signed => 2, 8 if !is_signed => 3, 16 if is_signed => 4, 16 if !is_signed => 5, 32 if is_signed => 8, 32 if !is_signed => 9, 64 if is_signed => 17, 64 if !is_signed => 17, 128 if is_signed => 33, 128 if !is_signed => 33, _ => 1, } } #[inline(always)] #[cfg_attr(not(feature = "radix"), allow(dead_code))] const fn min_step_15(bits: usize, is_signed: bool) -> usize { match bits { 8 if is_signed => 1, 8 if !is_signed => 2, 16 if is_signed => 3, 16 if !is_signed => 4, 32 if is_signed => 7, 32 if !is_signed => 8, 64 if is_signed => 16, 64 if !is_signed => 16, 128 if is_signed => 32, 128 if !is_signed => 32, _ => 1, } } #[inline(always)] #[cfg_attr(not(feature = "power-of-two"), allow(dead_code))] const fn max_step_16(bits: usize, is_signed: bool) -> usize { match bits { 8 if is_signed => 2, 8 if !is_signed => 2, 16 if is_signed => 4, 16 if !is_signed => 4, 32 if is_signed => 8, 32 if !is_signed => 8, 64 if is_signed => 16, 64 if !is_signed => 16, 128 if is_signed => 32, 128 if !is_signed => 32, _ => 1, } } #[inline(always)] #[cfg_attr(not(feature = "power-of-two"), allow(dead_code))] const fn min_step_16(bits: usize, is_signed: bool) -> usize { match bits { 8 if is_signed => 1, 8 if !is_signed => 2, 16 if is_signed => 3, 16 if !is_signed => 4, 32 if is_signed => 7, 32 if !is_signed => 8, 64 if is_signed => 15, 64 if !is_signed => 16, 128 if is_signed => 31, 128 if !is_signed => 32, _ => 1, } } #[inline(always)] #[cfg_attr(not(feature = "radix"), allow(dead_code))] const fn max_step_17(bits: usize, is_signed: bool) -> usize { match bits { 8 if is_signed => 2, 8 if !is_signed => 2, 16 if is_signed => 4, 16 if !is_signed => 4, 32 if is_signed => 8, 32 if !is_signed => 8, 64 if is_signed => 16, 64 if !is_signed => 16, 128 if is_signed => 32, 128 if !is_signed => 32, _ => 1, } } #[inline(always)] #[cfg_attr(not(feature = "radix"), allow(dead_code))] const fn min_step_17(bits: usize, is_signed: bool) -> usize { match bits { 8 if is_signed => 1, 8 if !is_signed => 1, 16 if is_signed => 3, 16 if !is_signed => 3, 32 if is_signed => 7, 32 if !is_signed => 7, 64 if is_signed => 15, 64 if !is_signed => 15, 128 if is_signed => 31, 128 if !is_signed => 31, _ => 1, } } #[inline(always)] #[cfg_attr(not(feature = "radix"), allow(dead_code))] const fn max_step_18(bits: usize, is_signed: bool) -> usize { match bits { 8 if is_signed => 2, 8 if !is_signed => 2, 16 if is_signed => 4, 16 if !is_signed => 4, 32 if is_signed => 8, 32 if !is_signed => 8, 64 if is_signed => 16, 64 if !is_signed => 16, 128 if is_signed => 31, 128 if !is_signed => 31, _ => 1, } } #[inline(always)] #[cfg_attr(not(feature = "radix"), allow(dead_code))] const fn min_step_18(bits: usize, is_signed: bool) -> usize { match bits { 8 if is_signed => 1, 8 if !is_signed => 1, 16 if is_signed => 3, 16 if !is_signed => 3, 32 if is_signed => 7, 32 if !is_signed => 7, 64 if is_signed => 15, 64 if !is_signed => 15, 128 if is_signed => 30, 128 if !is_signed => 30, _ => 1, } } #[inline(always)] #[cfg_attr(not(feature = "radix"), allow(dead_code))] const fn max_step_19(bits: usize, is_signed: bool) -> usize { match bits { 8 if is_signed => 2, 8 if !is_signed => 2, 16 if is_signed => 4, 16 if !is_signed => 4, 32 if is_signed => 8, 32 if !is_signed => 8, 64 if is_signed => 15, 64 if !is_signed => 16, 128 if is_signed => 30, 128 if !is_signed => 31, _ => 1, } } #[inline(always)] #[cfg_attr(not(feature = "radix"), allow(dead_code))] const fn min_step_19(bits: usize, is_signed: bool) -> usize { match bits { 8 if is_signed => 1, 8 if !is_signed => 1, 16 if is_signed => 3, 16 if !is_signed => 3, 32 if is_signed => 7, 32 if !is_signed => 7, 64 if is_signed => 14, 64 if !is_signed => 15, 128 if is_signed => 29, 128 if !is_signed => 30, _ => 1, } } #[inline(always)] #[cfg_attr(not(feature = "radix"), allow(dead_code))] const fn max_step_20(bits: usize, is_signed: bool) -> usize { match bits { 8 if is_signed => 2, 8 if !is_signed => 2, 16 if is_signed => 4, 16 if !is_signed => 4, 32 if is_signed => 8, 32 if !is_signed => 8, 64 if is_signed => 15, 64 if !is_signed => 15, 128 if is_signed => 30, 128 if !is_signed => 30, _ => 1, } } #[inline(always)] #[cfg_attr(not(feature = "radix"), allow(dead_code))] const fn min_step_20(bits: usize, is_signed: bool) -> usize { match bits { 8 if is_signed => 1, 8 if !is_signed => 1, 16 if is_signed => 3, 16 if !is_signed => 3, 32 if is_signed => 7, 32 if !is_signed => 7, 64 if is_signed => 14, 64 if !is_signed => 14, 128 if is_signed => 29, 128 if !is_signed => 29, _ => 1, } } #[inline(always)] #[cfg_attr(not(feature = "radix"), allow(dead_code))] const fn max_step_21(bits: usize, is_signed: bool) -> usize { match bits { 8 if is_signed => 2, 8 if !is_signed => 2, 16 if is_signed => 4, 16 if !is_signed => 4, 32 if is_signed => 8, 32 if !is_signed => 8, 64 if is_signed => 15, 64 if !is_signed => 15, 128 if is_signed => 29, 128 if !is_signed => 30, _ => 1, } } #[inline(always)] #[cfg_attr(not(feature = "radix"), allow(dead_code))] const fn min_step_21(bits: usize, is_signed: bool) -> usize { match bits { 8 if is_signed => 1, 8 if !is_signed => 1, 16 if is_signed => 3, 16 if !is_signed => 3, 32 if is_signed => 7, 32 if !is_signed => 7, 64 if is_signed => 14, 64 if !is_signed => 14, 128 if is_signed => 28, 128 if !is_signed => 29, _ => 1, } } #[inline(always)] #[cfg_attr(not(feature = "radix"), allow(dead_code))] const fn max_step_22(bits: usize, is_signed: bool) -> usize { match bits { 8 if is_signed => 2, 8 if !is_signed => 2, 16 if is_signed => 4, 16 if !is_signed => 4, 32 if is_signed => 7, 32 if !is_signed => 8, 64 if is_signed => 15, 64 if !is_signed => 15, 128 if is_signed => 29, 128 if !is_signed => 29, _ => 1, } } #[inline(always)] #[cfg_attr(not(feature = "radix"), allow(dead_code))] const fn min_step_22(bits: usize, is_signed: bool) -> usize { match bits { 8 if is_signed => 1, 8 if !is_signed => 1, 16 if is_signed => 3, 16 if !is_signed => 3, 32 if is_signed => 6, 32 if !is_signed => 7, 64 if is_signed => 14, 64 if !is_signed => 14, 128 if is_signed => 28, 128 if !is_signed => 28, _ => 1, } } #[inline(always)] #[cfg_attr(not(feature = "radix"), allow(dead_code))] const fn max_step_23(bits: usize, is_signed: bool) -> usize { match bits { 8 if is_signed => 2, 8 if !is_signed => 2, 16 if is_signed => 4, 16 if !is_signed => 4, 32 if is_signed => 7, 32 if !is_signed => 8, 64 if is_signed => 14, 64 if !is_signed => 15, 128 if is_signed => 29, 128 if !is_signed => 29, _ => 1, } } #[inline(always)] #[cfg_attr(not(feature = "radix"), allow(dead_code))] const fn min_step_23(bits: usize, is_signed: bool) -> usize { match bits { 8 if is_signed => 1, 8 if !is_signed => 1, 16 if is_signed => 3, 16 if !is_signed => 3, 32 if is_signed => 6, 32 if !is_signed => 7, 64 if is_signed => 13, 64 if !is_signed => 14, 128 if is_signed => 28, 128 if !is_signed => 28, _ => 1, } } #[inline(always)] #[cfg_attr(not(feature = "radix"), allow(dead_code))] const fn max_step_24(bits: usize, is_signed: bool) -> usize { match bits { 8 if is_signed => 2, 8 if !is_signed => 2, 16 if is_signed => 4, 16 if !is_signed => 4, 32 if is_signed => 7, 32 if !is_signed => 7, 64 if is_signed => 14, 64 if !is_signed => 14, 128 if is_signed => 28, 128 if !is_signed => 28, _ => 1, } } #[inline(always)] #[cfg_attr(not(feature = "radix"), allow(dead_code))] const fn min_step_24(bits: usize, is_signed: bool) -> usize { match bits { 8 if is_signed => 1, 8 if !is_signed => 1, 16 if is_signed => 3, 16 if !is_signed => 3, 32 if is_signed => 6, 32 if !is_signed => 6, 64 if is_signed => 13, 64 if !is_signed => 13, 128 if is_signed => 27, 128 if !is_signed => 27, _ => 1, } } #[inline(always)] #[cfg_attr(not(feature = "radix"), allow(dead_code))] const fn max_step_25(bits: usize, is_signed: bool) -> usize { match bits { 8 if is_signed => 2, 8 if !is_signed => 2, 16 if is_signed => 4, 16 if !is_signed => 4, 32 if is_signed => 7, 32 if !is_signed => 7, 64 if is_signed => 14, 64 if !is_signed => 14, 128 if is_signed => 28, 128 if !is_signed => 28, _ => 1, } } #[inline(always)] #[cfg_attr(not(feature = "radix"), allow(dead_code))] const fn min_step_25(bits: usize, is_signed: bool) -> usize { match bits { 8 if is_signed => 1, 8 if !is_signed => 1, 16 if is_signed => 3, 16 if !is_signed => 3, 32 if is_signed => 6, 32 if !is_signed => 6, 64 if is_signed => 13, 64 if !is_signed => 13, 128 if is_signed => 27, 128 if !is_signed => 27, _ => 1, } } #[inline(always)] #[cfg_attr(not(feature = "radix"), allow(dead_code))] const fn max_step_26(bits: usize, is_signed: bool) -> usize { match bits { 8 if is_signed => 2, 8 if !is_signed => 2, 16 if is_signed => 4, 16 if !is_signed => 4, 32 if is_signed => 7, 32 if !is_signed => 7, 64 if is_signed => 14, 64 if !is_signed => 14, 128 if is_signed => 28, 128 if !is_signed => 28, _ => 1, } } #[inline(always)] #[cfg_attr(not(feature = "radix"), allow(dead_code))] const fn min_step_26(bits: usize, is_signed: bool) -> usize { match bits { 8 if is_signed => 1, 8 if !is_signed => 1, 16 if is_signed => 3, 16 if !is_signed => 3, 32 if is_signed => 6, 32 if !is_signed => 6, 64 if is_signed => 13, 64 if !is_signed => 13, 128 if is_signed => 27, 128 if !is_signed => 27, _ => 1, } } #[inline(always)] #[cfg_attr(not(feature = "radix"), allow(dead_code))] const fn max_step_27(bits: usize, is_signed: bool) -> usize { match bits { 8 if is_signed => 2, 8 if !is_signed => 2, 16 if is_signed => 4, 16 if !is_signed => 4, 32 if is_signed => 7, 32 if !is_signed => 7, 64 if is_signed => 14, 64 if !is_signed => 14, 128 if is_signed => 27, 128 if !is_signed => 27, _ => 1, } } #[inline(always)] #[cfg_attr(not(feature = "radix"), allow(dead_code))] const fn min_step_27(bits: usize, is_signed: bool) -> usize { match bits { 8 if is_signed => 1, 8 if !is_signed => 1, 16 if is_signed => 3, 16 if !is_signed => 3, 32 if is_signed => 6, 32 if !is_signed => 6, 64 if is_signed => 13, 64 if !is_signed => 13, 128 if is_signed => 26, 128 if !is_signed => 26, _ => 1, } } #[inline(always)] #[cfg_attr(not(feature = "radix"), allow(dead_code))] const fn max_step_28(bits: usize, is_signed: bool) -> usize { match bits { 8 if is_signed => 2, 8 if !is_signed => 2, 16 if is_signed => 4, 16 if !is_signed => 4, 32 if is_signed => 7, 32 if !is_signed => 7, 64 if is_signed => 14, 64 if !is_signed => 14, 128 if is_signed => 27, 128 if !is_signed => 27, _ => 1, } } #[inline(always)] #[cfg_attr(not(feature = "radix"), allow(dead_code))] const fn min_step_28(bits: usize, is_signed: bool) -> usize { match bits { 8 if is_signed => 1, 8 if !is_signed => 1, 16 if is_signed => 3, 16 if !is_signed => 3, 32 if is_signed => 6, 32 if !is_signed => 6, 64 if is_signed => 13, 64 if !is_signed => 13, 128 if is_signed => 26, 128 if !is_signed => 26, _ => 1, } } #[inline(always)] #[cfg_attr(not(feature = "radix"), allow(dead_code))] const fn max_step_29(bits: usize, is_signed: bool) -> usize { match bits { 8 if is_signed => 2, 8 if !is_signed => 2, 16 if is_signed => 4, 16 if !is_signed => 4, 32 if is_signed => 7, 32 if !is_signed => 7, 64 if is_signed => 13, 64 if !is_signed => 14, 128 if is_signed => 27, 128 if !is_signed => 27, _ => 1, } } #[inline(always)] #[cfg_attr(not(feature = "radix"), allow(dead_code))] const fn min_step_29(bits: usize, is_signed: bool) -> usize { match bits { 8 if is_signed => 1, 8 if !is_signed => 1, 16 if is_signed => 3, 16 if !is_signed => 3, 32 if is_signed => 6, 32 if !is_signed => 6, 64 if is_signed => 12, 64 if !is_signed => 13, 128 if is_signed => 26, 128 if !is_signed => 26, _ => 1, } } #[inline(always)] #[cfg_attr(not(feature = "radix"), allow(dead_code))] const fn max_step_30(bits: usize, is_signed: bool) -> usize { match bits { 8 if is_signed => 2, 8 if !is_signed => 2, 16 if is_signed => 4, 16 if !is_signed => 4, 32 if is_signed => 7, 32 if !is_signed => 7, 64 if is_signed => 13, 64 if !is_signed => 14, 128 if is_signed => 26, 128 if !is_signed => 27, _ => 1, } } #[inline(always)] #[cfg_attr(not(feature = "radix"), allow(dead_code))] const fn min_step_30(bits: usize, is_signed: bool) -> usize { match bits { 8 if is_signed => 1, 8 if !is_signed => 1, 16 if is_signed => 3, 16 if !is_signed => 3, 32 if is_signed => 6, 32 if !is_signed => 6, 64 if is_signed => 12, 64 if !is_signed => 13, 128 if is_signed => 25, 128 if !is_signed => 26, _ => 1, } } #[inline(always)] #[cfg_attr(not(feature = "radix"), allow(dead_code))] const fn max_step_31(bits: usize, is_signed: bool) -> usize { match bits { 8 if is_signed => 2, 8 if !is_signed => 2, 16 if is_signed => 4, 16 if !is_signed => 4, 32 if is_signed => 7, 32 if !is_signed => 7, 64 if is_signed => 13, 64 if !is_signed => 13, 128 if is_signed => 26, 128 if !is_signed => 26, _ => 1, } } #[inline(always)] #[cfg_attr(not(feature = "radix"), allow(dead_code))] const fn min_step_31(bits: usize, is_signed: bool) -> usize { match bits { 8 if is_signed => 1, 8 if !is_signed => 1, 16 if is_signed => 3, 16 if !is_signed => 3, 32 if is_signed => 6, 32 if !is_signed => 6, 64 if is_signed => 12, 64 if !is_signed => 12, 128 if is_signed => 25, 128 if !is_signed => 25, _ => 1, } } #[inline(always)] #[cfg_attr(not(feature = "power-of-two"), allow(dead_code))] const fn max_step_32(bits: usize, is_signed: bool) -> usize { match bits { 8 if is_signed => 2, 8 if !is_signed => 2, 16 if is_signed => 3, 16 if !is_signed => 4, 32 if is_signed => 7, 32 if !is_signed => 7, 64 if is_signed => 13, 64 if !is_signed => 13, 128 if is_signed => 26, 128 if !is_signed => 26, _ => 1, } } #[inline(always)] #[cfg_attr(not(feature = "power-of-two"), allow(dead_code))] const fn min_step_32(bits: usize, is_signed: bool) -> usize { match bits { 8 if is_signed => 1, 8 if !is_signed => 1, 16 if is_signed => 3, 16 if !is_signed => 3, 32 if is_signed => 6, 32 if !is_signed => 6, 64 if is_signed => 12, 64 if !is_signed => 12, 128 if is_signed => 25, 128 if !is_signed => 25, _ => 1, } } #[inline(always)] #[cfg_attr(not(feature = "radix"), allow(dead_code))] const fn max_step_33(bits: usize, is_signed: bool) -> usize { match bits { 8 if is_signed => 2, 8 if !is_signed => 2, 16 if is_signed => 3, 16 if !is_signed => 4, 32 if is_signed => 7, 32 if !is_signed => 7, 64 if is_signed => 13, 64 if !is_signed => 13, 128 if is_signed => 26, 128 if !is_signed => 26, _ => 1, } } #[inline(always)] #[cfg_attr(not(feature = "radix"), allow(dead_code))] const fn min_step_33(bits: usize, is_signed: bool) -> usize { match bits { 8 if is_signed => 1, 8 if !is_signed => 1, 16 if is_signed => 2, 16 if !is_signed => 3, 32 if is_signed => 6, 32 if !is_signed => 6, 64 if is_signed => 12, 64 if !is_signed => 12, 128 if is_signed => 25, 128 if !is_signed => 25, _ => 1, } } #[inline(always)] #[cfg_attr(not(feature = "radix"), allow(dead_code))] const fn max_step_34(bits: usize, is_signed: bool) -> usize { match bits { 8 if is_signed => 2, 8 if !is_signed => 2, 16 if is_signed => 3, 16 if !is_signed => 4, 32 if is_signed => 7, 32 if !is_signed => 7, 64 if is_signed => 13, 64 if !is_signed => 13, 128 if is_signed => 25, 128 if !is_signed => 26, _ => 1, } } #[inline(always)] #[cfg_attr(not(feature = "radix"), allow(dead_code))] const fn min_step_34(bits: usize, is_signed: bool) -> usize { match bits { 8 if is_signed => 1, 8 if !is_signed => 1, 16 if is_signed => 2, 16 if !is_signed => 3, 32 if is_signed => 6, 32 if !is_signed => 6, 64 if is_signed => 12, 64 if !is_signed => 12, 128 if is_signed => 24, 128 if !is_signed => 25, _ => 1, } } #[inline(always)] #[cfg_attr(not(feature = "radix"), allow(dead_code))] const fn max_step_35(bits: usize, is_signed: bool) -> usize { match bits { 8 if is_signed => 2, 8 if !is_signed => 2, 16 if is_signed => 3, 16 if !is_signed => 4, 32 if is_signed => 7, 32 if !is_signed => 7, 64 if is_signed => 13, 64 if !is_signed => 13, 128 if is_signed => 25, 128 if !is_signed => 25, _ => 1, } } #[inline(always)] #[cfg_attr(not(feature = "radix"), allow(dead_code))] const fn min_step_35(bits: usize, is_signed: bool) -> usize { match bits { 8 if is_signed => 1, 8 if !is_signed => 1, 16 if is_signed => 2, 16 if !is_signed => 3, 32 if is_signed => 6, 32 if !is_signed => 6, 64 if is_signed => 12, 64 if !is_signed => 12, 128 if is_signed => 24, 128 if !is_signed => 24, _ => 1, } } #[inline(always)] #[cfg_attr(not(feature = "radix"), allow(dead_code))] const fn max_step_36(bits: usize, is_signed: bool) -> usize { match bits { 8 if is_signed => 2, 8 if !is_signed => 2, 16 if is_signed => 3, 16 if !is_signed => 4, 32 if is_signed => 6, 32 if !is_signed => 7, 64 if is_signed => 13, 64 if !is_signed => 13, 128 if is_signed => 25, 128 if !is_signed => 25, _ => 1, } } #[inline(always)] #[cfg_attr(not(feature = "radix"), allow(dead_code))] const fn min_step_36(bits: usize, is_signed: bool) -> usize { match bits { 8 if is_signed => 1, 8 if !is_signed => 1, 16 if is_signed => 2, 16 if !is_signed => 3, 32 if is_signed => 5, 32 if !is_signed => 6, 64 if is_signed => 12, 64 if !is_signed => 12, 128 if is_signed => 24, 128 if !is_signed => 24, _ => 1, } } lexical-util-1.0.6/tests/algorithm_tests.rs000064400000000000000000000016631046102023000171520ustar 00000000000000#[cfg(feature = "write")] use lexical_util::algorithm; #[test] #[cfg(feature = "write")] fn copy_to_dest_test() { let src = b"12345"; let mut dst = [b'0'; 16]; assert_eq!(5, algorithm::copy_to_dst(&mut dst, src)); assert_eq!(&dst[..5], src); } #[test] #[cfg(feature = "write")] fn ltrim_char_test() { let w = "0001"; let x = "1010"; let y = "1.00"; let z = "1e05"; assert_eq!(algorithm::ltrim_char_count(w.as_bytes(), b'0'), 3); assert_eq!(algorithm::ltrim_char_count(x.as_bytes(), b'0'), 0); assert_eq!(algorithm::ltrim_char_count(x.as_bytes(), b'1'), 1); assert_eq!(algorithm::ltrim_char_count(y.as_bytes(), b'0'), 0); assert_eq!(algorithm::ltrim_char_count(y.as_bytes(), b'1'), 1); assert_eq!(algorithm::ltrim_char_count(z.as_bytes(), b'0'), 0); assert_eq!(algorithm::ltrim_char_count(z.as_bytes(), b'1'), 1); assert_eq!(algorithm::ltrim_char_count(z.as_bytes(), b'5'), 0); } lexical-util-1.0.6/tests/ascii_tests.rs000064400000000000000000000037441046102023000162560ustar 00000000000000use lexical_util::ascii; #[test] fn is_valid_ascii_test() { assert_eq!(ascii::is_valid_ascii(b'\x00'), false); assert_eq!(ascii::is_valid_ascii(b'\n'), true); assert_eq!(ascii::is_valid_ascii(b'\r'), true); assert_eq!(ascii::is_valid_ascii(b'\x1b'), false); assert_eq!(ascii::is_valid_ascii(b' '), true); assert_eq!(ascii::is_valid_ascii(b'0'), true); assert_eq!(ascii::is_valid_ascii(b'9'), true); assert_eq!(ascii::is_valid_ascii(b':'), true); assert_eq!(ascii::is_valid_ascii(b'A'), true); assert_eq!(ascii::is_valid_ascii(b'Z'), true); assert_eq!(ascii::is_valid_ascii(b']'), true); assert_eq!(ascii::is_valid_ascii(b'a'), true); assert_eq!(ascii::is_valid_ascii(b'z'), true); assert_eq!(ascii::is_valid_ascii(b'~'), true); assert_eq!(ascii::is_valid_ascii(b'\x7f'), false); } #[test] fn is_valid_ascii_slice_test() { assert_eq!(ascii::is_valid_ascii_slice(b" 09a"), true); assert_eq!(ascii::is_valid_ascii_slice(b" 09a\x1b"), false); } #[test] fn is_valid_letter_test() { assert_eq!(ascii::is_valid_letter(b'\x00'), false); assert_eq!(ascii::is_valid_letter(b'\n'), false); assert_eq!(ascii::is_valid_letter(b'\r'), false); assert_eq!(ascii::is_valid_letter(b'\x1b'), false); assert_eq!(ascii::is_valid_letter(b' '), false); assert_eq!(ascii::is_valid_letter(b'0'), false); assert_eq!(ascii::is_valid_letter(b'9'), false); assert_eq!(ascii::is_valid_letter(b':'), false); assert_eq!(ascii::is_valid_letter(b'A'), true); assert_eq!(ascii::is_valid_letter(b'Z'), true); assert_eq!(ascii::is_valid_letter(b']'), false); assert_eq!(ascii::is_valid_letter(b'a'), true); assert_eq!(ascii::is_valid_letter(b'z'), true); assert_eq!(ascii::is_valid_letter(b'~'), false); assert_eq!(ascii::is_valid_letter(b'\x7f'), false); } #[test] fn is_valid_letter_slice_test() { assert_eq!(ascii::is_valid_letter_slice(b" 09a"), false); assert_eq!(ascii::is_valid_letter_slice(b"aZAz"), true); } lexical-util-1.0.6/tests/bf16_tests.rs000064400000000000000000000041551046102023000157210ustar 00000000000000#![cfg(feature = "f16")] mod util; use lexical_util::bf16::bf16; use lexical_util::num::Float; use proptest::prelude::*; use crate::util::default_proptest_config; #[test] fn as_f32_test() { assert_eq!(bf16::from_bits(1).as_f32(), 9.18355e-41f32); assert_eq!(bf16::ZERO.as_f32(), 0.0f32); assert_eq!(bf16::ZERO.to_bits(), 0); assert_eq!(bf16::ONE.as_f32(), 1.0f32); assert_eq!(bf16::ONE.to_bits(), (127 << 7)); assert_eq!(bf16::TWO.as_f32(), 2.0f32); assert_eq!(bf16::TWO.to_bits(), (128 << 7)); assert_eq!(bf16::from_bits(126 << 7).as_f32(), 0.5f32); assert!(bf16::NAN.as_f32().is_nan()); assert!(bf16::INFINITY.as_f32().is_inf()); assert!(bf16::NEG_INFINITY.as_f32().is_inf()); } #[test] fn from_f32_test() { assert_eq!(bf16::from_f32(4.5917e-41f32).to_bits(), 0); assert_eq!(bf16::from_f32(4.5918e-41f32).to_bits(), 0); assert_eq!(bf16::from_f32(4.5919e-41f32).to_bits(), 1); assert_eq!(bf16::from_f32(9.18354e-41f32).to_bits(), 1); assert_eq!(bf16::from_f32(9.18355e-41f32).to_bits(), 1); assert_eq!(bf16::from_f32(9.18356e-41f32).to_bits(), 1); assert_eq!(bf16::from_f32(1.37752e-40f32).to_bits(), 1); assert_eq!(bf16::from_f32(1.37753e-40f32).to_bits(), 2); assert_eq!(bf16::from_f32(1.37754e-40f32).to_bits(), 2); assert!(bf16::from_f32(f32::NAN).is_nan()); assert!(bf16::from_f32(f32::INFINITY).is_inf()); assert!(bf16::from_f32(f32::NEG_INFINITY).is_inf()); } #[test] fn math_tests() { assert_eq!(bf16::ONE + bf16::ONE, bf16::TWO); assert_eq!(bf16::ONE * bf16::ONE, bf16::ONE); assert_eq!(bf16::ONE / bf16::ONE, bf16::ONE); assert_eq!(bf16::ONE - bf16::ONE, bf16::ZERO); assert_eq!(bf16::ONE % bf16::ONE, bf16::ZERO); } default_quickcheck! { fn f32_roundtrip_quickcheck(x: u16) -> bool { let f = bf16::from_bits(x).as_f32(); bf16::from_f32(f).to_bits() == x } } proptest! { #![proptest_config(default_proptest_config())] #[test] fn f32_roundtrip_proptest(x in u16::MIN..u16::MAX) { let f = bf16::from_bits(x).as_f32(); prop_assert_eq!(bf16::from_f32(f).to_bits(), x); } } lexical-util-1.0.6/tests/digit_tests.rs000064400000000000000000000062631046102023000162650ustar 00000000000000#![cfg(any(feature = "parse", feature = "write"))] use lexical_util::digit; #[cfg(feature = "parse")] fn char_to_digit(c: u8, radix: u32, expected: Option) { assert_eq!(digit::char_to_digit_const(c, radix), expected); assert_eq!(digit::char_to_digit(c, radix), expected); } #[test] #[cfg(feature = "parse")] fn char_to_digit_test() { char_to_digit(b'0', 2, Some(0)); char_to_digit(b'1', 2, Some(1)); char_to_digit(b'9', 2, None); char_to_digit(b'A', 2, None); char_to_digit(b'Z', 2, None); char_to_digit(b'0', 10, Some(0)); char_to_digit(b'1', 10, Some(1)); char_to_digit(b'9', 10, Some(9)); char_to_digit(b'A', 10, None); char_to_digit(b'Z', 10, None); char_to_digit(b'0', 16, Some(0)); char_to_digit(b'1', 16, Some(1)); char_to_digit(b'9', 16, Some(9)); char_to_digit(b'A', 16, Some(10)); char_to_digit(b'Z', 16, None); // char_to_digit doesn't care about the radix. // check some more comprehensive cases. for c in b'0'..=b'9' { char_to_digit(c, 10, Some(c as u32 - b'0' as u32)); } char_to_digit(0x29, 10, None); char_to_digit(0x3A, 10, None); char_to_digit(0x59, 10, None); for c in b'0'..=b'8' { char_to_digit(c, 9, Some(c as u32 - b'0' as u32)); } char_to_digit(0x29, 9, None); char_to_digit(0x39, 9, None); char_to_digit(0x3A, 9, None); char_to_digit(0x59, 9, None); for c in b'0'..=b'9' { char_to_digit(c, 16, Some(c as u32 - b'0' as u32)); } for c in b'a'..=b'f' { char_to_digit(c, 16, Some(c as u32 - b'a' as u32 + 10)); } for c in b'A'..=b'F' { char_to_digit(c, 16, Some(c as u32 - b'A' as u32 + 10)); } char_to_digit(0x29, 16, None); char_to_digit(0x40, 16, None); char_to_digit(0x3A, 16, None); char_to_digit(0x59, 16, None); char_to_digit(0x41, 16, Some(10)); char_to_digit(0x47, 16, None); char_to_digit(0x5A, 16, None); char_to_digit(0x61, 16, Some(10)); char_to_digit(0x67, 16, None); char_to_digit(0x7A, 16, None); } #[cfg(feature = "parse")] fn char_is_digit(c: u8, radix: u32, expected: bool) { assert_eq!(digit::char_is_digit_const(c, radix), expected); assert_eq!(digit::char_is_digit(c, radix), expected); } #[test] #[cfg(feature = "parse")] fn char_is_digit_const_test() { char_is_digit(b'0', 2, true); char_is_digit(b'1', 2, true); char_is_digit(b'9', 2, false); char_is_digit(b'A', 2, false); char_is_digit(b'Z', 2, false); char_is_digit(b'0', 10, true); char_is_digit(b'1', 10, true); char_is_digit(b'9', 10, true); char_is_digit(b'A', 10, false); char_is_digit(b'Z', 10, false); char_is_digit(b'0', 16, true); char_is_digit(b'1', 16, true); char_is_digit(b'9', 16, true); char_is_digit(b'A', 16, true); char_is_digit(b'Z', 16, false); } #[cfg(feature = "write")] fn digit_to_char(digit: u32, radix: u32, expected: u8) { assert_eq!(digit::digit_to_char_const(digit, radix), expected); assert_eq!(digit::digit_to_char(digit), expected); } #[test] #[cfg(feature = "write")] fn digit_to_char_const_test() { digit_to_char(9, 10, b'9'); digit_to_char(10, 36, b'A'); digit_to_char(11, 36, b'B'); } lexical-util-1.0.6/tests/div128_tests.rs000064400000000000000000000017161046102023000162000ustar 00000000000000#![cfg(not(feature = "compact"))] #![cfg(feature = "write")] mod util; use lexical_util::div128::u128_divrem; use lexical_util::step::u64_step; use proptest::{prop_assert_eq, proptest}; use crate::util::default_proptest_config; proptest! { #![proptest_config(default_proptest_config())] #[test] fn u128_divrem_proptest(i in u128::MIN..u128::MAX) { let (hi, lo) = u128_divrem(i, 10); let step = u64_step(10); let d = 10u128.pow(step as u32); let expected = (i / d, (i % d) as u64); prop_assert_eq!((hi, lo), expected); } #[test] #[cfg(feature = "radix")] fn u128_divrem_radix_proptest(i in u128::MIN..u128::MAX, radix in 2u32..=36) { // Simulate a const expr. let (hi, lo) = u128_divrem(i, radix); let step = u64_step(radix); let d = (radix as u128).pow(step as u32); let expected = (i / d, (i % d) as u64); prop_assert_eq!((hi, lo), expected); } } lexical-util-1.0.6/tests/f16_tests.rs000064400000000000000000000041231046102023000155520ustar 00000000000000#![cfg(feature = "f16")] mod util; use lexical_util::f16::f16; use lexical_util::num::Float; use proptest::prelude::*; use crate::util::default_proptest_config; #[test] fn as_f32_test() { assert_eq!(f16::from_bits(1).as_f32(), 0.000000059604645); assert_eq!(f16::ZERO.as_f32(), 0.0f32); assert_eq!(f16::ZERO.to_bits(), 0); assert_eq!(f16::ONE.as_f32(), 1.0f32); assert_eq!(f16::ONE.to_bits(), (15 << 10)); assert_eq!(f16::TWO.as_f32(), 2.0f32); assert_eq!(f16::TWO.to_bits(), (16 << 10)); assert_eq!(f16::from_bits(14 << 10).as_f32(), 0.5f32); assert!(f16::NAN.as_f32().is_nan()); assert!(f16::INFINITY.as_f32().is_inf()); assert!(f16::NEG_INFINITY.as_f32().is_inf()); } #[test] fn from_f32_test() { assert_eq!(f16::from_f32(2.980232e-08).to_bits(), 0); assert_eq!(f16::from_f32(2.9802322e-08).to_bits(), 0); assert_eq!(f16::from_f32(2.9802326e-08).to_bits(), 1); assert_eq!(f16::from_f32(5.960464e-08).to_bits(), 1); assert_eq!(f16::from_f32(5.9604645e-08).to_bits(), 1); assert_eq!(f16::from_f32(5.960465e-08).to_bits(), 1); assert!(f16::from_f32(f32::NAN).is_nan()); assert!(f16::from_f32(f32::INFINITY).is_inf()); assert!(f16::from_f32(f32::NEG_INFINITY).is_inf()); } #[test] fn math_tests() { assert_eq!(f16::ONE + f16::ONE, f16::TWO); assert_eq!(f16::ONE * f16::ONE, f16::ONE); assert_eq!(f16::ONE / f16::ONE, f16::ONE); assert_eq!(f16::ONE - f16::ONE, f16::ZERO); assert_eq!(f16::ONE % f16::ONE, f16::ZERO); } default_quickcheck! { fn f32_roundtrip_quickcheck(x: u16) -> bool { let f = f16::from_bits(x).as_f32(); if f.is_nan() { f16::from_f32(f).is_nan() } else { f16::from_f32(f).to_bits() == x } } } proptest! { #![proptest_config(default_proptest_config())] #[test] fn f32_roundtrip_proptest(x in u16::MIN..u16::MAX) { let f = f16::from_bits(x).as_f32(); if f.is_nan() { prop_assert!(f16::from_f32(f).is_nan()); } else { prop_assert_eq!(f16::from_f32(f).to_bits(), x); } } } lexical-util-1.0.6/tests/feature_format_tests.rs000064400000000000000000000250071046102023000201650ustar 00000000000000#![cfg(feature = "format")] use core::num; use lexical_util::format; #[test] fn ignore_test() { let fmt = format::NumberFormat::<{ format::IGNORE }> {}; assert_eq!(fmt.flags(), format::DIGIT_SEPARATOR_FLAG_MASK); assert_eq!(fmt.digit_separator(), b'_'); assert_eq!(fmt.required_integer_digits(), false); assert_eq!(fmt.required_fraction_digits(), false); assert_eq!(fmt.required_exponent_digits(), false); assert_eq!(fmt.required_mantissa_digits(), false); assert_eq!(fmt.required_digits(), false); assert_eq!(fmt.no_positive_mantissa_sign(), false); assert_eq!(fmt.required_mantissa_sign(), false); assert_eq!(fmt.no_exponent_notation(), false); assert_eq!(fmt.no_positive_exponent_sign(), false); assert_eq!(fmt.required_exponent_sign(), false); assert_eq!(fmt.no_exponent_without_fraction(), false); assert_eq!(fmt.no_special(), false); assert_eq!(fmt.case_sensitive_special(), false); assert_eq!(fmt.no_integer_leading_zeros(), false); assert_eq!(fmt.no_float_leading_zeros(), false); assert_eq!(fmt.required_exponent_notation(), false); assert_eq!(fmt.case_sensitive_exponent(), false); #[cfg(feature = "power-of-two")] assert_eq!(fmt.case_sensitive_base_prefix(), false); #[cfg(feature = "power-of-two")] assert_eq!(fmt.case_sensitive_base_suffix(), false); assert_eq!(fmt.integer_internal_digit_separator(), true); assert_eq!(fmt.fraction_internal_digit_separator(), true); assert_eq!(fmt.exponent_internal_digit_separator(), true); assert_eq!(fmt.internal_digit_separator(), true); assert_eq!(fmt.integer_leading_digit_separator(), true); assert_eq!(fmt.fraction_leading_digit_separator(), true); assert_eq!(fmt.exponent_leading_digit_separator(), true); assert_eq!(fmt.leading_digit_separator(), true); assert_eq!(fmt.integer_trailing_digit_separator(), true); assert_eq!(fmt.fraction_trailing_digit_separator(), true); assert_eq!(fmt.exponent_trailing_digit_separator(), true); assert_eq!(fmt.trailing_digit_separator(), true); assert_eq!(fmt.integer_consecutive_digit_separator(), true); assert_eq!(fmt.fraction_consecutive_digit_separator(), true); assert_eq!(fmt.exponent_consecutive_digit_separator(), true); assert_eq!(fmt.consecutive_digit_separator(), true); assert_eq!(fmt.special_digit_separator(), true); } fn test_flag() { let fmt = format::NumberFormat:: {}; assert_eq!(fmt.flags(), FORMAT); assert_eq!(fmt.digit_separator(), 0); } macro_rules! test_flag { ($field:ident, $flag:ident) => {{ test_flag::<{ format::$flag }>(); if format::$flag & format::CONSECUTIVE_DIGIT_SEPARATOR == 0 { const FORMAT: u128 = format::NumberFormatBuilder::new() .digit_separator(num::NonZeroU8::new(b'_')) .$field(true) .build(); let fmt = format::NumberFormat:: {}; assert_eq!(fmt.is_valid(), true); assert_eq!(fmt.$field(), true); } else { const FORMAT: u128 = format::NumberFormatBuilder::new() .digit_separator(num::NonZeroU8::new(b'_')) .internal_digit_separator(true) .leading_digit_separator(true) .trailing_digit_separator(true) .$field(true) .build(); let fmt = format::NumberFormat:: {}; assert_eq!(fmt.is_valid(), true); assert_eq!(fmt.$field(), true); } }}; } #[test] fn flags_test() { test_flag!(required_integer_digits, REQUIRED_INTEGER_DIGITS); test_flag!(required_fraction_digits, REQUIRED_FRACTION_DIGITS); test_flag!(required_exponent_digits, REQUIRED_EXPONENT_DIGITS); test_flag!(required_mantissa_digits, REQUIRED_MANTISSA_DIGITS); test_flag!(no_positive_mantissa_sign, NO_POSITIVE_MANTISSA_SIGN); test_flag!(required_mantissa_sign, REQUIRED_MANTISSA_SIGN); test_flag!(no_exponent_notation, NO_EXPONENT_NOTATION); test_flag!(no_positive_exponent_sign, NO_POSITIVE_EXPONENT_SIGN); test_flag!(required_exponent_sign, REQUIRED_EXPONENT_SIGN); test_flag!(no_exponent_without_fraction, NO_EXPONENT_WITHOUT_FRACTION); test_flag!(no_special, NO_SPECIAL); test_flag!(case_sensitive_special, CASE_SENSITIVE_SPECIAL); test_flag!(no_integer_leading_zeros, NO_INTEGER_LEADING_ZEROS); test_flag!(no_float_leading_zeros, NO_FLOAT_LEADING_ZEROS); test_flag!(required_exponent_notation, REQUIRED_EXPONENT_NOTATION); test_flag!(case_sensitive_exponent, CASE_SENSITIVE_EXPONENT); #[cfg(feature = "power-of-two")] test_flag!(case_sensitive_base_prefix, CASE_SENSITIVE_BASE_PREFIX); #[cfg(feature = "power-of-two")] test_flag!(case_sensitive_base_suffix, CASE_SENSITIVE_BASE_SUFFIX); test_flag!(integer_internal_digit_separator, INTEGER_INTERNAL_DIGIT_SEPARATOR); test_flag!(fraction_internal_digit_separator, FRACTION_INTERNAL_DIGIT_SEPARATOR); test_flag!(exponent_internal_digit_separator, EXPONENT_INTERNAL_DIGIT_SEPARATOR); test_flag!(integer_leading_digit_separator, INTEGER_LEADING_DIGIT_SEPARATOR); test_flag!(fraction_leading_digit_separator, FRACTION_LEADING_DIGIT_SEPARATOR); test_flag!(exponent_leading_digit_separator, EXPONENT_LEADING_DIGIT_SEPARATOR); test_flag!(integer_trailing_digit_separator, INTEGER_TRAILING_DIGIT_SEPARATOR); test_flag!(fraction_trailing_digit_separator, FRACTION_TRAILING_DIGIT_SEPARATOR); test_flag!(exponent_trailing_digit_separator, EXPONENT_TRAILING_DIGIT_SEPARATOR); test_flag!(integer_consecutive_digit_separator, INTEGER_CONSECUTIVE_DIGIT_SEPARATOR); test_flag!(fraction_consecutive_digit_separator, FRACTION_CONSECUTIVE_DIGIT_SEPARATOR); test_flag!(exponent_consecutive_digit_separator, EXPONENT_CONSECUTIVE_DIGIT_SEPARATOR); test_flag!(special_digit_separator, SPECIAL_DIGIT_SEPARATOR); } #[test] fn constants_test() { // Don't check the actual values: just check they're defined. let _: u128 = format::RUST_LITERAL; let _: u128 = format::RUST_STRING; let _: u128 = format::PYTHON_LITERAL; let _: u128 = format::PYTHON_STRING; let _: u128 = format::PYTHON3_LITERAL; let _: u128 = format::PYTHON3_STRING; let _: u128 = format::PYTHON36_LITERAL; let _: u128 = format::PYTHON35_LITERAL; let _: u128 = format::PYTHON2_LITERAL; let _: u128 = format::PYTHON2_STRING; let _: u128 = format::CXX17_LITERAL; let _: u128 = format::CXX17_STRING; let _: u128 = format::CXX14_LITERAL; let _: u128 = format::CXX14_STRING; let _: u128 = format::CXX11_LITERAL; let _: u128 = format::CXX11_STRING; let _: u128 = format::CXX03_LITERAL; let _: u128 = format::CXX03_STRING; let _: u128 = format::CXX98_LITERAL; let _: u128 = format::CXX98_STRING; let _: u128 = format::C18_LITERAL; let _: u128 = format::C18_STRING; let _: u128 = format::C11_LITERAL; let _: u128 = format::C11_STRING; let _: u128 = format::C99_LITERAL; let _: u128 = format::C99_STRING; let _: u128 = format::C90_LITERAL; let _: u128 = format::C90_STRING; let _: u128 = format::C89_LITERAL; let _: u128 = format::C89_STRING; let _: u128 = format::RUBY_LITERAL; let _: u128 = format::RUBY_STRING; let _: u128 = format::SWIFT_LITERAL; let _: u128 = format::SWIFT_STRING; let _: u128 = format::GO_LITERAL; let _: u128 = format::GO_STRING; let _: u128 = format::HASKELL_LITERAL; let _: u128 = format::HASKELL_STRING; let _: u128 = format::JAVASCRIPT_LITERAL; let _: u128 = format::JAVASCRIPT_STRING; let _: u128 = format::PERL_LITERAL; let _: u128 = format::PERL_STRING; let _: u128 = format::PHP_LITERAL; let _: u128 = format::PHP_STRING; let _: u128 = format::JAVA_LITERAL; let _: u128 = format::JAVA_STRING; let _: u128 = format::R_LITERAL; let _: u128 = format::R_STRING; let _: u128 = format::KOTLIN_LITERAL; let _: u128 = format::KOTLIN_STRING; let _: u128 = format::JULIA_LITERAL; let _: u128 = format::JULIA_STRING; let _: u128 = format::CSHARP7_LITERAL; let _: u128 = format::CSHARP7_STRING; let _: u128 = format::CSHARP6_LITERAL; let _: u128 = format::CSHARP6_STRING; let _: u128 = format::CSHARP5_LITERAL; let _: u128 = format::CSHARP5_STRING; let _: u128 = format::CSHARP4_LITERAL; let _: u128 = format::CSHARP4_STRING; let _: u128 = format::CSHARP3_LITERAL; let _: u128 = format::CSHARP3_STRING; let _: u128 = format::CSHARP2_LITERAL; let _: u128 = format::CSHARP2_STRING; let _: u128 = format::CSHARP1_LITERAL; let _: u128 = format::CSHARP1_STRING; let _: u128 = format::KAWA_LITERAL; let _: u128 = format::KAWA_STRING; let _: u128 = format::GAMBITC_LITERAL; let _: u128 = format::GAMBITC_STRING; let _: u128 = format::GUILE_LITERAL; let _: u128 = format::GUILE_STRING; let _: u128 = format::CLOJURE_LITERAL; let _: u128 = format::CLOJURE_STRING; let _: u128 = format::ERLANG_LITERAL; let _: u128 = format::ERLANG_STRING; let _: u128 = format::ELM_LITERAL; let _: u128 = format::ELM_STRING; let _: u128 = format::SCALA_LITERAL; let _: u128 = format::SCALA_STRING; let _: u128 = format::ELIXIR_LITERAL; let _: u128 = format::ELIXIR_STRING; let _: u128 = format::FORTRAN_LITERAL; let _: u128 = format::FORTRAN_STRING; let _: u128 = format::D_LITERAL; let _: u128 = format::D_STRING; let _: u128 = format::COFFEESCRIPT_LITERAL; let _: u128 = format::COFFEESCRIPT_STRING; let _: u128 = format::COBOL_LITERAL; let _: u128 = format::COBOL_STRING; let _: u128 = format::FSHARP_LITERAL; let _: u128 = format::FSHARP_STRING; let _: u128 = format::VB_LITERAL; let _: u128 = format::VB_STRING; let _: u128 = format::OCAML_LITERAL; let _: u128 = format::OCAML_STRING; let _: u128 = format::OBJECTIVEC_LITERAL; let _: u128 = format::OBJECTIVEC_STRING; let _: u128 = format::REASONML_LITERAL; let _: u128 = format::REASONML_STRING; let _: u128 = format::OCTAVE_LITERAL; let _: u128 = format::OCTAVE_STRING; let _: u128 = format::MATLAB_LITERAL; let _: u128 = format::MATLAB_STRING; let _: u128 = format::ZIG_LITERAL; let _: u128 = format::ZIG_STRING; let _: u128 = format::SAGE_LITERAL; let _: u128 = format::SAGE_STRING; let _: u128 = format::JSON; let _: u128 = format::TOML; let _: u128 = format::YAML; let _: u128 = format::XML; let _: u128 = format::SQLITE; let _: u128 = format::POSTGRESQL; let _: u128 = format::MYSQL; let _: u128 = format::MONGODB; } lexical-util-1.0.6/tests/format_builder_tests.rs000064400000000000000000000035131046102023000201560ustar 00000000000000use lexical_util::format::{NumberFormat, NumberFormatBuilder}; #[test] fn decimal_test() { const FORMAT: u128 = NumberFormatBuilder::decimal(); let format = NumberFormat:: {}; assert!(format.is_valid()); assert_eq!(format.radix(), 10); assert_eq!(format.mantissa_radix(), 10); assert_eq!(format.exponent_base(), 10); assert_eq!(format.exponent_radix(), 10); } #[test] #[cfg(feature = "power-of-two")] fn binary_test() { const FORMAT: u128 = NumberFormatBuilder::binary(); let format = NumberFormat:: {}; assert!(format.is_valid()); assert_eq!(format.radix(), 2); assert_eq!(format.mantissa_radix(), 2); assert_eq!(format.exponent_base(), 2); assert_eq!(format.exponent_radix(), 2); } #[test] #[cfg(feature = "power-of-two")] fn octal_test() { const FORMAT: u128 = NumberFormatBuilder::octal(); let format = NumberFormat:: {}; assert!(format.is_valid()); assert_eq!(format.radix(), 8); assert_eq!(format.mantissa_radix(), 8); assert_eq!(format.exponent_base(), 8); assert_eq!(format.exponent_radix(), 8); } #[test] #[cfg(feature = "power-of-two")] fn hexadecimal_test() { const FORMAT: u128 = NumberFormatBuilder::hexadecimal(); let format = NumberFormat:: {}; assert!(format.is_valid()); assert_eq!(format.radix(), 16); assert_eq!(format.mantissa_radix(), 16); assert_eq!(format.exponent_base(), 16); assert_eq!(format.exponent_radix(), 16); } #[test] #[cfg(feature = "power-of-two")] fn from_radix_test() { const FORMAT: u128 = NumberFormatBuilder::from_radix(32); let format = NumberFormat:: {}; assert!(format.is_valid()); assert_eq!(format.radix(), 32); assert_eq!(format.mantissa_radix(), 32); assert_eq!(format.exponent_base(), 32); assert_eq!(format.exponent_radix(), 32); } lexical-util-1.0.6/tests/format_flags_tests.rs000064400000000000000000000040201046102023000176160ustar 00000000000000#[cfg(feature = "format")] use core::num; #[cfg(feature = "format")] use lexical_util::format; #[cfg(feature = "format")] const fn from_digit_separator(digit_separator: u8) -> u128 { format::NumberFormatBuilder::new() .digit_separator(num::NonZeroU8::new(digit_separator)) .digit_separator_flags(true) .build() } #[cfg(feature = "format")] fn is_valid_digit_separator(digit_separator: u8) -> bool { let format = from_digit_separator(digit_separator); format::is_valid_digit_separator(format) } #[test] #[cfg(feature = "format")] fn test_is_valid_digit_separator() { assert_eq!(is_valid_digit_separator(b'_'), true); assert_eq!(is_valid_digit_separator(b'\''), true); assert_eq!(is_valid_digit_separator(b'.'), true); assert_eq!(is_valid_digit_separator(b'e'), true); assert_eq!(is_valid_digit_separator(b'0'), false); assert_eq!(is_valid_digit_separator(128), false); // Try with a custom radix. #[cfg(feature = "radix")] { let format = format::NumberFormat::<{ from_digit_separator(b'e') }>::rebuild().radix(16).build(); assert_eq!(format::is_valid_digit_separator(format), false); } } #[cfg(all(feature = "power-of-two", feature = "format"))] fn is_valid_punctuation(digit_separator: u8, base_prefix: u8, base_suffix: u8) -> bool { let fmt = format::NumberFormatBuilder::new() .digit_separator(num::NonZeroU8::new(digit_separator)) .digit_separator_flags(true) .base_prefix(num::NonZeroU8::new(base_prefix)) .base_suffix(num::NonZeroU8::new(base_suffix)) .build(); format::is_valid_punctuation(fmt) } #[test] #[cfg(all(feature = "power-of-two", feature = "format"))] fn test_is_valid_punctuation() { assert_eq!(is_valid_punctuation(b'_', b'h', 0), true); assert_eq!(is_valid_punctuation(b'e', b'h', 0), true); assert_eq!(is_valid_punctuation(b'^', b'h', 0), true); assert_eq!(is_valid_punctuation(b'\'', b'h', 0), true); assert_eq!(is_valid_punctuation(b'\'', b'h', b'h'), false); } lexical-util-1.0.6/tests/iterator_tests.rs000064400000000000000000000075551046102023000170230ustar 00000000000000#![cfg(feature = "parse")] use lexical_util::iterator::{AsBytes, Bytes, DigitsIter, Iter}; #[test] #[cfg(not(feature = "format"))] fn digits_iterator_test() { use lexical_util::format::STANDARD; type Digits<'a> = Bytes<'a, { STANDARD }>; assert!(Digits::IS_CONTIGUOUS); let digits = b"12345"; let mut byte1 = Digits::new(digits); let mut byte2 = Digits::new(digits); assert!(byte1.integer_iter().eq(byte2.integer_iter())); let mut byte = digits.bytes::<{ STANDARD }>(); let mut iter = byte.integer_iter(); assert_eq!(iter.as_slice(), &digits[..]); assert_eq!(iter.as_ptr(), digits.as_ptr()); assert_eq!(iter.is_consumed(), false); assert_eq!(iter.is_buffer_empty(), false); assert_eq!(u32::from_le(iter.peek_u32().unwrap()), 0x34333231); assert_eq!(iter.buffer_length(), 5); assert_eq!(iter.cursor(), 0); assert_eq!(iter.current_count(), 0); unsafe { iter.step_by_unchecked(4); } assert_eq!(iter.buffer_length(), 5); assert_eq!(iter.cursor(), 4); assert_eq!(iter.current_count(), 4); assert_eq!(iter.peek(), Some(&b'5')); assert_eq!(iter.peek(), Some(&b'5')); assert_eq!(iter.next(), Some(&b'5')); assert_eq!(iter.peek(), None); assert_eq!(iter.next(), None); let mut byte = digits.bytes::<{ STANDARD }>(); let mut iter = byte.integer_iter(); assert_eq!(iter.peek_u64(), None); assert_eq!(iter.nth(4).unwrap(), &b'5'); assert_eq!(iter.as_slice(), &digits[digits.len()..]); assert_eq!(iter.as_ptr(), digits[digits.len()..].as_ptr()); let mut byte = digits.bytes::<{ STANDARD }>(); let mut iter = byte.integer_iter(); assert_eq!(iter.peek(), Some(&b'1')); unsafe { iter.step_unchecked(); } assert_eq!(iter.peek(), Some(&b'2')); unsafe { iter.step_unchecked(); } } #[test] #[cfg(feature = "format")] fn skip_iterator_test() { use core::num; use lexical_util::format::{NumberFormat, NumberFormatBuilder}; use static_assertions::const_assert; pub const FORMAT: u128 = NumberFormatBuilder::new() .digit_separator(num::NonZeroU8::new(b'_')) .digit_separator_flags(true) .build(); const_assert!(NumberFormat::<{ FORMAT }> {}.is_valid()); type Digits<'a> = Bytes<'a, { FORMAT }>; assert!(!Digits::IS_CONTIGUOUS); let digits = b"123_45"; let mut byte1 = Digits::new(digits); let mut byte2 = Digits::new(digits); assert!(byte1.integer_iter().eq(byte2.integer_iter())); let mut byte = digits.bytes::<{ FORMAT }>(); let mut iter = byte.integer_iter(); assert_eq!(iter.as_slice(), &digits[..]); assert_eq!(iter.as_ptr(), digits.as_ptr()); assert_eq!(iter.is_consumed(), false); assert_eq!(iter.is_buffer_empty(), false); assert_eq!(iter.buffer_length(), 6); assert_eq!(iter.cursor(), 0); assert_eq!(iter.current_count(), 0); unsafe { iter.step_unchecked() }; assert_eq!(iter.cursor(), 1); assert_eq!(iter.current_count(), 0); iter.next(); assert_eq!(iter.cursor(), 2); assert_eq!(iter.current_count(), 1); let mut byte = digits.bytes::<{ FORMAT }>(); let mut iter = byte.integer_iter(); assert_eq!(iter.peek(), Some(&b'1')); assert_eq!(iter.peek(), Some(&b'1')); assert_eq!(iter.next(), Some(&b'1')); assert_eq!(iter.next(), Some(&b'2')); assert_eq!(iter.next(), Some(&b'3')); assert_eq!(iter.cursor(), 3); assert_eq!(iter.current_count(), 3); assert_eq!(iter.next(), Some(&b'4')); assert_eq!(iter.cursor(), 5); assert_eq!(iter.current_count(), 4); assert_eq!(iter.next(), Some(&b'5')); assert_eq!(iter.next(), None); let mut byte = digits.bytes::<{ FORMAT }>(); let mut iter = byte.integer_iter(); assert_eq!(iter.nth(4).unwrap(), &b'5'); assert_eq!(iter.as_slice(), &digits[digits.len()..]); assert_eq!(iter.as_ptr(), digits[digits.len()..].as_ptr()); } lexical-util-1.0.6/tests/mul_tests.rs000064400000000000000000000025501046102023000157550ustar 00000000000000mod util; use lexical_util::mul::{mul, mulhi}; default_quickcheck! { fn mul_u16_quickcheck(x: u16, y: u16) -> bool { let (hi, lo) = mul::(x, y); let hi = hi as u32; let lo = lo as u32; let expected = x as u32 * y as u32; ((hi << 16) | lo) == expected } fn mul_u32_quickcheck(x: u32, y: u32) -> bool { let (hi, lo) = mul::(x, y); let hi = hi as u64; let lo = lo as u64; let expected = x as u64 * y as u64; ((hi << 32) | lo) == expected } fn mul_u64_quickcheck(x: u64, y: u64) -> bool { let (hi, lo) = mul::(x, y); let hi = hi as u128; let lo = lo as u128; let expected = x as u128 * y as u128; ((hi << 64) | lo) == expected } fn mulhi_u16_quickcheck(x: u16, y: u16) -> bool { let actual = mulhi::(x, y); let expected = (x as u32 * y as u32) >> 16; actual == expected as u16 } fn mulhi_u32_quickcheck(x: u32, y: u32) -> bool { let actual = mulhi::(x, y); let expected = (x as u64 * y as u64) >> 32; actual == expected as u32 } fn mulhi_u64_quickcheck(x: u64, y: u64) -> bool { let actual = mulhi::(x, y); let expected = (x as u128 * y as u128) >> 64; actual == expected as u64 } } lexical-util-1.0.6/tests/not_feature_format_tests.rs000064400000000000000000000053751046102023000210530ustar 00000000000000#![cfg(not(feature = "format"))] use lexical_util::format::{self, NumberFormat, STANDARD}; #[test] fn format_properties_test() { let format = NumberFormat::<{ STANDARD }> {}; assert_eq!(format.flags(), STANDARD & format::FLAG_MASK); assert_eq!(format.interface_flags(), STANDARD & format::INTERFACE_FLAG_MASK); assert_eq!(format.digit_separator(), b'\x00'); assert_eq!(format.base_prefix(), b'\x00'); assert_eq!(format.base_suffix(), b'\x00'); assert_eq!(format.mantissa_radix(), 10); assert_eq!(format.radix(), 10); assert_eq!(format.exponent_base(), 10); assert_eq!(format.exponent_radix(), 10); assert_eq!(format.required_integer_digits(), false); assert_eq!(format.required_fraction_digits(), false); assert_eq!(format.required_exponent_digits(), true); assert_eq!(format.required_mantissa_digits(), true); assert_eq!(format.required_digits(), true); assert_eq!(format.no_positive_mantissa_sign(), false); assert_eq!(format.required_mantissa_sign(), false); assert_eq!(format.no_exponent_notation(), false); assert_eq!(format.no_positive_exponent_sign(), false); assert_eq!(format.required_exponent_sign(), false); assert_eq!(format.no_exponent_without_fraction(), false); assert_eq!(format.no_special(), false); assert_eq!(format.case_sensitive_special(), false); assert_eq!(format.no_integer_leading_zeros(), false); assert_eq!(format.no_float_leading_zeros(), false); assert_eq!(format.required_exponent_notation(), false); assert_eq!(format.case_sensitive_exponent(), false); assert_eq!(format.case_sensitive_base_prefix(), false); assert_eq!(format.case_sensitive_base_suffix(), false); assert_eq!(format.integer_internal_digit_separator(), false); assert_eq!(format.fraction_internal_digit_separator(), false); assert_eq!(format.exponent_internal_digit_separator(), false); assert_eq!(format.internal_digit_separator(), false); assert_eq!(format.integer_leading_digit_separator(), false); assert_eq!(format.fraction_leading_digit_separator(), false); assert_eq!(format.exponent_leading_digit_separator(), false); assert_eq!(format.leading_digit_separator(), false); assert_eq!(format.integer_trailing_digit_separator(), false); assert_eq!(format.fraction_trailing_digit_separator(), false); assert_eq!(format.exponent_trailing_digit_separator(), false); assert_eq!(format.trailing_digit_separator(), false); assert_eq!(format.integer_consecutive_digit_separator(), false); assert_eq!(format.fraction_consecutive_digit_separator(), false); assert_eq!(format.exponent_consecutive_digit_separator(), false); assert_eq!(format.consecutive_digit_separator(), false); assert_eq!(format.special_digit_separator(), false); } lexical-util-1.0.6/tests/num_tests.rs000064400000000000000000000137241046102023000157640ustar 00000000000000use lexical_util::num; fn as_primitive(t: T) { let _: u8 = t.as_u8(); let _: u16 = t.as_u16(); let _: u32 = t.as_u32(); let _: u64 = t.as_u64(); let _: u128 = t.as_u128(); let _: usize = t.as_usize(); let _: i8 = t.as_i8(); let _: i16 = t.as_i16(); let _: i32 = t.as_i32(); let _: i64 = t.as_i64(); let _: i128 = t.as_i128(); let _: isize = t.as_isize(); let _: f32 = t.as_f32(); let _: f64 = t.as_f64(); } #[test] fn as_primitive_test() { as_primitive(1u8); as_primitive(1u16); as_primitive(1u32); as_primitive(1u64); as_primitive(1u128); as_primitive(1usize); as_primitive(1i8); as_primitive(1i16); as_primitive(1i32); as_primitive(1i64); as_primitive(1i128); as_primitive(1isize); as_primitive(1f32); as_primitive(1f64); } fn as_cast(t: T) { let _: i8 = num::as_cast(t); let _: i16 = num::as_cast(t); let _: i32 = num::as_cast(t); let _: i64 = num::as_cast(t); let _: i128 = num::as_cast(t); let _: isize = num::as_cast(t); let _: u8 = num::as_cast(t); let _: u16 = num::as_cast(t); let _: u32 = num::as_cast(t); let _: u64 = num::as_cast(t); let _: u128 = num::as_cast(t); let _: usize = num::as_cast(t); let _: f32 = num::as_cast(t); let _: f64 = num::as_cast(t); } #[test] fn as_cast_test() { as_cast(1u8); as_cast(1u16); as_cast(1u32); as_cast(1u64); as_cast(1u128); as_cast(1usize); as_cast(1i8); as_cast(1i16); as_cast(1i32); as_cast(1i64); as_cast(1i128); as_cast(1isize); as_cast(1f32); as_cast(1f64); } fn check_number(x: T, mut y: T) { // Copy, partialeq, partialord let _ = x; assert!(x < y); assert!(x != y); // Operations let _ = y + x; let _ = y - x; let _ = y * x; let _ = y / x; let _ = y % x; y += x; y -= x; y *= x; y /= x; y %= x; // Conversions already tested. } #[test] fn number_test() { check_number(1u8, 5); check_number(1u16, 5); check_number(1u32, 5); check_number(1u64, 5); check_number(1u128, 5); check_number(1usize, 5); check_number(1i8, 5); check_number(1i16, 5); check_number(1i32, 5); check_number(1i64, 5); check_number(1i128, 5); check_number(1isize, 5); check_number(1f32, 5.0); check_number(1f64, 5.0); } fn check_integer(mut x: T) { // Copy, partialeq, partialord, ord, eq let _ = x; assert!(x > T::ONE); assert!(x != T::ONE); assert_eq!(x.min(T::ONE), T::ONE); assert_eq!(x.max(T::ONE), x); // Operations let _ = x + T::ONE; let _ = x - T::ONE; let _ = x * T::ONE; let _ = x / T::ONE; let _ = x % T::ONE; x += T::ONE; x -= T::ONE; x *= T::ONE; x /= T::ONE; x %= T::ONE; // Bitwise operations let _ = x & T::ONE; let _ = x | T::ONE; let _ = x ^ T::ONE; x &= T::ONE; x |= T::ONE; x ^= T::ONE; // Bit shifts let _ = x << 1i32; let _ = x >> 1i32; x <<= 1i32; x >>= 1i32; // Conversions already tested. } #[test] fn integer_test() { check_integer(65u8); check_integer(65u16); check_integer(65u32); check_integer(65u64); check_integer(65u128); check_integer(65usize); check_integer(65i8); check_integer(65i16); check_integer(65i32); check_integer(65i64); check_integer(65i128); check_integer(65isize); } #[test] fn ceil_divmod_test() { use lexical_util::num::Integer; assert_eq!(5usize.ceil_divmod(7), (1, -2)); assert_eq!(0usize.ceil_divmod(7), (0, 0)); assert_eq!(35usize.ceil_divmod(7), (5, 0)); assert_eq!(36usize.ceil_divmod(7), (6, -6)); } #[cfg(feature = "floats")] fn check_float(mut x: T) { // Copy, partialeq, partialord let _ = x; assert!(x > T::ONE); assert!(x != T::ONE); // Operations let _ = x + T::ONE; let _ = x - T::ONE; let _ = x * T::ONE; let _ = x / T::ONE; let _ = x % T::ONE; let _ = -x; x += T::ONE; x -= T::ONE; x *= T::ONE; x /= T::ONE; x %= T::ONE; // Check functions let _ = x.to_bits(); assert_eq!(T::from_bits(x.to_bits()), x); let _ = x.is_sign_positive(); let _ = x.is_sign_negative(); let _ = x.ln(); let _ = x.floor(); // Check properties let _ = x.to_bits() & T::SIGN_MASK; let _ = x.to_bits() & T::EXPONENT_MASK; let _ = x.to_bits() & T::HIDDEN_BIT_MASK; let _ = x.to_bits() & T::MANTISSA_MASK; assert!(T::from_bits(T::INFINITY_BITS).is_special()); } #[test] #[cfg(feature = "floats")] fn float_test() { use lexical_util::num::Float; check_float(123f32); check_float(123f64); // b00000000000000000000000000000001 let f: f32 = 1e-45; assert!(f.is_odd()); assert!(f.next().is_even()); assert!(f.next_positive().is_even()); assert!(f.prev().is_even()); assert!(f.prev_positive().is_even()); assert!(f.round_positive_even().is_even()); assert_eq!(f.prev().next(), f); assert_eq!(f.prev_positive().next_positive(), f); assert_eq!(f.round_positive_even(), f.next()); // b00111101110011001100110011001101 let f: f32 = 0.1; assert!(f.is_odd()); assert!(f.next().is_even()); assert!(f.next_positive().is_even()); assert!(f.prev().is_even()); assert!(f.prev_positive().is_even()); assert!(f.round_positive_even().is_even()); assert_eq!(f.prev().next(), f); assert_eq!(f.prev_positive().next_positive(), f); assert_eq!(f.round_positive_even(), f.next()); // b01000000000000000000000000000000 let f: f32 = 1.0; assert!(f.is_even()); assert!(f.next().is_odd()); assert!(f.next_positive().is_odd()); assert!(f.prev().is_odd()); assert!(f.prev_positive().is_odd()); assert!(f.round_positive_even().is_even()); assert_eq!(f.prev().next(), f); assert_eq!(f.prev_positive().next_positive(), f); assert_ne!(f.round_positive_even(), f.next()); } lexical-util-1.0.6/tests/skip_tests.rs000064400000000000000000000662131046102023000161340ustar 00000000000000#![cfg(all(feature = "format", feature = "parse"))] use core::num; use lexical_util::format::{NumberFormat, NumberFormatBuilder}; use lexical_util::iterator::AsBytes; use static_assertions::const_assert; fn skip_iter_eq(input: &[u8], output: &[u8]) { // next is done in terms of peek, so we're safe here. let mut input = input.bytes::<{ FORMAT }>(); let mut output = output.bytes::<{ FORMAT }>(); assert!(input.integer_iter().eq(output.integer_iter())); } #[test] fn test_skip_iter_i() { // Test iterators that skip single, internal-only digit separators. pub const FORMAT: u128 = NumberFormatBuilder::new() .digit_separator(num::NonZeroU8::new(b'_')) .integer_internal_digit_separator(true) .build(); const_assert!(NumberFormat::<{ FORMAT }> {}.is_valid()); skip_iter_eq::<{ FORMAT }>(b"123.45", b"123.45"); skip_iter_eq::<{ FORMAT }>(b"1e45", b"1e45"); skip_iter_eq::<{ FORMAT }>(b"1e", b"1e"); skip_iter_eq::<{ FORMAT }>(b"1", b"1"); skip_iter_eq::<{ FORMAT }>(b"_45", b"_45"); skip_iter_eq::<{ FORMAT }>(b"__45", b"__45"); skip_iter_eq::<{ FORMAT }>(b"_.45", b"_.45"); skip_iter_eq::<{ FORMAT }>(b"__.45", b"__.45"); skip_iter_eq::<{ FORMAT }>(b"4_5", b"45"); skip_iter_eq::<{ FORMAT }>(b"4__5", b"4__5"); skip_iter_eq::<{ FORMAT }>(b"4_", b"4_"); skip_iter_eq::<{ FORMAT }>(b"4__", b"4__"); skip_iter_eq::<{ FORMAT }>(b"4_.", b"4_."); skip_iter_eq::<{ FORMAT }>(b"4__.", b"4__."); skip_iter_eq::<{ FORMAT }>(b"_45_5", b"_455"); skip_iter_eq::<{ FORMAT }>(b"__45__5", b"__45__5"); skip_iter_eq::<{ FORMAT }>(b"_.45_5", b"_.455"); skip_iter_eq::<{ FORMAT }>(b"__.45__5", b"__.45__5"); skip_iter_eq::<{ FORMAT }>(b"4_5_", b"45_"); skip_iter_eq::<{ FORMAT }>(b"4__5__", b"4__5__"); skip_iter_eq::<{ FORMAT }>(b"4_5_.5", b"45_.5"); skip_iter_eq::<{ FORMAT }>(b"4__5__.5", b"4__5__.5"); skip_iter_eq::<{ FORMAT }>(b"_45_", b"_45_"); skip_iter_eq::<{ FORMAT }>(b"__45__", b"__45__"); skip_iter_eq::<{ FORMAT }>(b"_45_.56", b"_45_.56"); skip_iter_eq::<{ FORMAT }>(b"__45__.56", b"__45__.56"); skip_iter_eq::<{ FORMAT }>(b"_4_5_", b"_45_"); skip_iter_eq::<{ FORMAT }>(b"__4__5__", b"__4__5__"); skip_iter_eq::<{ FORMAT }>(b"_4_5_.56", b"_45_.56"); skip_iter_eq::<{ FORMAT }>(b"__4__5__.56", b"__4__5__.56"); } #[test] fn test_skip_iter_l() { // Test iterators that skip single, leading-only digit separators. pub const FORMAT: u128 = NumberFormatBuilder::new() .digit_separator(num::NonZeroU8::new(b'_')) .integer_leading_digit_separator(true) .build(); const_assert!(NumberFormat::<{ FORMAT }> {}.is_valid()); skip_iter_eq::<{ FORMAT }>(b"123.45", b"123.45"); skip_iter_eq::<{ FORMAT }>(b"1e45", b"1e45"); skip_iter_eq::<{ FORMAT }>(b"1e", b"1e"); skip_iter_eq::<{ FORMAT }>(b"1", b"1"); skip_iter_eq::<{ FORMAT }>(b"_45", b"45"); skip_iter_eq::<{ FORMAT }>(b"__45", b"__45"); skip_iter_eq::<{ FORMAT }>(b"_.45", b".45"); skip_iter_eq::<{ FORMAT }>(b"__.45", b"__.45"); skip_iter_eq::<{ FORMAT }>(b"4_5", b"4_5"); skip_iter_eq::<{ FORMAT }>(b"4__5", b"4__5"); skip_iter_eq::<{ FORMAT }>(b"4_", b"4_"); skip_iter_eq::<{ FORMAT }>(b"4__", b"4__"); skip_iter_eq::<{ FORMAT }>(b"4_.", b"4_."); skip_iter_eq::<{ FORMAT }>(b"4__.", b"4__."); skip_iter_eq::<{ FORMAT }>(b"_45_5", b"45_5"); skip_iter_eq::<{ FORMAT }>(b"__45__5", b"__45__5"); skip_iter_eq::<{ FORMAT }>(b"_.45_5", b".45_5"); skip_iter_eq::<{ FORMAT }>(b"__.45__5", b"__.45__5"); skip_iter_eq::<{ FORMAT }>(b"4_5_", b"4_5_"); skip_iter_eq::<{ FORMAT }>(b"4__5__", b"4__5__"); skip_iter_eq::<{ FORMAT }>(b"4_5_.5", b"4_5_.5"); skip_iter_eq::<{ FORMAT }>(b"4__5__.5", b"4__5__.5"); skip_iter_eq::<{ FORMAT }>(b"_45_", b"45_"); skip_iter_eq::<{ FORMAT }>(b"__45__", b"__45__"); skip_iter_eq::<{ FORMAT }>(b"_45_.56", b"45_.56"); skip_iter_eq::<{ FORMAT }>(b"__45__.56", b"__45__.56"); skip_iter_eq::<{ FORMAT }>(b"_4_5_", b"4_5_"); skip_iter_eq::<{ FORMAT }>(b"__4__5__", b"__4__5__"); skip_iter_eq::<{ FORMAT }>(b"_4_5_.56", b"4_5_.56"); skip_iter_eq::<{ FORMAT }>(b"__4__5__.56", b"__4__5__.56"); } #[test] fn test_skip_iter_t() { // Test iterators that skip single, trailing-only digit separators. pub const FORMAT: u128 = NumberFormatBuilder::new() .digit_separator(num::NonZeroU8::new(b'_')) .integer_trailing_digit_separator(true) .build(); const_assert!(NumberFormat::<{ FORMAT }> {}.is_valid()); skip_iter_eq::<{ FORMAT }>(b"123.45", b"123.45"); skip_iter_eq::<{ FORMAT }>(b"1e45", b"1e45"); skip_iter_eq::<{ FORMAT }>(b"1e", b"1e"); skip_iter_eq::<{ FORMAT }>(b"1", b"1"); skip_iter_eq::<{ FORMAT }>(b"_45", b"_45"); skip_iter_eq::<{ FORMAT }>(b"__45", b"__45"); skip_iter_eq::<{ FORMAT }>(b"_.45", b".45"); skip_iter_eq::<{ FORMAT }>(b"__.45", b"__.45"); skip_iter_eq::<{ FORMAT }>(b"4_5", b"4_5"); skip_iter_eq::<{ FORMAT }>(b"4__5", b"4__5"); skip_iter_eq::<{ FORMAT }>(b"4_", b"4"); skip_iter_eq::<{ FORMAT }>(b"4__", b"4__"); skip_iter_eq::<{ FORMAT }>(b"4_.", b"4."); skip_iter_eq::<{ FORMAT }>(b"4__.", b"4__."); skip_iter_eq::<{ FORMAT }>(b"_45_5", b"_45_5"); skip_iter_eq::<{ FORMAT }>(b"__45__5", b"__45__5"); skip_iter_eq::<{ FORMAT }>(b"_.45_5", b".45_5"); skip_iter_eq::<{ FORMAT }>(b"__.45__5", b"__.45__5"); skip_iter_eq::<{ FORMAT }>(b"4_5_", b"4_5"); skip_iter_eq::<{ FORMAT }>(b"4__5__", b"4__5__"); skip_iter_eq::<{ FORMAT }>(b"4_5_.5", b"4_5.5"); skip_iter_eq::<{ FORMAT }>(b"4__5__.5", b"4__5__.5"); skip_iter_eq::<{ FORMAT }>(b"_45_", b"_45"); skip_iter_eq::<{ FORMAT }>(b"__45__", b"__45__"); skip_iter_eq::<{ FORMAT }>(b"_45_.56", b"_45.56"); skip_iter_eq::<{ FORMAT }>(b"__45__.56", b"__45__.56"); skip_iter_eq::<{ FORMAT }>(b"_4_5_", b"_4_5"); skip_iter_eq::<{ FORMAT }>(b"__4__5__", b"__4__5__"); skip_iter_eq::<{ FORMAT }>(b"_4_5_.56", b"_4_5.56"); skip_iter_eq::<{ FORMAT }>(b"__4__5__.56", b"__4__5__.56"); } #[test] fn test_skip_iter_il() { // Test iterators that skip single, internal or leading-only digit separators. pub const FORMAT: u128 = NumberFormatBuilder::new() .digit_separator(num::NonZeroU8::new(b'_')) .integer_internal_digit_separator(true) .integer_leading_digit_separator(true) .build(); const_assert!(NumberFormat::<{ FORMAT }> {}.is_valid()); skip_iter_eq::<{ FORMAT }>(b"123.45", b"123.45"); skip_iter_eq::<{ FORMAT }>(b"1e45", b"1e45"); skip_iter_eq::<{ FORMAT }>(b"1e", b"1e"); skip_iter_eq::<{ FORMAT }>(b"1", b"1"); skip_iter_eq::<{ FORMAT }>(b"_45", b"45"); skip_iter_eq::<{ FORMAT }>(b"__45", b"__45"); skip_iter_eq::<{ FORMAT }>(b"_.45", b".45"); skip_iter_eq::<{ FORMAT }>(b"__.45", b"__.45"); skip_iter_eq::<{ FORMAT }>(b"4_5", b"45"); skip_iter_eq::<{ FORMAT }>(b"4__5", b"4__5"); skip_iter_eq::<{ FORMAT }>(b"4_", b"4_"); skip_iter_eq::<{ FORMAT }>(b"4__", b"4__"); skip_iter_eq::<{ FORMAT }>(b"4_.", b"4_."); skip_iter_eq::<{ FORMAT }>(b"4__.", b"4__."); skip_iter_eq::<{ FORMAT }>(b"_45_5", b"455"); skip_iter_eq::<{ FORMAT }>(b"__45__5", b"__45__5"); skip_iter_eq::<{ FORMAT }>(b"_.45_5", b".455"); skip_iter_eq::<{ FORMAT }>(b"__.45__5", b"__.45__5"); skip_iter_eq::<{ FORMAT }>(b"4_5_", b"45_"); skip_iter_eq::<{ FORMAT }>(b"4__5__", b"4__5__"); skip_iter_eq::<{ FORMAT }>(b"4_5_.5", b"45_.5"); skip_iter_eq::<{ FORMAT }>(b"4__5__.5", b"4__5__.5"); skip_iter_eq::<{ FORMAT }>(b"_45_", b"45_"); skip_iter_eq::<{ FORMAT }>(b"__45__", b"__45__"); skip_iter_eq::<{ FORMAT }>(b"_45_.56", b"45_.56"); skip_iter_eq::<{ FORMAT }>(b"__45__.56", b"__45__.56"); skip_iter_eq::<{ FORMAT }>(b"_4_5_", b"45_"); skip_iter_eq::<{ FORMAT }>(b"__4__5__", b"__4__5__"); skip_iter_eq::<{ FORMAT }>(b"_4_5_.56", b"45_.56"); skip_iter_eq::<{ FORMAT }>(b"__4__5__.56", b"__4__5__.56"); } #[test] fn test_skip_iter_it() { // Test iterators that skip single, internal or trailing-only digit separators. pub const FORMAT: u128 = NumberFormatBuilder::new() .digit_separator(num::NonZeroU8::new(b'_')) .integer_internal_digit_separator(true) .integer_trailing_digit_separator(true) .build(); const_assert!(NumberFormat::<{ FORMAT }> {}.is_valid()); skip_iter_eq::<{ FORMAT }>(b"123.45", b"123.45"); skip_iter_eq::<{ FORMAT }>(b"1e45", b"1e45"); skip_iter_eq::<{ FORMAT }>(b"1e", b"1e"); skip_iter_eq::<{ FORMAT }>(b"1", b"1"); skip_iter_eq::<{ FORMAT }>(b"_45", b"_45"); skip_iter_eq::<{ FORMAT }>(b"__45", b"__45"); skip_iter_eq::<{ FORMAT }>(b"_.45", b".45"); skip_iter_eq::<{ FORMAT }>(b"__.45", b"__.45"); skip_iter_eq::<{ FORMAT }>(b"4_5", b"45"); skip_iter_eq::<{ FORMAT }>(b"4__5", b"4__5"); skip_iter_eq::<{ FORMAT }>(b"4_", b"4"); skip_iter_eq::<{ FORMAT }>(b"4__", b"4__"); skip_iter_eq::<{ FORMAT }>(b"4_.", b"4."); skip_iter_eq::<{ FORMAT }>(b"4__.", b"4__."); skip_iter_eq::<{ FORMAT }>(b"_45_5", b"_455"); skip_iter_eq::<{ FORMAT }>(b"__45__5", b"__45__5"); skip_iter_eq::<{ FORMAT }>(b"_.45_5", b".455"); skip_iter_eq::<{ FORMAT }>(b"__.45__5", b"__.45__5"); skip_iter_eq::<{ FORMAT }>(b"4_5_", b"45"); skip_iter_eq::<{ FORMAT }>(b"4__5__", b"4__5__"); skip_iter_eq::<{ FORMAT }>(b"4_5_.5", b"45.5"); skip_iter_eq::<{ FORMAT }>(b"4__5__.5", b"4__5__.5"); skip_iter_eq::<{ FORMAT }>(b"_45_", b"_45"); skip_iter_eq::<{ FORMAT }>(b"__45__", b"__45__"); skip_iter_eq::<{ FORMAT }>(b"_45_.56", b"_45.56"); skip_iter_eq::<{ FORMAT }>(b"__45__.56", b"__45__.56"); skip_iter_eq::<{ FORMAT }>(b"_4_5_", b"_45"); skip_iter_eq::<{ FORMAT }>(b"__4__5__", b"__4__5__"); skip_iter_eq::<{ FORMAT }>(b"_4_5_.56", b"_45.56"); skip_iter_eq::<{ FORMAT }>(b"__4__5__.56", b"__4__5__.56"); } #[test] fn test_skip_iter_lt() { // Test iterators that skip single, leading or trailing-only digit separators. pub const FORMAT: u128 = NumberFormatBuilder::new() .digit_separator(num::NonZeroU8::new(b'_')) .integer_leading_digit_separator(true) .integer_trailing_digit_separator(true) .build(); const_assert!(NumberFormat::<{ FORMAT }> {}.is_valid()); skip_iter_eq::<{ FORMAT }>(b"123.45", b"123.45"); skip_iter_eq::<{ FORMAT }>(b"1e45", b"1e45"); skip_iter_eq::<{ FORMAT }>(b"1e", b"1e"); skip_iter_eq::<{ FORMAT }>(b"1", b"1"); skip_iter_eq::<{ FORMAT }>(b"_45", b"45"); skip_iter_eq::<{ FORMAT }>(b"__45", b"__45"); skip_iter_eq::<{ FORMAT }>(b"_.45", b".45"); skip_iter_eq::<{ FORMAT }>(b"__.45", b"__.45"); skip_iter_eq::<{ FORMAT }>(b"4_5", b"4_5"); skip_iter_eq::<{ FORMAT }>(b"4__5", b"4__5"); skip_iter_eq::<{ FORMAT }>(b"4_", b"4"); skip_iter_eq::<{ FORMAT }>(b"4__", b"4__"); skip_iter_eq::<{ FORMAT }>(b"4_.", b"4."); skip_iter_eq::<{ FORMAT }>(b"4__.", b"4__."); skip_iter_eq::<{ FORMAT }>(b"_45_5", b"45_5"); skip_iter_eq::<{ FORMAT }>(b"__45__5", b"__45__5"); skip_iter_eq::<{ FORMAT }>(b"_.45_5", b".45_5"); skip_iter_eq::<{ FORMAT }>(b"__.45__5", b"__.45__5"); skip_iter_eq::<{ FORMAT }>(b"4_5_", b"4_5"); skip_iter_eq::<{ FORMAT }>(b"4__5__", b"4__5__"); skip_iter_eq::<{ FORMAT }>(b"4_5_.5", b"4_5.5"); skip_iter_eq::<{ FORMAT }>(b"4__5__.5", b"4__5__.5"); skip_iter_eq::<{ FORMAT }>(b"_45_", b"45"); skip_iter_eq::<{ FORMAT }>(b"__45__", b"__45__"); skip_iter_eq::<{ FORMAT }>(b"_45_.56", b"45.56"); skip_iter_eq::<{ FORMAT }>(b"__45__.56", b"__45__.56"); skip_iter_eq::<{ FORMAT }>(b"_4_5_", b"4_5"); skip_iter_eq::<{ FORMAT }>(b"__4__5__", b"__4__5__"); skip_iter_eq::<{ FORMAT }>(b"_4_5_.56", b"4_5.56"); skip_iter_eq::<{ FORMAT }>(b"__4__5__.56", b"__4__5__.56"); } #[test] fn test_skip_iter_ilt() { // Test iterators that skip single digit separators. pub const FORMAT: u128 = NumberFormatBuilder::new() .digit_separator(num::NonZeroU8::new(b'_')) .integer_internal_digit_separator(true) .integer_leading_digit_separator(true) .integer_trailing_digit_separator(true) .build(); const_assert!(NumberFormat::<{ FORMAT }> {}.is_valid()); skip_iter_eq::<{ FORMAT }>(b"123.45", b"123.45"); skip_iter_eq::<{ FORMAT }>(b"1e45", b"1e45"); skip_iter_eq::<{ FORMAT }>(b"1e", b"1e"); skip_iter_eq::<{ FORMAT }>(b"1", b"1"); skip_iter_eq::<{ FORMAT }>(b"_45", b"45"); skip_iter_eq::<{ FORMAT }>(b"__45", b"__45"); skip_iter_eq::<{ FORMAT }>(b"_.45", b".45"); skip_iter_eq::<{ FORMAT }>(b"__.45", b"__.45"); skip_iter_eq::<{ FORMAT }>(b"4_5", b"45"); skip_iter_eq::<{ FORMAT }>(b"4__5", b"4__5"); skip_iter_eq::<{ FORMAT }>(b"4_", b"4"); skip_iter_eq::<{ FORMAT }>(b"4__", b"4__"); skip_iter_eq::<{ FORMAT }>(b"4_.", b"4."); skip_iter_eq::<{ FORMAT }>(b"4__.", b"4__."); skip_iter_eq::<{ FORMAT }>(b"_45_5", b"455"); skip_iter_eq::<{ FORMAT }>(b"__45__5", b"__45__5"); skip_iter_eq::<{ FORMAT }>(b"_.45_5", b".455"); skip_iter_eq::<{ FORMAT }>(b"__.45__5", b"__.45__5"); skip_iter_eq::<{ FORMAT }>(b"4_5_", b"45"); skip_iter_eq::<{ FORMAT }>(b"4__5__", b"4__5__"); skip_iter_eq::<{ FORMAT }>(b"4_5_.5", b"45.5"); skip_iter_eq::<{ FORMAT }>(b"4__5__.5", b"4__5__.5"); skip_iter_eq::<{ FORMAT }>(b"_45_", b"45"); skip_iter_eq::<{ FORMAT }>(b"__45__", b"__45__"); skip_iter_eq::<{ FORMAT }>(b"_45_.56", b"45.56"); skip_iter_eq::<{ FORMAT }>(b"__45__.56", b"__45__.56"); skip_iter_eq::<{ FORMAT }>(b"_4_5_", b"45"); skip_iter_eq::<{ FORMAT }>(b"__4__5__", b"__4__5__"); skip_iter_eq::<{ FORMAT }>(b"_4_5_.56", b"45.56"); skip_iter_eq::<{ FORMAT }>(b"__4__5__.56", b"__4__5__.56"); } #[test] fn test_skip_iter_ic() { // Test iterators that skip multiple, internal digit separators. pub const FORMAT: u128 = NumberFormatBuilder::new() .digit_separator(num::NonZeroU8::new(b'_')) .integer_internal_digit_separator(true) .integer_consecutive_digit_separator(true) .build(); const_assert!(NumberFormat::<{ FORMAT }> {}.is_valid()); skip_iter_eq::<{ FORMAT }>(b"123.45", b"123.45"); skip_iter_eq::<{ FORMAT }>(b"1e45", b"1e45"); skip_iter_eq::<{ FORMAT }>(b"1e", b"1e"); skip_iter_eq::<{ FORMAT }>(b"1", b"1"); skip_iter_eq::<{ FORMAT }>(b"_45", b"_45"); skip_iter_eq::<{ FORMAT }>(b"__45", b"__45"); skip_iter_eq::<{ FORMAT }>(b"_.45", b"_.45"); skip_iter_eq::<{ FORMAT }>(b"__.45", b"__.45"); skip_iter_eq::<{ FORMAT }>(b"4_5", b"45"); skip_iter_eq::<{ FORMAT }>(b"4__5", b"45"); skip_iter_eq::<{ FORMAT }>(b"4_", b"4_"); skip_iter_eq::<{ FORMAT }>(b"4__", b"4__"); skip_iter_eq::<{ FORMAT }>(b"4_.", b"4_."); skip_iter_eq::<{ FORMAT }>(b"4__.", b"4__."); skip_iter_eq::<{ FORMAT }>(b"_45_5", b"_455"); skip_iter_eq::<{ FORMAT }>(b"__45__5", b"__455"); skip_iter_eq::<{ FORMAT }>(b"_.45_5", b"_.455"); skip_iter_eq::<{ FORMAT }>(b"__.45__5", b"__.455"); skip_iter_eq::<{ FORMAT }>(b"4_5_", b"45_"); skip_iter_eq::<{ FORMAT }>(b"4__5__", b"45__"); skip_iter_eq::<{ FORMAT }>(b"4_5_.5", b"45_.5"); skip_iter_eq::<{ FORMAT }>(b"4__5__.5", b"45__.5"); skip_iter_eq::<{ FORMAT }>(b"_45_", b"_45_"); skip_iter_eq::<{ FORMAT }>(b"__45__", b"__45__"); skip_iter_eq::<{ FORMAT }>(b"_45_.56", b"_45_.56"); skip_iter_eq::<{ FORMAT }>(b"__45__.56", b"__45__.56"); skip_iter_eq::<{ FORMAT }>(b"_4_5_", b"_45_"); skip_iter_eq::<{ FORMAT }>(b"__4__5__", b"__45__"); skip_iter_eq::<{ FORMAT }>(b"_4_5_.56", b"_45_.56"); skip_iter_eq::<{ FORMAT }>(b"__4__5__.56", b"__45__.56"); } #[test] fn test_skip_iter_lc() { // Test iterators that skip multiple, leading digit separators. pub const FORMAT: u128 = NumberFormatBuilder::new() .digit_separator(num::NonZeroU8::new(b'_')) .integer_leading_digit_separator(true) .integer_consecutive_digit_separator(true) .build(); const_assert!(NumberFormat::<{ FORMAT }> {}.is_valid()); skip_iter_eq::<{ FORMAT }>(b"123.45", b"123.45"); skip_iter_eq::<{ FORMAT }>(b"1e45", b"1e45"); skip_iter_eq::<{ FORMAT }>(b"1e", b"1e"); skip_iter_eq::<{ FORMAT }>(b"1", b"1"); skip_iter_eq::<{ FORMAT }>(b"_45", b"45"); skip_iter_eq::<{ FORMAT }>(b"__45", b"45"); skip_iter_eq::<{ FORMAT }>(b"_.45", b".45"); skip_iter_eq::<{ FORMAT }>(b"__.45", b".45"); skip_iter_eq::<{ FORMAT }>(b"4_5", b"4_5"); skip_iter_eq::<{ FORMAT }>(b"4__5", b"4__5"); skip_iter_eq::<{ FORMAT }>(b"4_", b"4_"); skip_iter_eq::<{ FORMAT }>(b"4__", b"4__"); skip_iter_eq::<{ FORMAT }>(b"4_.", b"4_."); skip_iter_eq::<{ FORMAT }>(b"4__.", b"4__."); skip_iter_eq::<{ FORMAT }>(b"_45_5", b"45_5"); skip_iter_eq::<{ FORMAT }>(b"__45__5", b"45__5"); skip_iter_eq::<{ FORMAT }>(b"_.45_5", b".45_5"); skip_iter_eq::<{ FORMAT }>(b"__.45__5", b".45__5"); skip_iter_eq::<{ FORMAT }>(b"4_5_", b"4_5_"); skip_iter_eq::<{ FORMAT }>(b"4__5__", b"4__5__"); skip_iter_eq::<{ FORMAT }>(b"4_5_.5", b"4_5_.5"); skip_iter_eq::<{ FORMAT }>(b"4__5__.5", b"4__5__.5"); skip_iter_eq::<{ FORMAT }>(b"_45_", b"45_"); skip_iter_eq::<{ FORMAT }>(b"__45__", b"45__"); skip_iter_eq::<{ FORMAT }>(b"_45_.56", b"45_.56"); skip_iter_eq::<{ FORMAT }>(b"__45__.56", b"45__.56"); skip_iter_eq::<{ FORMAT }>(b"_4_5_", b"4_5_"); skip_iter_eq::<{ FORMAT }>(b"__4__5__", b"4__5__"); skip_iter_eq::<{ FORMAT }>(b"_4_5_.56", b"4_5_.56"); skip_iter_eq::<{ FORMAT }>(b"__4__5__.56", b"4__5__.56"); } #[test] fn test_skip_iter_tc() { // Test iterators that skip multiple, trailing digit separators. pub const FORMAT: u128 = NumberFormatBuilder::new() .digit_separator(num::NonZeroU8::new(b'_')) .integer_trailing_digit_separator(true) .integer_consecutive_digit_separator(true) .build(); const_assert!(NumberFormat::<{ FORMAT }> {}.is_valid()); skip_iter_eq::<{ FORMAT }>(b"123.45", b"123.45"); skip_iter_eq::<{ FORMAT }>(b"1e45", b"1e45"); skip_iter_eq::<{ FORMAT }>(b"1e", b"1e"); skip_iter_eq::<{ FORMAT }>(b"1", b"1"); skip_iter_eq::<{ FORMAT }>(b"_45", b"_45"); skip_iter_eq::<{ FORMAT }>(b"__45", b"__45"); skip_iter_eq::<{ FORMAT }>(b"_.45", b".45"); skip_iter_eq::<{ FORMAT }>(b"__.45", b".45"); skip_iter_eq::<{ FORMAT }>(b"4_5", b"4_5"); skip_iter_eq::<{ FORMAT }>(b"4__5", b"4__5"); skip_iter_eq::<{ FORMAT }>(b"4_", b"4"); skip_iter_eq::<{ FORMAT }>(b"4__", b"4"); skip_iter_eq::<{ FORMAT }>(b"4_.", b"4."); skip_iter_eq::<{ FORMAT }>(b"4__.", b"4."); skip_iter_eq::<{ FORMAT }>(b"_45_5", b"_45_5"); skip_iter_eq::<{ FORMAT }>(b"__45__5", b"__45__5"); skip_iter_eq::<{ FORMAT }>(b"_.45_5", b".45_5"); skip_iter_eq::<{ FORMAT }>(b"__.45__5", b".45__5"); skip_iter_eq::<{ FORMAT }>(b"4_5_", b"4_5"); skip_iter_eq::<{ FORMAT }>(b"4__5__", b"4__5"); skip_iter_eq::<{ FORMAT }>(b"4_5_.5", b"4_5.5"); skip_iter_eq::<{ FORMAT }>(b"4__5__.5", b"4__5.5"); skip_iter_eq::<{ FORMAT }>(b"_45_", b"_45"); skip_iter_eq::<{ FORMAT }>(b"__45__", b"__45"); skip_iter_eq::<{ FORMAT }>(b"_45_.56", b"_45.56"); skip_iter_eq::<{ FORMAT }>(b"__45__.56", b"__45.56"); skip_iter_eq::<{ FORMAT }>(b"_4_5_", b"_4_5"); skip_iter_eq::<{ FORMAT }>(b"__4__5__", b"__4__5"); skip_iter_eq::<{ FORMAT }>(b"_4_5_.56", b"_4_5.56"); skip_iter_eq::<{ FORMAT }>(b"__4__5__.56", b"__4__5.56"); } #[test] fn test_skip_iter_ilc() { // Test iterators that skip multiple, internal or leading digit separators. pub const FORMAT: u128 = NumberFormatBuilder::new() .digit_separator(num::NonZeroU8::new(b'_')) .integer_internal_digit_separator(true) .integer_leading_digit_separator(true) .integer_consecutive_digit_separator(true) .build(); const_assert!(NumberFormat::<{ FORMAT }> {}.is_valid()); skip_iter_eq::<{ FORMAT }>(b"123.45", b"123.45"); skip_iter_eq::<{ FORMAT }>(b"1e45", b"1e45"); skip_iter_eq::<{ FORMAT }>(b"1e", b"1e"); skip_iter_eq::<{ FORMAT }>(b"1", b"1"); skip_iter_eq::<{ FORMAT }>(b"_45", b"45"); skip_iter_eq::<{ FORMAT }>(b"__45", b"45"); skip_iter_eq::<{ FORMAT }>(b"_.45", b".45"); skip_iter_eq::<{ FORMAT }>(b"__.45", b".45"); skip_iter_eq::<{ FORMAT }>(b"4_5", b"45"); skip_iter_eq::<{ FORMAT }>(b"4__5", b"45"); skip_iter_eq::<{ FORMAT }>(b"4_", b"4_"); skip_iter_eq::<{ FORMAT }>(b"4__", b"4__"); skip_iter_eq::<{ FORMAT }>(b"4_.", b"4_."); skip_iter_eq::<{ FORMAT }>(b"4__.", b"4__."); skip_iter_eq::<{ FORMAT }>(b"_45_5", b"455"); skip_iter_eq::<{ FORMAT }>(b"__45__5", b"455"); skip_iter_eq::<{ FORMAT }>(b"_.45_5", b".455"); skip_iter_eq::<{ FORMAT }>(b"__.45__5", b".455"); skip_iter_eq::<{ FORMAT }>(b"4_5_", b"45_"); skip_iter_eq::<{ FORMAT }>(b"4__5__", b"45__"); skip_iter_eq::<{ FORMAT }>(b"4_5_.5", b"45_.5"); skip_iter_eq::<{ FORMAT }>(b"4__5__.5", b"45__.5"); skip_iter_eq::<{ FORMAT }>(b"_45_", b"45_"); skip_iter_eq::<{ FORMAT }>(b"__45__", b"45__"); skip_iter_eq::<{ FORMAT }>(b"_45_.56", b"45_.56"); skip_iter_eq::<{ FORMAT }>(b"__45__.56", b"45__.56"); skip_iter_eq::<{ FORMAT }>(b"_4_5_", b"45_"); skip_iter_eq::<{ FORMAT }>(b"__4__5__", b"45__"); skip_iter_eq::<{ FORMAT }>(b"_4_5_.56", b"45_.56"); skip_iter_eq::<{ FORMAT }>(b"__4__5__.56", b"45__.56"); } #[test] fn test_skip_iter_itc() { // Test iterators that skip multiple, internal or trailing digit separators. pub const FORMAT: u128 = NumberFormatBuilder::new() .digit_separator(num::NonZeroU8::new(b'_')) .integer_internal_digit_separator(true) .integer_trailing_digit_separator(true) .integer_consecutive_digit_separator(true) .build(); const_assert!(NumberFormat::<{ FORMAT }> {}.is_valid()); skip_iter_eq::<{ FORMAT }>(b"123.45", b"123.45"); skip_iter_eq::<{ FORMAT }>(b"1e45", b"1e45"); skip_iter_eq::<{ FORMAT }>(b"1e", b"1e"); skip_iter_eq::<{ FORMAT }>(b"1", b"1"); skip_iter_eq::<{ FORMAT }>(b"_45", b"_45"); skip_iter_eq::<{ FORMAT }>(b"__45", b"__45"); skip_iter_eq::<{ FORMAT }>(b"_.45", b".45"); skip_iter_eq::<{ FORMAT }>(b"__.45", b".45"); skip_iter_eq::<{ FORMAT }>(b"4_5", b"45"); skip_iter_eq::<{ FORMAT }>(b"4__5", b"45"); skip_iter_eq::<{ FORMAT }>(b"4_", b"4"); skip_iter_eq::<{ FORMAT }>(b"4__", b"4"); skip_iter_eq::<{ FORMAT }>(b"4_.", b"4."); skip_iter_eq::<{ FORMAT }>(b"4__.", b"4."); skip_iter_eq::<{ FORMAT }>(b"_45_5", b"_455"); skip_iter_eq::<{ FORMAT }>(b"__45__5", b"__455"); skip_iter_eq::<{ FORMAT }>(b"_.45_5", b".455"); skip_iter_eq::<{ FORMAT }>(b"__.45__5", b".455"); skip_iter_eq::<{ FORMAT }>(b"4_5_", b"45"); skip_iter_eq::<{ FORMAT }>(b"4__5__", b"45"); skip_iter_eq::<{ FORMAT }>(b"4_5_.5", b"45.5"); skip_iter_eq::<{ FORMAT }>(b"4__5__.5", b"45.5"); skip_iter_eq::<{ FORMAT }>(b"_45_", b"_45"); skip_iter_eq::<{ FORMAT }>(b"__45__", b"__45"); skip_iter_eq::<{ FORMAT }>(b"_45_.56", b"_45.56"); skip_iter_eq::<{ FORMAT }>(b"__45__.56", b"__45.56"); skip_iter_eq::<{ FORMAT }>(b"_4_5_", b"_45"); skip_iter_eq::<{ FORMAT }>(b"__4__5__", b"__45"); skip_iter_eq::<{ FORMAT }>(b"_4_5_.56", b"_45.56"); skip_iter_eq::<{ FORMAT }>(b"__4__5__.56", b"__45.56"); } #[test] fn test_skip_iter_ltc() { // Test iterators that skip multiple, leading or trailing digit separators. pub const FORMAT: u128 = NumberFormatBuilder::new() .digit_separator(num::NonZeroU8::new(b'_')) .integer_leading_digit_separator(true) .integer_trailing_digit_separator(true) .integer_consecutive_digit_separator(true) .build(); const_assert!(NumberFormat::<{ FORMAT }> {}.is_valid()); skip_iter_eq::<{ FORMAT }>(b"123.45", b"123.45"); skip_iter_eq::<{ FORMAT }>(b"1e45", b"1e45"); skip_iter_eq::<{ FORMAT }>(b"1e", b"1e"); skip_iter_eq::<{ FORMAT }>(b"1", b"1"); skip_iter_eq::<{ FORMAT }>(b"_45", b"45"); skip_iter_eq::<{ FORMAT }>(b"__45", b"45"); skip_iter_eq::<{ FORMAT }>(b"_.45", b".45"); skip_iter_eq::<{ FORMAT }>(b"__.45", b".45"); skip_iter_eq::<{ FORMAT }>(b"4_5", b"4_5"); skip_iter_eq::<{ FORMAT }>(b"4__5", b"4__5"); skip_iter_eq::<{ FORMAT }>(b"4_", b"4"); skip_iter_eq::<{ FORMAT }>(b"4__", b"4"); skip_iter_eq::<{ FORMAT }>(b"4_.", b"4."); skip_iter_eq::<{ FORMAT }>(b"4__.", b"4."); skip_iter_eq::<{ FORMAT }>(b"_45_5", b"45_5"); skip_iter_eq::<{ FORMAT }>(b"__45__5", b"45__5"); skip_iter_eq::<{ FORMAT }>(b"_.45_5", b".45_5"); skip_iter_eq::<{ FORMAT }>(b"__.45__5", b".45__5"); skip_iter_eq::<{ FORMAT }>(b"4_5_", b"4_5"); skip_iter_eq::<{ FORMAT }>(b"4__5__", b"4__5"); skip_iter_eq::<{ FORMAT }>(b"4_5_.5", b"4_5.5"); skip_iter_eq::<{ FORMAT }>(b"4__5__.5", b"4__5.5"); skip_iter_eq::<{ FORMAT }>(b"_45_", b"45"); skip_iter_eq::<{ FORMAT }>(b"__45__", b"45"); skip_iter_eq::<{ FORMAT }>(b"_45_.56", b"45.56"); skip_iter_eq::<{ FORMAT }>(b"__45__.56", b"45.56"); skip_iter_eq::<{ FORMAT }>(b"_4_5_", b"4_5"); skip_iter_eq::<{ FORMAT }>(b"__4__5__", b"4__5"); skip_iter_eq::<{ FORMAT }>(b"_4_5_.56", b"4_5.56"); skip_iter_eq::<{ FORMAT }>(b"__4__5__.56", b"4__5.56"); } #[test] fn test_skip_iter_iltc() { // Test iterators that skip multiple digit separators. pub const FORMAT: u128 = NumberFormatBuilder::new() .digit_separator(num::NonZeroU8::new(b'_')) .integer_internal_digit_separator(true) .integer_leading_digit_separator(true) .integer_trailing_digit_separator(true) .integer_consecutive_digit_separator(true) .build(); const_assert!(NumberFormat::<{ FORMAT }> {}.is_valid()); skip_iter_eq::<{ FORMAT }>(b"123.45", b"123.45"); skip_iter_eq::<{ FORMAT }>(b"1e45", b"1e45"); skip_iter_eq::<{ FORMAT }>(b"1e", b"1e"); skip_iter_eq::<{ FORMAT }>(b"1", b"1"); skip_iter_eq::<{ FORMAT }>(b"_45", b"45"); skip_iter_eq::<{ FORMAT }>(b"__45", b"45"); skip_iter_eq::<{ FORMAT }>(b"_.45", b".45"); skip_iter_eq::<{ FORMAT }>(b"__.45", b".45"); skip_iter_eq::<{ FORMAT }>(b"4_5", b"45"); skip_iter_eq::<{ FORMAT }>(b"4__5", b"45"); skip_iter_eq::<{ FORMAT }>(b"4_", b"4"); skip_iter_eq::<{ FORMAT }>(b"4__", b"4"); skip_iter_eq::<{ FORMAT }>(b"4_.", b"4."); skip_iter_eq::<{ FORMAT }>(b"4__.", b"4."); skip_iter_eq::<{ FORMAT }>(b"_45_5", b"455"); skip_iter_eq::<{ FORMAT }>(b"__45__5", b"455"); skip_iter_eq::<{ FORMAT }>(b"_.45_5", b".455"); skip_iter_eq::<{ FORMAT }>(b"__.45__5", b".455"); skip_iter_eq::<{ FORMAT }>(b"4_5_", b"45"); skip_iter_eq::<{ FORMAT }>(b"4__5__", b"45"); skip_iter_eq::<{ FORMAT }>(b"4_5_.5", b"45.5"); skip_iter_eq::<{ FORMAT }>(b"4__5__.5", b"45.5"); skip_iter_eq::<{ FORMAT }>(b"_45_", b"45"); skip_iter_eq::<{ FORMAT }>(b"__45__", b"45"); skip_iter_eq::<{ FORMAT }>(b"_45_.56", b"45.56"); skip_iter_eq::<{ FORMAT }>(b"__45__.56", b"45.56"); skip_iter_eq::<{ FORMAT }>(b"_4_5_", b"45"); skip_iter_eq::<{ FORMAT }>(b"__4__5__", b"45"); skip_iter_eq::<{ FORMAT }>(b"_4_5_.56", b"45.56"); skip_iter_eq::<{ FORMAT }>(b"__4__5__.56", b"45.56"); } lexical-util-1.0.6/tests/util.rs000064400000000000000000000031111046102023000147050ustar 00000000000000#![allow(dead_code, unused_imports)] use proptest::prelude::*; pub(crate) use quickcheck::QuickCheck; pub fn default_proptest_config() -> ProptestConfig { ProptestConfig { cases: if cfg!(miri) { 10 } else { ProptestConfig::default().cases }, max_shrink_iters: if cfg!(miri) { 10 } else { ProptestConfig::default().max_shrink_iters }, failure_persistence: if cfg!(miri) { None } else { ProptestConfig::default().failure_persistence }, ..ProptestConfig::default() } } // This is almost identical to quickcheck's itself, just to add default // arguments https://docs.rs/quickcheck/1.0.3/src/quickcheck/lib.rs.html#43-67 // The code is unlicensed. #[macro_export] macro_rules! default_quickcheck { (@as_items $($i:item)*) => ($($i)*); { $( $(#[$m:meta])* fn $fn_name:ident($($arg_name:ident : $arg_ty:ty),*) -> $ret:ty { $($code:tt)* } )* } => ( $crate::default_quickcheck! { @as_items $( #[test] $(#[$m])* fn $fn_name() { fn prop($($arg_name: $arg_ty),*) -> $ret { $($code)* } $crate::util::QuickCheck::new() .max_tests(if cfg!(miri) { 10 } else { 10_000 }) .quickcheck(prop as fn($($arg_ty),*) -> $ret); } )* } ) }