1 //! Fast lexical conversion routines with a C FFI for a no_std environment.
2 //!
3 //! # Getting Started
4 //!
5 //! lexical-core is a low-level, partially FFI-compatible API for
6 //! number-to-string and string-to-number conversions, without requiring
7 //! a system allocator. If you would like to use a convenient, high-level
8 //! API, please look at [lexical](https://crates.io/crates/lexical) instead.
9 //!
10 //! # Getting Started
11 //!
12 //! ```rust
13 //! extern crate lexical_core;
14 //!
15 //! // String to number using slices
16 //! // The argument is the byte string parsed.
17 //! let f = lexical_core::atof64_slice(b"3.5");   // 3.5
18 //! let i = lexical_core::atoi32_slice(b"15");    // 15
19 //!
20 //! // String to number using pointer ranges, for FFI-compatible code.
21 //! // The first argument is a pointer to the start of the parsed byte array,
22 //! // and the second argument is a pointer to 1-past-the-end. It will process
23 //! // bytes in the range [first, last).
24 //! unsafe {
25 //!     let bytes = b"3.5";
26 //!     let first = bytes.as_ptr();
27 //!     let last = first.add(bytes.len());
28 //!     let f = lexical_core::atof64_range(first, last);
29 //! }
30 //!
31 //! // If and only if the `radix` feature is enabled, you may use the radix
32 //! // overloads to parse non-decimal floats and strings.
33 //! ##[cfg(feature = "radix")]
34 //! let f = lexical_core::atof32_radix_slice(2, b"11.1");   // 3.5
35 //! ##[cfg(feature = "radix")]
36 //! let i = lexical_core::atoi32_radix_slice(2, b"1111");   // 15
37 //!
38 //! // The ato*_slice and ato*_range parsers are not checked, they do not
39 //! // validate that the input data is entirely correct, and discard trailing
40 //! // bytes that are found. The explicit behavior is to wrap on overflow, and
41 //! // to discard invalid digits.
42 //! let i = lexical_core::atoi8_slice(b"256");    // 0, wraps from 256
43 //! let i = lexical_core::atoi8_slice(b"1a5");    // 1, discards "a5"
44 //!
45 //! // You should prefer the checked parsers, whenever possible. These detect
46 //! // numeric overflow, and no invalid trailing digits are present.
47 //! // The error code for success is 0, all errors are less than 0.
48 //!
49 //! // Ideally, everything works great.
50 //! let res = lexical_core::try_atoi8_slice(b"15");
51 //! assert_eq!(res.error.code, lexical_core::ErrorCode::Success);
52 //! assert_eq!(res.value, 15);
53 //!
54 //! // However, it detects numeric overflow, setting `res.error.code`
55 //! // to the appropriate value.
56 //! let res = lexical_core::try_atoi8_slice(b"256");
57 //! assert_eq!(res.error.code, lexical_core::ErrorCode::Overflow);
58 //!
59 //! // Errors occurring prematurely terminating the parser due to invalid
60 //! // digits return the index in the buffer where the invalid digit was
61 //! // seen. This may useful in contexts like serde, which require numerical
62 //! // parsers from complex data without having to extract a substring
63 //! // containing only numeric data ahead of time. If the error is set
64 //! // to a `InvalidDigit`, the value is guaranteed to be accurate up until
65 //! // that point. For example, if the trailing data is whitespace,
66 //! // the value from an invalid digit may be perfectly valid in some contexts.
67 //! let res = lexical_core::try_atoi8_slice(b"15 45");
68 //! assert_eq!(res.error.code, lexical_core::ErrorCode::InvalidDigit);
69 //! assert_eq!(res.error.index, 2);
70 //! assert_eq!(res.value, 15);
71 //!
72 //! // Number to string using slices.
73 //! // The first argument is the value, the second argument is the radix,
74 //! // and the third argument is the buffer to write to.
75 //! // The function returns a subslice of the original buffer, and will
76 //! // always start at the same position (`buf.as_ptr() == slc.as_ptr()`).
77 //! let mut buf = [b'0'; lexical_core::MAX_I64_SIZE];
78 //! let slc = lexical_core::i64toa_slice(15, &mut buf);
79 //! assert_eq!(slc, b"15");
80 //!
81 //! // If an insufficiently long buffer is passed, the serializer will panic.
82 //! // PANICS
83 //! let mut buf = [b'0'; 1];
84 //! //let slc = lexical_core::i64toa_slice(15, &mut buf);
85 //!
86 //! // In order to guarantee the buffer is long enough, always ensure there
87 //! // are at least `MAX_XX_SIZE`, where XX is the type name in upperase,
88 //! // IE, for `isize`, `MAX_ISIZE_SIZE`.
89 //! let mut buf = [b'0'; lexical_core::MAX_F64_SIZE];
90 //! let slc = lexical_core::f64toa_slice(15.1, &mut buf);
91 //! assert_eq!(slc, b"15.1");
92 //! ```
93 
94 // FEATURES
95 
96 // Require intrinsics in a no_std context.
97 #![cfg_attr(not(feature = "std"), no_std)]
98 #![cfg_attr(all(not(feature = "std"), feature = "correct", feature = "radix"), feature(alloc))]
99 #![cfg_attr(not(feature = "std"), feature(core_intrinsics))]
100 #![cfg_attr(all(not(test), not(feature = "std")), feature(lang_items))]
101 
102 // DEPENDENCIES
103 
104 #[macro_use]
105 extern crate cfg_if;
106 
107 #[cfg(feature = "correct")]
108 #[allow(unused_imports)]    // Not used before 1.26.
109 #[macro_use]
110 extern crate static_assertions;
111 
112 // Testing assertions for floating-point equality.
113 #[cfg(test)]
114 #[macro_use]
115 extern crate approx;
116 
117 // Test against randomly-generated data.
118 #[cfg(test)]
119 #[macro_use]
120 extern crate quickcheck;
121 
122 // Test against randomly-generated guided data.
123 #[cfg(test)]
124 #[macro_use]
125 extern crate proptest;
126 
127 // Use vec if there is a system allocator, which we require only if
128 // we're using the correct and radix features.
129 #[cfg(all(not(feature = "std"), feature = "correct", feature = "radix"))]
130 #[cfg_attr(test, macro_use)]
131 extern crate alloc;
132 
133 // Use stackvector for atof.
134 #[cfg(feature = "correct")]
135 #[macro_use]
136 extern crate stackvector;
137 
138 // Ensure only one back-end is enabled.
139 #[cfg(all(feature = "grisu3", feature = "ryu"))]
140 compile_error!("Lexical only accepts one of the following backends: `grisu3` or `ryu`.");
141 
142 // Import the back-end, if applicable.
143 cfg_if! {
144 if #[cfg(feature = "grisu3")] {
145     extern crate dtoa;
146 } else if #[cfg(feature = "ryu")] {
147     extern crate ryu;
148 }}  // cfg_if
149 
150 /// Facade around the core features for name mangling.
151 pub(crate) mod lib {
152 #[cfg(feature = "std")]
153 pub(crate) use std::*;
154 
155 #[cfg(not(feature = "std"))]
156 pub(crate) use core::*;
157 
158 cfg_if! {
159 if #[cfg(all(feature = "correct", feature = "radix"))] {
160     #[cfg(feature = "std")]
161     pub(crate) use std::vec::Vec;
162 
163     #[cfg(not(feature = "std"))]
164     pub(crate) use alloc::vec::Vec;
165 }}  // cfg_if
166 
167 }   // lib
168 
169 // PANIC
170 
171 // Need to define a panic handler when we're not testing (panic handler
172 // then becomes "unwind" but there is no_std). This causes us to fail
173 // with doctests, so ensure `--tests` is passed to `cargo test` whenever
174 // we are in a  `no_std` context.
175 cfg_if! {
176 if #[cfg(all(not(test), not(feature = "std")))] {
177     use lib::intrinsics;
178     use lib::panic::PanicInfo;
179 
180     #[panic_handler]
181     fn panic(_: &PanicInfo) -> ! {
182         unsafe {
183             intrinsics::abort();
184         }
185     }
186 
187     #[lang = "eh_personality"]
188     extern fn eh_personality() {}
189 }}  // cfg_if
190 
191 // API
192 
193 // Hide implementation details
194 #[macro_use]
195 mod util;
196 
197 mod atof;
198 mod atoi;
199 mod float;
200 mod ftoa;
201 mod itoa;
202 
203 // Publicly re-export the low-level string-to-float functions.
204 pub use atof::*;
205 
206 // Publicly re-export the low-level string-to-integer functions.
207 pub use atoi::*;
208 
209 // Publicly re-export the low-level float-to-string functions.
210 pub use ftoa::*;
211 
212 // Publicly re-export the low-level integer-to-string functions.
213 pub use itoa::*;
214 
215 // Re-export configuration and utilities globally.
216 pub use util::*;
217