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();