lexical_parse_integer/
options.rs

1//! Configuration options for parsing integers.
2//!
3//! # Pre-Defined Formats
4//!
5//! This contains pre-defined options optimized for either the parsing of large
6//! or small numbers.
7//! - [`SMALL_NUMBERS`][`SMALL_NUMBERS`]: Optimize the parsing of small
8//!   integers, at a major performance cost to larger values.
9//! - [`LARGE_NUMBERS`][`LARGE_NUMBERS`]: Optimize the parsing of large
10//!   integers, at a slight performance cost to smaller values.
11//!
12//! # Examples
13//!
14//! ```rust
15//! use lexical_parse_integer::{FromLexicalWithOptions, Options};
16//! use lexical_parse_integer::format::STANDARD;
17//!
18//! const OPTIONS: Options = Options::builder()
19//!     .no_multi_digit(true)
20//!     .build_strict();
21//!
22//! let value = "1234";
23//! let result = u64::from_lexical_with_options::<STANDARD>(value.as_bytes(), &OPTIONS);
24//! assert_eq!(result, Ok(1234));
25//! ```
26
27use lexical_util::options::ParseOptions;
28use lexical_util::result::Result;
29
30/// Builder for [`Options`].
31///
32/// # Examples
33///
34/// ```rust
35/// use lexical_parse_integer::{FromLexicalWithOptions, Options};
36/// use lexical_parse_integer::format::STANDARD;
37///
38/// const OPTIONS: Options = Options::builder()
39///     .no_multi_digit(true)
40///     .build_strict();
41///
42/// let value = "1234";
43/// let result = u64::from_lexical_with_options::<STANDARD>(value.as_bytes(), &OPTIONS);
44/// assert_eq!(result, Ok(1234));
45/// ```
46#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
47pub struct OptionsBuilder {
48    /// Disable multi-digit optimizations.
49    ///
50    /// Using multi-digit optimizations allows parsing many digits
51    /// from longer input strings at once which can dramatically
52    /// improve performance (>70%) for long strings, but the
53    /// increased branching can decrease performance for simple
54    /// strings by 5-20%. Choose based on your inputs.
55    no_multi_digit: bool,
56}
57
58impl OptionsBuilder {
59    /// Create new options builder with default options.
60    #[inline(always)]
61    pub const fn new() -> Self {
62        Self {
63            no_multi_digit: true,
64        }
65    }
66
67    // GETTERS
68
69    /// Get if we disable the use of multi-digit optimizations.
70    ///
71    /// Defaults to [`true`].
72    ///
73    /// # Examples
74    ///
75    /// ```rust
76    /// use lexical_parse_integer::Options;
77    ///
78    /// let builder = Options::builder();
79    /// assert_eq!(builder.get_no_multi_digit(), true);
80    /// ```
81    #[inline(always)]
82    pub const fn get_no_multi_digit(&self) -> bool {
83        self.no_multi_digit
84    }
85
86    // SETTERS
87
88    /// Set if we disable the use of multi-digit optimizations.
89    ///
90    /// Defaults to [`true`].
91    ///
92    /// # Examples
93    ///
94    /// ```rust
95    /// use lexical_parse_integer::Options;
96    ///
97    /// const OPTIONS: Options = Options::builder()
98    ///     .no_multi_digit(false)
99    ///     .build_strict();
100    /// assert_eq!(OPTIONS.get_no_multi_digit(), false);
101    /// ```
102    #[inline(always)]
103    pub const fn no_multi_digit(mut self, no_multi_digit: bool) -> Self {
104        self.no_multi_digit = no_multi_digit;
105        self
106    }
107
108    // BUILDERS
109
110    /// Check if the builder state is valid (always [`true`]).
111    #[inline(always)]
112    pub const fn is_valid(&self) -> bool {
113        true
114    }
115
116    /// Build the [`Options`] struct without validation.
117    ///
118    /// <div class="warning">
119    ///
120    /// This is completely safe, however, misusing this could cause panics at
121    /// runtime. Always check if [`is_valid`] prior to using the built
122    /// options.
123    ///
124    /// </div>
125    ///
126    /// [`is_valid`]: Self::is_valid
127    #[inline(always)]
128    pub const fn build_unchecked(&self) -> Options {
129        Options {
130            no_multi_digit: self.no_multi_digit,
131        }
132    }
133
134    /// Build the [`Options`] struct.
135    ///
136    /// This can never panic.
137    ///
138    /// <!-- # Panics
139    ///
140    /// If the built options are not valid. This should always
141    /// be used within a const context to avoid panics at runtime.
142    /// -->
143    #[inline(always)]
144    pub const fn build_strict(&self) -> Options {
145        match self.build() {
146            Ok(value) => value,
147            Err(error) => core::panic!("{}", error.description()),
148        }
149    }
150
151    /// Build the [`Options`] struct. Always [`Ok`].
152    #[inline(always)]
153    pub const fn build(&self) -> Result<Options> {
154        Ok(self.build_unchecked())
155    }
156}
157
158impl Default for OptionsBuilder {
159    #[inline(always)]
160    fn default() -> Self {
161        Self::new()
162    }
163}
164
165/// Options to customize the parsing integers.
166///
167/// # Examples
168///
169/// ```rust
170/// use lexical_parse_integer::{FromLexicalWithOptions, Options};
171/// use lexical_parse_integer::format::STANDARD;
172///
173/// const OPTIONS: Options = Options::builder()
174///     .no_multi_digit(true)
175///     .build_strict();
176///
177/// let value = "1234";
178/// let result = u64::from_lexical_with_options::<STANDARD>(value.as_bytes(), &OPTIONS);
179/// assert_eq!(result, Ok(1234));
180/// ```
181#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
182pub struct Options {
183    /// Disable multi-digit optimizations.
184    ///
185    /// Using multi-digit optimizations allows parsing many digits
186    /// from longer input strings at once which can dramatically
187    /// improve performance (>70%) for long strings, but the
188    /// increased branching can decrease performance for simple
189    /// strings by 5-20%. Choose based on your inputs.
190    no_multi_digit: bool,
191}
192
193impl Options {
194    /// Create [`Options`] with default values.
195    #[must_use]
196    #[inline(always)]
197    pub const fn new() -> Self {
198        Self::builder().build_unchecked()
199    }
200
201    /// Create the default options for a given radix.
202    #[inline(always)]
203    #[cfg(feature = "power-of-two")]
204    pub const fn from_radix(_: u8) -> Self {
205        Self::new()
206    }
207
208    // GETTERS
209
210    /// Check if the builder state is valid (always [`true`]).
211    #[inline(always)]
212    pub const fn is_valid(&self) -> bool {
213        self.rebuild().is_valid()
214    }
215
216    /// Get if we disable the use of multi-digit optimizations.
217    ///
218    /// Defaults to [`true`].
219    ///
220    /// # Examples
221    ///
222    /// ```rust
223    /// use lexical_parse_integer::options::Options;
224    ///
225    /// const OPTIONS: Options = Options::builder()
226    ///     .no_multi_digit(true)
227    ///     .build_strict();
228    /// assert_eq!(OPTIONS.get_no_multi_digit(), true);
229    /// ```
230    #[inline(always)]
231    pub const fn get_no_multi_digit(&self) -> bool {
232        self.no_multi_digit
233    }
234
235    // SETTERS
236
237    /// Set if we disable the use of multi-digit optimizations.
238    #[deprecated = "Setters should have a `set_` prefix. Use `set_no_multi_digit` instead. Will be removed in 2.0."]
239    #[inline(always)]
240    pub fn no_multi_digit(&mut self, no_multi_digit: bool) {
241        self.no_multi_digit = no_multi_digit;
242    }
243
244    /// Set if we disable the use of multi-digit optimizations.
245    #[deprecated = "Options should be treated as immutable, use `OptionsBuilder` instead. Will be removed in 2.0."]
246    #[inline(always)]
247    pub fn set_no_multi_digit(&mut self, no_multi_digit: bool) {
248        self.no_multi_digit = no_multi_digit;
249    }
250
251    // BUILDERS
252
253    /// Get [`OptionsBuilder`] as a static function.
254    #[inline(always)]
255    pub const fn builder() -> OptionsBuilder {
256        OptionsBuilder::new()
257    }
258
259    /// Create [`OptionsBuilder`] using existing values.
260    #[inline(always)]
261    pub const fn rebuild(&self) -> OptionsBuilder {
262        OptionsBuilder {
263            no_multi_digit: self.no_multi_digit,
264        }
265    }
266}
267
268impl Default for Options {
269    #[inline(always)]
270    fn default() -> Self {
271        Self::new()
272    }
273}
274
275impl ParseOptions for Options {
276    #[inline(always)]
277    fn is_valid(&self) -> bool {
278        Self::is_valid(self)
279    }
280}
281
282// PRE-DEFINED CONSTANTS
283// ---------------------
284
285/// Standard number format.
286#[rustfmt::skip]
287pub const STANDARD: Options = Options::new();
288
289/// Options optimized for small numbers.
290#[rustfmt::skip]
291pub const SMALL_NUMBERS: Options = Options::builder()
292    .no_multi_digit(true)
293    .build_strict();
294
295/// Options optimized for large numbers and long strings.
296#[rustfmt::skip]
297pub const LARGE_NUMBERS: Options = Options::builder()
298    .no_multi_digit(false)
299    .build_strict();