lib.rs - source (original) (raw)

fast_float/

lib.rs

1//! This crate provides a super-fast decimal number parser from strings into floats.
2//!
3//! ## Usage
4//!
5//! There's two top-level functions provided: [`parse`](crate::parse()) and
6//! [`parse_partial`](crate::parse_partial()), both taking
7//! either a string or a bytes slice and parsing the input into either `f32` or `f64`:
8//!
9//! - [`parse`](crate::parse()) treats the whole string as a decimal number and returns an
10//!   error if there are invalid characters or if the string is empty.
11//! - [`parse_partial`](crate::parse_partial()) tries to find the longest substring at the
12//! beginning of the given input string that can be parsed as a decimal number and,
13//! in the case of success, returns the parsed value along the number of characters processed;
14//! an error is returned if the string doesn't start with a decimal number or if it is empty.
15//! This function is most useful as a building block when constructing more complex parsers,
16//! or when parsing streams of data.
17//!
18//! ## Examples
19//!
20//! ```rust
21//! // Parse the entire string as a decimal number.
22//! let s = "1.23e-02";
23//! let x: f32 = fast_float::parse(s).unwrap();
24//! assert_eq!(x, 0.0123);
25//!
26//! // Parse as many characters as possible as a decimal number.
27//! let s = "1.23e-02foo";
28//! let (x, n) = fast_float::parse_partial::<f32, _>(s).unwrap();
29//! assert_eq!(x, 0.0123);
30//! assert_eq!(n, 8);
31//! assert_eq!(&s[n..], "foo");
32//! ```
33
34#![warn(clippy::all, clippy::pedantic, clippy::nursery, clippy::cargo)]
35#![allow(
36    clippy::cast_possible_truncation,
37    clippy::cast_possible_wrap,
38    clippy::cast_sign_loss,
39    clippy::cast_lossless,
40    clippy::cast_precision_loss,
41    clippy::missing_const_for_fn,
42    clippy::use_self,
43    clippy::module_name_repetitions,
44    clippy::cargo_common_metadata
45)]
46
47use core::fmt::{self, Display};
48
49mod binary;
50mod common;
51mod decimal;
52mod float;
53mod number;
54mod parse;
55mod simple;
56mod table;
57
58/// Opaque error type for fast-float parsing functions.
59#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
60pub struct Error;
61
62impl Display for Error {
63    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
64        write!(f, "error while parsing a float")
65    }
66}
67
68#[cfg(feature = "std")]
69impl std::error::Error for Error {
70    fn description(&self) -> &str {
71        "error while parsing a float"
72    }
73}
74
75/// Result type alias for fast-float parsing functions.
76pub type Result<T> = core::result::Result<T, Error>;
77
78/// Trait for numerical float types that can be parsed from string.
79pub trait FastFloat: float::Float {
80    /// Parse a decimal number from string into float (full).
81    ///
82    /// # Errors
83    ///
84    /// Will return an error either if the string is not a valid decimal number.
85    /// or if any characterse are left remaining unparsed.
86    #[inline]
87    fn parse_float<S: AsRef<[u8]>>(s: S) -> Result<Self> {
88        let s = s.as_ref();
89        match Self::parse_float_partial(s) {
90            Ok((v, n)) if n == s.len() => Ok(v),
91            _ => Err(Error),
92        }
93    }
94
95    /// Parse a decimal number from string into float (partial).
96    ///
97    /// This method parses as many characters as possible and returns the resulting number along
98    /// with the number of digits processed (in case of success, this number is always positive).
99    ///
100    /// # Errors
101    ///
102    /// Will return an error either if the string doesn't start with a valid decimal number
103    /// – that is, if no zero digits were processed.
104    #[inline]
105    fn parse_float_partial<S: AsRef<[u8]>>(s: S) -> Result<(Self, usize)> {
106        parse::parse_float(s.as_ref()).ok_or(Error)
107    }
108}
109
110impl FastFloat for f32 {}
111impl FastFloat for f64 {}
112
113/// Parse a decimal number from string into float (full).
114///
115/// # Errors
116///
117/// Will return an error either if the string is not a valid decimal number
118/// or if any characterse are left remaining unparsed.
119#[inline]
120pub fn parse<T: FastFloat, S: AsRef<[u8]>>(s: S) -> Result<T> {
121    T::parse_float(s)
122}
123
124/// Parse a decimal number from string into float (partial).
125///
126/// This function parses as many characters as possible and returns the resulting number along
127/// with the number of digits processed (in case of success, this number is always positive).
128///
129/// # Errors
130///
131/// Will return an error either if the string doesn't start with a valid decimal number
132/// – that is, if no zero digits were processed.
133#[inline]
134pub fn parse_partial<T: FastFloat, S: AsRef<[u8]>>(s: S) -> Result<(T, usize)> {
135    T::parse_float_partial(s)
136}