lexical/lib.rs
1//! Fast lexical conversion routines.
2//!
3//! `lexical-core` is a high-performance library for number-to-string and
4//! string-to-number conversions. The writers require a system allocator,
5//! but support a [`no_std`] environment. In addition to high performance,
6//! it's also highly configurable, supporting nearly every float and integer
7//! format available.
8//!
9//! `lexical` is well-tested, and has been downloaded more than 25 million
10//! times and currently has no known errors in correctness. `lexical`
11//! prioritizes performance above all else, and is competitive or faster
12//! than any other float or integer parser and writer.
13//!
14//! In addition, despite having a large number of features, configurability,
15//! and a focus on performance, it also aims to have fast compile times.
16//! Recent versions also add [`support`](#compact) for smaller binary sizes, as
17//! well ideal for embedded or web environments, where executable bloat can
18//! be much more detrimental than performance.
19//!
20//! [`no_std`]: https://docs.rust-embedded.org/book/intro/no-std.html
21//!
22//! # Getting Started
23//!
24//! #### Parse API
25//!
26//! The main parsing API is [`parse`] and [`parse_partial`]. For example,
27//! to parse a number from string, validating the entire input is a number:
28//!
29//! ```rust
30//! # #[cfg(all(feature = "parse-floats", feature = "parse-integers"))] {
31//! let i: i32 = lexical::parse("3").unwrap(); // 3, auto-type deduction.
32//! let f: f32 = lexical::parse("3.5").unwrap(); // 3.5
33//! let d = lexical::parse::<f64, _>("3.5"); // Ok(3.5), successful parse.
34//! # }
35//! ```
36//!
37//! All `lexical` parsers are validating, they check the that entire input data
38//! is correct, and stop parsing when invalid data is found, numerical overflow,
39//! or other errors:
40//!
41//! ```rust
42//! # #[cfg(all(feature = "parse-floats", feature = "parse-integers"))] {
43//! let r = lexical::parse::<u8, _>("256"); // Err(ErrorCode::Overflow.into())
44//! let r = lexical::parse::<u8, _>("1a5"); // Err(ErrorCode::InvalidDigit.into())
45//! # }
46//! ```
47//!
48//! For streaming APIs or those incrementally parsing data fed to a parser,
49//! where the input data is known to be a float but where the float ends is
50//! currently unknown, the partial parsers will both return the data it was
51//! able to parse and the number of bytes processed:
52//!
53//! ```rust
54//! # #[cfg(feature = "parse-integers")] {
55//! let r = lexical::parse_partial::<i8, _>("3a5"); // Ok((3, 1))
56//! # }
57//! ```
58//!
59//! #### Write API
60//!
61//! The main parsing API is [`to_string`]. For example, to write a number to
62//! string:
63//!
64//! ```rust
65//! # #[cfg(feature = "write-floats")] {
66//! let value = lexical::to_string(15.1);
67//! assert_eq!(value, "15.1");
68//! # }
69//! ```
70//!
71//! # Conversion API
72//!
73//! This writes and parses numbers to and from a format identical to
74//! Rust's [`parse`][`core-parse`] and [`write`][`core-write`].
75//!
76//! [`core-parse`]: core::str::FromStr::from_str
77//! [`core-write`]: core::fmt::Display::fmt
78//!
79//! <!-- Spacer for rustfmt -->
80#![cfg_attr(
81 any(feature = "write-floats", feature = "write-integers"),
82 doc = "- [`to_string`]: Write a number to string."
83)]
84#![cfg_attr(
85 any(feature = "parse-floats", feature = "parse-integers"),
86 doc = "
87- [`parse`]: Parse a number from string validating the complete string is a number.
88- [`parse_partial`]: Parse a number from string returning the number and the number
89 of digits it was able to parse.
90"
91)]
92//!
93//! ```rust
94//! # #[cfg(all(feature = "parse-floats", feature = "write-floats"))] {
95//! // parse
96//! let f: f64 = lexical::parse(b"3.5").unwrap();
97//! assert_eq!(f, 3.5);
98//!
99//! let (f, count): (f64, usize) = lexical::parse_partial(b"3.5").unwrap();
100//! assert_eq!(f, 3.5);
101//! assert_eq!(count, 3);
102//!
103//! // write
104//! let value = lexical::to_string(f);
105//! assert_eq!(value, "3.5");
106//! # }
107//! ```
108//!
109//! # Options/Formatting API
110//!
111//! Each number parser and writer contains extensive formatting control
112//! through options and [`mod@format`] specifications, including digit
113//! [`separator`] support (that is, numbers such as `1_2__3.4_5`), if
114//! integral, fractional, or any significant digits are required, if to
115//! disable parsing or writing of non-finite values, if `+` signs are
116//! invalid or required, and much more.
117//!
118//! [`separator`]: NumberFormat::digit_separator
119//!
120//! <!-- Spacer for rustfmt -->
121#![cfg_attr(
122 feature = "write-floats",
123 doc = "[`nan_string`]: WriteFloatOptionsBuilder::nan_string"
124)]
125#![cfg_attr(
126 all(not(feature = "write-floats"), feature = "parse-floats"),
127 doc = "[`nan_string`]: ParseFloatOptionsBuilder::nan_string"
128)]
129#![cfg_attr(
130 all(not(feature = "write-floats"), not(feature = "parse-floats")),
131 doc = "[`nan_string`]: https://docs.rs/lexical-core/latest/lexical_core/struct.WriteFloatOptionsBuilder.html#method.nan_string"
132)]
133//!
134//! <!-- Spacer for rustfmt -->
135#![cfg_attr(
136 any(feature = "write-floats", feature = "write-integers"),
137 doc = "- [`to_string_with_options`]: Write a number to string using custom formatting options."
138)]
139#![cfg_attr(
140 any(feature = "parse-floats", feature = "parse-integers"),
141 doc = "
142- [`parse_with_options`]: Parse a number from string using custom formatting options,
143 validating the complete string is a number.
144- [`parse_partial_with_options`]: Parse a number from string using custom formatting
145 options, returning the number and the number of digits it was able to parse.
146"
147)]
148//!
149//! Some options, such as custom string representations of non-finite
150//! floats (such as [`NaN`][`nan_string`]), are available without the
151//! [`format`](crate#format) feature. For more comprehensive examples, see the
152//! [`format`](#format) and [Comprehensive Configuration] sections
153//! below.
154//!
155//! ```rust
156//! # #[cfg(all(feature = "parse-floats", feature = "write-floats", feature = "format"))] {
157//! use lexical::{format, parse_float_options, write_float_options};
158//!
159//! // parse
160//! let f: f64 = lexical::parse_with_options::<_, _, { format::JSON }>(
161//! "3.5",
162//! &parse_float_options::JSON
163//! ).unwrap();
164//!
165//! // write
166//! let value = lexical::to_string_with_options::<_, { format::JSON }>(
167//! f,
168//! &write_float_options::JSON
169//! );
170//! assert_eq!(value, "3.5");
171//! # }
172//! ```
173//!
174//! [Comprehensive Configuration]: #comprehensive-configuration
175//!
176//! # Features
177//!
178//! In accordance with the Rust ethos, all features are additive: the crate
179//! may be build with `--all-features` without issue. The following features
180//! are enabled by default:
181//!
182//! * `write-integers` (Default) - Enable writing of integers.
183//! * `write-floats` (Default) - Enable writing of floats.
184//! * `parse-integers` (Default) - Enable parsing of integers.
185//! * `parse-floats` (Default) - Enable parsing of floats.
186//! * `radix` - Add support for strings of any radix.
187//! * `compact` - Reduce code size at the cost of performance.
188//! * `format` - Add support for custom number formatting.
189//! * `f16` - Enable support for half-precision [`f16`][`ieee-f16`] and
190//! [`bf16`][`brain-float`] floats.
191//! * `std` (Default) - Disable to allow use in a [`no_std`] environment.
192//!
193//! [`ieee-f16`]: https://en.wikipedia.org/wiki/Half-precision_floating-point_format
194//! [`brain-float`]: https://en.wikipedia.org/wiki/Bfloat16_floating-point_format
195//!
196//! A complete description of supported features includes:
197//!
198//! #### write-integers
199//!
200//! Enable support for writing integers to string.
201//!
202//! ```rust
203//! # #[cfg(feature = "write-integers")] {
204//! let value = lexical::to_string(1234u64);
205//! assert_eq!(value, "1234");
206//! # }
207//! ```
208//!
209//! #### write-floats
210//!
211//! Enable support for writing floating-point numbers to string.
212//!
213//! ```rust
214//! # #[cfg(feature = "write-floats")] {
215//! let value = lexical::to_string(1.234f64);
216//! assert_eq!(value, "1.234");
217//! # }
218//! ```
219//!
220//! #### parse-integers
221//!
222//! Enable support for parsing integers from string.
223//!
224//! ```rust
225//! # #[cfg(feature = "parse-integers")] {
226//! let f: i64 = lexical::parse("1234").unwrap();
227//! assert_eq!(f, 1234);
228//! # }
229//! ```
230//!
231//! #### parsing-floats
232//!
233//! Enable support for parsing floating-point numbers from string.
234//!
235//! ```rust
236//! # #[cfg(feature = "parse-integers")] {
237//! let f: f64 = lexical::parse("1.234").unwrap();
238//! assert_eq!(f, 1.234);
239//! # }
240//! ```
241//!
242//! #### format
243//!
244//! Adds support for the entire format API (using [`NumberFormatBuilder`]).
245//! This allows extensive configurability for parsing and writing numbers
246//! in custom formats, with different valid syntax requirements.
247//!
248//! For example, in JSON, the following floats are valid or invalid:
249//!
250//! ```text
251//! -1 // valid
252//! +1 // invalid
253//! 1 // valid
254//! 1. // invalid
255//! .1 // invalid
256//! 0.1 // valid
257//! nan // invalid
258//! inf // invalid
259//! Infinity // invalid
260//! ```
261//!
262//! All of the finite numbers are valid in Rust, and Rust provides constants
263//! for non-finite floats. In order to parse standard-conforming JSON floats
264//! using lexical, you may use the following approach:
265//!
266//! ```rust
267//! # #[cfg(all(feature = "parse-floats", feature = "format"))] {
268//! use lexical::{format, parse_with_options, ParseFloatOptions, Result};
269//!
270//! fn parse_json_float<Bytes: AsRef<[u8]>>(bytes: Bytes) -> Result<f64> {
271//! const OPTIONS: ParseFloatOptions = ParseFloatOptions::new();
272//! parse_with_options::<_, _, { format::JSON }>(bytes.as_ref(), &OPTIONS)
273//! }
274//! # }
275//! ```
276//!
277//! Enabling the [`format`](crate#format) API significantly increases compile
278//! times, however, it enables a large amount of customization in how floats are
279//! written.
280//!
281//! #### power-of-two
282//!
283//! Enable doing numeric conversions to and from strings radixes that are powers
284//! of two, that is, `2`, `4`, `8`, `16`, and `32`. This avoids most of the
285//! overhead and binary bloat of the [`radix`](#radix) feature, while enabling
286//! support for the most commonly-used radixes.
287//!
288//! ```rust
289//! # #[cfg(all(feature = "parse-floats", feature = "write-floats", feature = "power-of-two"))] {
290//! use lexical::{
291//! ParseFloatOptions,
292//! WriteFloatOptions,
293//! NumberFormatBuilder
294//! };
295//!
296//! // parse
297//! const BINARY: u128 = NumberFormatBuilder::binary();
298//! let value = "1.0011101111100111011011001000101101000011100101011";
299//! let f: f64 = lexical::parse_with_options::<_, _, { BINARY }>(
300//! value,
301//! &ParseFloatOptions::new()
302//! ).unwrap();
303//!
304//! // write
305//! let result = lexical::to_string_with_options::<_, { BINARY }>(
306//! f,
307//! &WriteFloatOptions::new()
308//! );
309//! assert_eq!(result, value);
310//! # }
311//! ```
312//!
313//! #### radix
314//!
315//! Enable doing numeric conversions to and from strings for all radixes.
316//! This requires more static storage than [`power-of-two`](#power-of-two),
317//! and increases compile times, but can be quite useful
318//! for esoteric programming languages which use duodecimal floats, for
319//! example.
320//!
321//! ```rust
322//! # #[cfg(all(feature = "parse-floats", feature = "write-floats", feature = "radix"))] {
323//! # use core::str;
324//! use lexical::{
325//! ParseFloatOptions,
326//! WriteFloatOptions,
327//! NumberFormatBuilder
328//! };
329//!
330//! // parse
331//! const FORMAT: u128 = NumberFormatBuilder::from_radix(12);
332//! let value = "1.29842830A44BAA2";
333//! let f: f64 = lexical::parse_with_options::<_, _, { FORMAT }>(
334//! value,
335//! &ParseFloatOptions::new()
336//! ).unwrap();
337//!
338//! // write
339//! let result = lexical::to_string_with_options::<_, { FORMAT }>(
340//! f,
341//! &WriteFloatOptions::new()
342//! );
343//! assert_eq!(result, value);
344//! # }
345//! ```
346//!
347//! #### compact
348//!
349//! Reduce the generated code size at the cost of performance. This minimizes
350//! the number of static tables, inlining, and generics used, drastically
351//! reducing the size of the generated binaries.
352//!
353//! #### std
354//!
355//! Enable use of the standard library. Currently, the standard library
356//! is not used, and may be disabled without any change in functionality
357//! on stable.
358//!
359//! # Comprehensive Configuration
360//!
361//! `lexical` provides two main levels of configuration:
362//! - The [`NumberFormatBuilder`], creating a packed struct with custom
363//! formatting options.
364//! - The Options API.
365//!
366//! ## Number Format
367//!
368//! The number format class provides numerous flags to specify
369//! number parsing or writing. When the `power-of-two` feature is
370//! enabled, additional flags are added:
371//! - The radix for the significant digits (default `10`).
372//! - The radix for the exponent base (default `10`).
373//! - The radix for the exponent digits (default `10`).
374//!
375//! When the [`format`](#format) feature is enabled, numerous other syntax and
376//! digit separator flags are enabled, including:
377//! - A digit separator character, to group digits for increased legibility.
378//! - Whether leading, trailing, internal, and consecutive digit separators are
379//! allowed.
380//! - Toggling required float components, such as digits before the decimal
381//! point.
382//! - Toggling whether special floats are allowed or are case-sensitive.
383//!
384//! Many pre-defined constants therefore exist to simplify common use-cases,
385//! including:
386//! - [`JSON`], [`XML`], [`TOML`], [`YAML`], [`SQLite`], and many more.
387//! - [`Rust`], [`Python`], [`C#`], [`FORTRAN`], [`COBOL`] literals and strings,
388//! and many more.
389//!
390//! For a list of all supported fields, see
391//! [Fields][NumberFormatBuilder#fields-1].
392//!
393//! <!-- Spacer for rustfmt -->
394#![cfg_attr(
395 feature = "format",
396 doc = "
397[`JSON`]: format::JSON
398[`XML`]: format::XML
399[`TOML`]: format::TOML
400[`YAML`]: format::YAML
401[`SQLite`]: format::SQLITE
402[`Rust`]: format::RUST_LITERAL
403[`Python`]: format::PYTHON_LITERAL
404[`C#`]: format::CSHARP_LITERAL
405[`FORTRAN`]: format::FORTRAN_LITERAL
406[`COBOL`]: format::COBOL_LITERAL
407"
408)]
409#![cfg_attr(
410 not(feature = "format"),
411 doc = "
412[`JSON`]: https://docs.rs/lexical/latest/lexical/format/constant.JSON.html
413[`XML`]: https://docs.rs/lexical/latest/lexical/format/constant.XML.html
414[`TOML`]: https://docs.rs/lexical/latest/lexical/format/constant.TOML.html
415[`YAML`]: https://docs.rs/lexical/latest/lexical/format/constant.YAML.html
416[`SQLite`]: https://docs.rs/lexical/latest/lexical/format/constant.SQLITE.html
417[`Rust`]: https://docs.rs/lexical/latest/lexical/format/constant.RUST_LITERAL.html
418[`Python`]: https://docs.rs/lexical/latest/lexical/format/constant.PYTHON_LITERAL.html
419[`C#`]: https://docs.rs/lexical/latest/lexical/format/constant.CSHARP_LITERAL.html
420[`FORTRAN`]: https://docs.rs/lexical/latest/lexical/format/constant.FORTRAN_LITERAL.html
421[`COBOL`]: https://docs.rs/lexical/latest/lexical/format/constant.COBOL_LITERAL.html
422"
423)]
424//!
425//! ## Options API
426//!
427//! The Options API provides high-level options to specify number parsing
428//! or writing, options not intrinsically tied to a number format.
429//! For example, the Options API provides:
430//!
431//! - The [`exponent`][`write-float-exponent`] character (defaults to `b'e'` or `b'^'`, depending on the radix).
432//! - The [`decimal point`][`write-float-decimal_point`] character (defaults to `b'.'`).
433//! - Custom [`NaN`][f64::NAN] and [`Infinity`][f64::INFINITY] string
434//! [`representations`][`write-float-nan_string`].
435//! - Whether to [`trim`][`write-float-trim_floats`] the fraction component from integral floats.
436//! - The exponent [`break-point`][`write-float-positive_exponent_break`] for scientific notation.
437//! - The [`maximum`][`write-float-max_significant_digits`] and [`minimum`][`write-float-min_significant_digits`] number of significant digits to write.
438//! - The rounding [`mode`][`write-float-round_mode`] when truncating significant digits while writing.
439//!
440//! <!-- Spacer for Rustfmt -->
441#![cfg_attr(
442 feature = "write-floats",
443 doc = "
444[`write-float-exponent`]: WriteFloatOptionsBuilder::exponent
445[`write-float-decimal_point`]: WriteFloatOptionsBuilder::decimal_point
446[`write-float-nan_string`]: WriteFloatOptionsBuilder::nan_string
447[`write-float-trim_floats`]: WriteFloatOptionsBuilder::trim_floats
448[`write-float-positive_exponent_break`]: WriteFloatOptionsBuilder::positive_exponent_break
449[`write-float-max_significant_digits`]: WriteFloatOptionsBuilder::max_significant_digits
450[`write-float-min_significant_digits`]: WriteFloatOptionsBuilder::min_significant_digits
451[`write-float-round_mode`]: WriteFloatOptionsBuilder::round_mode
452"
453)]
454#![cfg_attr(
455 not(feature = "write-floats"),
456 doc = "
457[`write-float-exponent`]: https://docs.rs/lexical/latest/lexical/struct.WriteFloatOptionsBuilder.html#method.exponent
458[`write-float-decimal_point`]: https://docs.rs/lexical/latest/lexical/struct.WriteFloatOptionsBuilder.html#method.decimal_point
459[`write-float-nan_string`]: https://docs.rs/lexical/latest/lexical/struct.WriteFloatOptionsBuilder.html#method.nan_string
460[`write-float-trim_floats`]: https://docs.rs/lexical/latest/lexical/struct.WriteFloatOptionsBuilder.html#method.trim_floats
461[`write-float-positive_exponent_break`]: https://docs.rs/lexical/latest/lexical/struct.WriteFloatOptionsBuilder.html#method.positive_exponent_break
462[`write-float-max_significant_digits`]: https://docs.rs/lexical/latest/lexical/struct.WriteFloatOptionsBuilder.html#method.max_significant_digits
463[`write-float-min_significant_digits`]: https://docs.rs/lexical/latest/lexical/struct.WriteFloatOptionsBuilder.html#method.min_significant_digits
464[`write-float-round_mode`]: https://docs.rs/lexical/latest/lexical/struct.WriteFloatOptionsBuilder.html#method.round_mode
465"
466)]
467//!
468//! The available options are:
469#![cfg_attr(feature = "parse-floats", doc = " - [`ParseFloatOptions`]")]
470#![cfg_attr(feature = "parse-integers", doc = " - [`ParseIntegerOptions`]")]
471#![cfg_attr(feature = "write-floats", doc = " - [`WriteFloatOptions`]")]
472#![cfg_attr(feature = "write-integers", doc = " - [`WriteIntegerOptions`]")]
473//!
474//! In addition, pre-defined constants for each category of options may
475//! be found in their respective modules, for example, [`JSON`][`JSON-OPTS`].
476//!
477//! <!-- Spacer for Rustfmt -->
478#![cfg_attr(feature = "parse-floats", doc = "[`JSON-OPTS`]: parse_float_options::JSON")]
479#![cfg_attr(
480 not(feature = "parse-floats"),
481 doc = "[`JSON-OPTS`]: https://docs.rs/lexical/latest/lexical/parse_float_options/constant.JSON.html"
482)]
483//!
484//! ## Examples
485//!
486//! An example of creating your own options to parse European-style
487//! numbers (which use commas as decimal points, and periods as digit
488//! separators) is as follows:
489//!
490//! ```
491//! # #[cfg(all(feature = "parse-floats", feature = "format"))] {
492//! # use core::num;
493//! // This creates a format to parse a European-style float number.
494//! // The decimal point is a comma, and the digit separators (optional)
495//! // are periods.
496//! const EUROPEAN: u128 = lexical::NumberFormatBuilder::new()
497//! .digit_separator(num::NonZeroU8::new(b'.'))
498//! .build_strict();
499//! const COMMA_OPTIONS: lexical::ParseFloatOptions = lexical::ParseFloatOptions::builder()
500//! .decimal_point(b',')
501//! .build_strict();
502//! assert_eq!(
503//! lexical::parse_with_options::<f32, _, EUROPEAN>("300,10", &COMMA_OPTIONS),
504//! Ok(300.10)
505//! );
506//!
507//! // Another example, using a pre-defined constant for JSON.
508//! const JSON: u128 = lexical::format::JSON;
509//! const JSON_OPTIONS: lexical::ParseFloatOptions = lexical::ParseFloatOptions::new();
510//! assert_eq!(
511//! lexical::parse_with_options::<f32, _, JSON>("0e1", &JSON_OPTIONS),
512//! Ok(0.0)
513//! );
514//! assert_eq!(
515//! lexical::parse_with_options::<f32, _, JSON>("1E+2", &JSON_OPTIONS),
516//! Ok(100.0)
517//! );
518//! # }
519//! ```
520//!
521//! # Version Support
522//!
523//! The minimum, standard, required version is [`1.63.0`][`rust-1.63.0`], for
524//! const generic support. Older versions of lexical support older Rust
525//! versions.
526//!
527//! # Algorithms
528//!
529//! - [Parsing Floats](https://github.com/Alexhuszagh/rust-lexical/blob/main/lexical-parse-float/docs/Algorithm.md)
530//! - [Parsing Integers](https://github.com/Alexhuszagh/rust-lexical/blob/main/lexical-parse-integer/docs/Algorithm.md)
531//! - [Writing Floats](https://github.com/Alexhuszagh/rust-lexical/blob/main/lexical-write-float/docs/Algorithm.md)
532//! - [Writing Integers](https://github.com/Alexhuszagh/rust-lexical/blob/main/lexical-write-integer/docs/Algorithm.md)
533//!
534//! # Benchmarks
535//!
536//! - [Parsing Floats](https://github.com/Alexhuszagh/rust-lexical/blob/main/lexical-parse-float/docs/Benchmarks.md)
537//! - [Parsing Integers](https://github.com/Alexhuszagh/rust-lexical/blob/main/lexical-parse-integer/docs/Benchmarks.md)
538//! - [Writing Floats](https://github.com/Alexhuszagh/rust-lexical/blob/main/lexical-write-float/docs/Benchmarks.md)
539//! - [Writing Integers](https://github.com/Alexhuszagh/rust-lexical/blob/main/lexical-write-integer/docs/Benchmarks.md)
540//! - [Comprehensive Benchmarks](https://github.com/Alexhuszagh/lexical-benchmarks)
541//!
542//! A comprehensive analysis of lexical commits and their performance can be
543//! found in [benchmarks].
544//!
545//! # Design
546//!
547//! - [Binary Size](https://github.com/Alexhuszagh/rust-lexical/blob/main/docs/BinarySize.md)
548//! - [Build Timings](https://github.com/Alexhuszagh/rust-lexical/blob/main/docs/BuildTimings.md)
549//! - [Digit Separators](https://github.com/Alexhuszagh/rust-lexical/blob/main/docs/DigitSeparators.md)
550//!
551//! # Safety
552//!
553//! There is no non-trivial unsafe behavior in [lexical][crate] itself,
554//! however, any incorrect safety invariants in our parsers and writers
555//! (`lexical-parse-float`, `lexical-parse-integer`, `lexical-write-float`,
556//! and `lexical-write-integer`) could cause those safety invariants to
557//! be broken.
558//!
559//! <!-- Space for Rustfmt -->
560#![cfg_attr(
561 any(feature = "write-floats", feature = "write-integers"),
562 doc = "
563[`to_string`]: crate::to_string
564[`to_string_with_options`]: crate::to_string_with_options
565"
566)]
567#![cfg_attr(
568 not(any(feature = "write-floats", feature = "write-integers")),
569 doc = "
570[`to_string`]: https://docs.rs/lexical/latest/lexical/fn.to_string.html
571[`to_string_with_options`]: https://docs.rs/lexical/latest/lexical/fn.to_string_with_options.html
572"
573)]
574#![cfg_attr(
575 any(feature = "parse-floats", feature = "parse-integers"),
576 doc = "
577[`parse`]: crate::parse
578[`parse_partial`]: crate::parse_partial
579[`parse_with_options`]: crate::parse_with_options
580[`parse_partial_with_options`]: crate::parse_partial_with_options
581"
582)]
583#![cfg_attr(
584 not(any(feature = "parse-floats", feature = "parse-integers")),
585 doc = "
586[`parse`]: https://docs.rs/lexical/latest/lexical/fn.parse.html
587[`parse_partial`]: https://docs.rs/lexical/latest/lexical/fn.parse_partial.html
588[`parse_with_options`]: https://docs.rs/lexical/latest/lexical/fn.parse_with_options.html
589[`parse_partial_with_options`]: https://docs.rs/lexical/latest/lexical/fn.parse_partial_with_options.html
590"
591)]
592//!
593//! <!-- Space for Rustfmt -->
594#![cfg_attr(feature = "parse-floats", doc = "[`ParseFloatOptions`]: crate::ParseFloatOptions")]
595#![cfg_attr(feature = "parse-integers", doc = "[`ParseIntegerOptions`]: crate::ParseIntegerOptions")]
596#![cfg_attr(feature = "write-floats", doc = "[`WriteFloatOptions`]: crate::WriteFloatOptions")]
597#![cfg_attr(feature = "write-integers", doc = "[`WriteIntegerOptions`]: crate::WriteIntegerOptions")]
598//!
599//! [`NumberFormatBuilder`]: crate::NumberFormatBuilder
600//! [benchmarks]: https://github.com/Alexhuszagh/lexical-benchmarks
601//! [`rust-1.63.0`]: https://blog.rust-lang.org/2022/08/11/Rust-1.63.0.html
602
603// We want to have the same safety guarantees as Rust core,
604// so we allow unused unsafe to clearly document safety guarantees.
605#![allow(unused_unsafe)]
606#![cfg_attr(feature = "lint", warn(unsafe_op_in_unsafe_fn))]
607#![cfg_attr(not(feature = "std"), no_std)]
608#![cfg_attr(docsrs, feature(doc_cfg))]
609#![cfg_attr(docsrs, feature(doc_auto_cfg))]
610#![deny(
611 clippy::doc_markdown,
612 clippy::unnecessary_safety_comment,
613 clippy::semicolon_if_nothing_returned,
614 clippy::unwrap_used,
615 clippy::as_underscore
616)]
617#![allow(
618 // used when concepts are logically separate
619 clippy::match_same_arms,
620 // loss of precision is intentional
621 clippy::integer_division,
622 // mathematical names use 1-character identifiers
623 clippy::min_ident_chars,
624 // these are not cryptographically secure contexts
625 clippy::integer_division_remainder_used,
626 // this can be intentional
627 clippy::module_name_repetitions,
628 // this is intentional: already passing a pointer and need performance
629 clippy::needless_pass_by_value,
630 // we use this for inline formatting for unsafe blocks
631 clippy::semicolon_inside_block,
632)]
633#![cfg_attr(rustfmt, rustfmt_skip)] // reason = "this simplifies our imports"
634
635// Need an allocator for String/Vec.
636#[cfg(any(feature = "write-floats", feature = "write-integers"))]
637#[macro_use(vec)]
638extern crate alloc;
639
640#[cfg(any(feature = "write-floats", feature = "write-integers"))]
641use alloc::string::String;
642
643// Re-exports
644pub use lexical_core::Error;
645pub use lexical_core::Result;
646
647pub use lexical_core::format::{
648 self,
649 // FIXME: Do not export in the next breaking release.
650 format_error,
651 // FIXME: Do not export in the next breaking release.
652 format_is_valid,
653 NumberFormat,
654 NumberFormatBuilder,
655};
656
657#[cfg(feature = "f16")]
658pub use lexical_core::{bf16, f16};
659
660// PARSE
661
662#[cfg(any(feature = "parse-floats", feature = "parse-integers"))]
663pub use lexical_core::ParseOptions;
664
665#[cfg(any(feature = "parse-floats", feature = "parse-integers"))]
666pub use lexical_core::{FromLexical, FromLexicalWithOptions};
667
668#[cfg(feature = "parse-floats")]
669pub use lexical_core::{parse_float_options, ParseFloatOptions, ParseFloatOptionsBuilder};
670
671#[cfg(feature = "parse-integers")]
672pub use lexical_core::{parse_integer_options, ParseIntegerOptions, ParseIntegerOptionsBuilder};
673
674// WRITE
675
676#[cfg(any(feature = "write-floats", feature = "write-integers"))]
677pub use lexical_core::WriteOptions;
678
679#[cfg(any(feature = "write-floats", feature = "write-integers"))]
680pub use lexical_core::{ToLexical, ToLexicalWithOptions};
681
682#[cfg(any(feature = "write-floats", feature = "write-integers"))]
683pub use lexical_core::{FormattedSize, BUFFER_SIZE};
684
685#[cfg(feature = "write-floats")]
686pub use lexical_core::{write_float_options, WriteFloatOptions, WriteFloatOptionsBuilder};
687
688#[cfg(feature = "write-integers")]
689pub use lexical_core::{write_integer_options, WriteIntegerOptions, WriteIntegerOptionsBuilder};
690
691// NOTE: We cannot just use an uninitialized vector with excess capacity and
692// then use read-assign rather than `ptr::write` or `MaybeUninit.write` to
693// modify the values. When LLVM was the primary code generator, this was
694// **UNSPECIFIED** but not undefined behavior: reading undef primitives is safe:
695// https://llvm.org/docs/LangRef.html#undefined-values
696//
697// However, a different backend such as cranelift might make this undefined
698// behavior. That is, from the perspective of Rust, this is undefined behavior:
699//
700// ```rust
701// let x = Vec::<u8>::with_capacity(500);
702// let ptr = x.as_mut_ptr()
703// let slc = slice::from_raw_parts_mut(ptr, x.capacity())
704// // UB!!
705// slc[0] = 1;
706//
707// // Fine
708// ptr.write(1);
709// ```
710//
711// Currently, since LLVM treats it as unspecified behavior and will not drop
712// values, there is no risk of a memory leak and this is **currently** safe.
713// However, this can explode at any time, just like any undefined behavior.
714
715/// High-level conversion of a number to a decimal-encoded string.
716///
717/// * `n` - Number to convert to string.
718///
719/// # Examples
720///
721/// ```rust
722/// assert_eq!(lexical::to_string(5), "5");
723/// assert_eq!(lexical::to_string(0.0), "0.0");
724/// ```
725#[inline]
726#[cfg(any(feature = "write-floats", feature = "write-integers"))]
727pub fn to_string<N: ToLexical>(n: N) -> String {
728 let mut buf = vec![0u8; N::FORMATTED_SIZE_DECIMAL];
729 let len = lexical_core::write(n, buf.as_mut_slice()).len();
730
731 // SAFETY: safe since the buffer is of sufficient size, len() must be <= the vec
732 // size.
733 unsafe {
734 buf.set_len(len);
735 String::from_utf8_unchecked(buf)
736 }
737}
738
739/// High-level conversion of a number to a string with custom writing options.
740///
741/// * `FORMAT` - Packed struct containing the number format.
742/// * `n` - Number to convert to string.
743/// * `options` - Options to specify number writing.
744///
745/// # Examples
746///
747/// ```rust
748/// const FORMAT: u128 = lexical::format::STANDARD;
749/// const OPTIONS: lexical::WriteFloatOptions = lexical::WriteFloatOptions::builder()
750/// .trim_floats(true)
751/// .build_strict();
752/// assert_eq!(lexical::to_string_with_options::<_, FORMAT>(0.0, &OPTIONS), "0");
753/// assert_eq!(lexical::to_string_with_options::<_, FORMAT>(123.456, &OPTIONS), "123.456");
754/// ```
755#[inline]
756#[cfg(any(feature = "write-floats", feature = "write-integers"))]
757#[allow(deprecated)] // reason = "allow the user of `buffer_size`"
758pub fn to_string_with_options<N: ToLexicalWithOptions, const FORMAT: u128>(
759 n: N,
760 options: &N::Options,
761) -> String {
762 // Need to use the `buffer_size` hint to properly deal with float formatting
763 // options.
764 let size = N::Options::buffer_size::<N, FORMAT>(options);
765 let mut buf = vec![0u8; size];
766 let slc = buf.as_mut_slice();
767 let len = lexical_core::write_with_options::<_, FORMAT>(n, slc, options).len();
768
769 // SAFETY: safe since the buffer is of sufficient size, `len()` must be <= the
770 // vec size.
771 unsafe {
772 buf.set_len(len);
773 String::from_utf8_unchecked(buf)
774 }
775}
776
777/// High-level conversion of decimal-encoded bytes to a number.
778///
779/// This function only returns a value if the entire string is
780/// successfully parsed.
781///
782/// * `bytes` - Byte slice to convert to number.
783///
784/// # Examples
785///
786/// ```rust
787/// # use lexical::Error;
788/// // Create our error.
789/// fn error<T>(r: lexical::Result<T>) -> Error {
790/// r.err().unwrap()
791/// }
792///
793/// // String overloads
794/// assert_eq!(lexical::parse::<i32, _>("5"), Ok(5));
795/// assert!(lexical::parse::<i32, _>("1a").err().unwrap().is_invalid_digit());
796/// assert_eq!(lexical::parse::<f32, _>("0"), Ok(0.0));
797/// assert_eq!(lexical::parse::<f32, _>("1.0"), Ok(1.0));
798/// assert_eq!(lexical::parse::<f32, _>("1."), Ok(1.0));
799///
800/// // Bytes overloads
801/// assert_eq!(lexical::parse::<i32, _>(b"5"), Ok(5));
802/// assert!(lexical::parse::<f32, _>(b"1a").err().unwrap().is_invalid_digit());
803/// assert_eq!(lexical::parse::<f32, _>(b"0"), Ok(0.0));
804/// assert_eq!(lexical::parse::<f32, _>(b"1.0"), Ok(1.0));
805/// assert_eq!(lexical::parse::<f32, _>(b"1."), Ok(1.0));
806/// # assert_eq!(lexical::parse::<f32, _>(b"5.002868148396374"), Ok(5.002868148396374));
807/// # assert_eq!(lexical::parse::<f64, _>(b"5.002868148396374"), Ok(5.002868148396374));
808/// ```
809#[inline]
810#[cfg(any(feature = "parse-floats", feature = "parse-integers"))]
811pub fn parse<N: FromLexical, Bytes: AsRef<[u8]>>(bytes: Bytes) -> Result<N> {
812 N::from_lexical(bytes.as_ref())
813}
814
815/// High-level, partial conversion of decimal-encoded bytes to a number.
816///
817/// This functions parses as many digits as possible, returning the parsed
818/// value and the number of digits processed if at least one character
819/// is processed. If another error, such as numerical overflow or underflow
820/// occurs, this function returns the error code and the index at which
821/// the error occurred.
822///
823/// * `bytes` - Byte slice to convert to number.
824///
825/// # Examples
826///
827/// ```rust
828/// // String overloads
829/// assert_eq!(lexical::parse_partial::<i32, _>("5"), Ok((5, 1)));
830/// assert_eq!(lexical::parse_partial::<i32, _>("1a"), Ok((1, 1)));
831/// assert_eq!(lexical::parse_partial::<f32, _>("0"), Ok((0.0, 1)));
832/// assert_eq!(lexical::parse_partial::<f32, _>("1.0"), Ok((1.0, 3)));
833/// assert_eq!(lexical::parse_partial::<f32, _>("1."), Ok((1.0, 2)));
834///
835/// // Bytes overloads
836/// assert_eq!(lexical::parse_partial::<i32, _>(b"5"), Ok((5, 1)));
837/// assert_eq!(lexical::parse_partial::<i32, _>(b"1a"), Ok((1, 1)));
838/// assert_eq!(lexical::parse_partial::<f32, _>(b"0"), Ok((0.0, 1)));
839/// assert_eq!(lexical::parse_partial::<f32, _>(b"1.0"), Ok((1.0, 3)));
840/// assert_eq!(lexical::parse_partial::<f32, _>(b"1."), Ok((1.0, 2)));
841/// # assert_eq!(lexical::parse_partial::<f32, _>(b"5.002868148396374"), Ok((5.002868148396374, 17)));
842/// # assert_eq!(lexical::parse_partial::<f64, _>(b"5.002868148396374"), Ok((5.002868148396374, 17)));
843/// ```
844#[inline]
845#[cfg(any(feature = "parse-floats", feature = "parse-integers"))]
846pub fn parse_partial<N: FromLexical, Bytes: AsRef<[u8]>>(bytes: Bytes) -> Result<(N, usize)> {
847 N::from_lexical_partial(bytes.as_ref())
848}
849
850/// High-level conversion of bytes to a number with custom parsing options.
851///
852/// This function only returns a value if the entire string is
853/// successfully parsed.
854///
855/// * `FORMAT` - Packed struct containing the number format.
856/// * `bytes` - Byte slice to convert to number.
857/// * `options` - Options to specify number parsing.
858///
859/// # Panics
860///
861/// If the provided `FORMAT` is not valid, the function may panic. Please
862/// ensure `is_valid()` is called prior to using the format, or checking
863/// its validity using a static assertion.
864///
865/// # Examples
866///
867/// ```rust
868/// const FORMAT: u128 = lexical::format::STANDARD;
869/// const OPTIONS: lexical::ParseFloatOptions = lexical::ParseFloatOptions::builder()
870/// .exponent(b'^')
871/// .decimal_point(b',')
872/// .build_strict();
873/// assert_eq!(lexical::parse_with_options::<f32, _, FORMAT>("0", &OPTIONS), Ok(0.0));
874/// assert_eq!(lexical::parse_with_options::<f32, _, FORMAT>("1,2345", &OPTIONS), Ok(1.2345));
875/// assert_eq!(lexical::parse_with_options::<f32, _, FORMAT>("1,2345^4", &OPTIONS), Ok(12345.0));
876/// ```
877#[inline]
878#[cfg(any(feature = "parse-floats", feature = "parse-integers"))]
879pub fn parse_with_options<N: FromLexicalWithOptions, Bytes: AsRef<[u8]>, const FORMAT: u128>(
880 bytes: Bytes,
881 options: &N::Options,
882) -> Result<N> {
883 N::from_lexical_with_options::<FORMAT>(bytes.as_ref(), options)
884}
885
886/// High-level, partial conversion of bytes to a number with custom parsing
887/// options.
888///
889/// This functions parses as many digits as possible, returning the parsed
890/// value and the number of digits processed if at least one character
891/// is processed. If another error, such as numerical overflow or underflow
892/// occurs, this function returns the error code and the index at which
893/// the error occurred.
894///
895/// * `FORMAT` - Packed struct containing the number format.
896/// * `bytes` - Byte slice to convert to number.
897/// * `options` - Options to specify number parsing.
898///
899/// # Panics
900///
901/// If the provided `FORMAT` is not valid, the function may panic. Please
902/// ensure `is_valid()` is called prior to using the format, or checking
903/// its validity using a static assertion.
904///
905/// # Examples
906///
907/// ```rust
908/// const FORMAT: u128 = lexical::format::STANDARD;
909/// const OPTIONS: lexical::ParseFloatOptions = lexical::ParseFloatOptions::builder()
910/// .exponent(b'^')
911/// .decimal_point(b',')
912/// .build_strict();
913/// assert_eq!(lexical::parse_partial_with_options::<f32, _, FORMAT>("0", &OPTIONS), Ok((0.0, 1)));
914/// assert_eq!(lexical::parse_partial_with_options::<f32, _, FORMAT>("1,2345", &OPTIONS), Ok((1.2345, 6)));
915/// assert_eq!(lexical::parse_partial_with_options::<f32, _, FORMAT>("1,2345^4", &OPTIONS), Ok((12345.0, 8)));
916/// ```
917#[inline]
918#[cfg(any(feature = "parse-floats", feature = "parse-integers"))]
919pub fn parse_partial_with_options<
920 N: FromLexicalWithOptions,
921 Bytes: AsRef<[u8]>,
922 const FORMAT: u128,
923>(
924 bytes: Bytes,
925 options: &N::Options,
926) -> Result<(N, usize)> {
927 N::from_lexical_partial_with_options::<FORMAT>(bytes.as_ref(), options)
928}