Skip to main content

num_literal_traits/
lib.rs

1// Copyright 2025 Sascha Klick
2//
3// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
4// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
5// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
6// option. This file may not be copied, modified, or distributed
7// except according to those terms.
8
9//! Parsing common formats numeric literal formats
10//!
11//! ## Compatibility
12//!
13//! The `num-literal-traits` crate is tested for rustc 1.88 and greater.
14use num_traits::Num;
15
16/// The trait adds String parsing functions to types already implementing
17/// the num_traits::Num trait.
18pub trait NumLiteralTrait<T: Num>: Num {
19    
20    /// Determine the literal type, then convert to a number value or
21    /// return an error.
22    /// 
23    /// # Arguments
24    /// - `text`: Textual representation of a number.    
25    /// # Returns
26    /// - Numerical result or error.
27    ///
28    /// # Examples
29    ///
30    /// ```rust
31    /// use num_traits::Num;
32    /// use num_literal_traits::NumLiteralTrait;
33    ///
34    /// let result = u32::parse_literal("0xCAFE");
35    /// assert_eq!(result, Ok(0xcafe));
36    /// 
37    /// let result = u32::parse_literal("0b1000_0001_1111_1010");
38    /// assert_eq!(result, Ok(33274));
39    ///
40    /// let result = u32::parse_literal("CAFE");
41    /// assert!(result.is_err());
42    /// 
43    /// let result = u32::parse_literal("'A'");
44    /// assert_eq!(result, Ok(65));
45    /// ```
46    ///
47    /// # Supported formats
48    ///
49    /// Most integer literal formats found in C and C++ are supported:
50    /// Binary      : `0b100010`, `0B0`, `0b10101101`
51    /// Octal       : `0123`, `00`, `04763523`
52    /// Decimal     : `123`, `0`, `7635223`    
53    /// Hexadecimal : `0xCAFE`, `0x0`, `0xa1fb484`
54    /// Char        : `'A'`, `'!'`
55    ///
56    /// Additionally, the numeric parts can contain underscores `_` to
57    /// which get removed before converting.    
58    fn parse_literal(text: &str) -> Result<T, T::FromStrRadixErr>;
59    
60    /// Determine the literal type, then convert to a number value or
61    /// return the provided fallback if the parsing fails.
62    ///
63    /// # Arguments
64    /// - `text`: Textual representation of a number.    
65    /// - `fallback`: Fallback return value if the parsing fails.
66    /// # Returns
67    /// - Numerical result, either the parsed value or the fallback.
68    ///  
69    /// # Examples
70    ///
71    /// ```rust
72    /// use num_traits::Num;
73    /// use num_literal_traits::NumLiteralTrait;
74    ///
75    /// let result = u32::parse_literal_fallback("0xCAFE", 0xfabc);
76    /// assert_eq!(result, 0xcafe);
77    ///
78    /// let result = u32::parse_literal_fallback("CAFE", 0xfabc);
79    /// assert_eq!(result, 0xfabc);
80    ///     
81    /// let result = u32::parse_literal_fallback("'全'", 0xfabc);
82    /// assert_eq!(result, 0xfabc);
83    ///    
84    /// ```
85    fn parse_literal_fallback(text: &str, fallback: T) -> T;
86}
87
88mod parse_literal;
89
90#[cfg(test)]
91mod tests {    
92    use super::*;
93    
94    #[test]
95
96    fn null_works() {
97        let result = u32::parse_literal("0");
98        assert_eq!(result, Ok(0));    
99    }
100    fn binary_works() {
101        let result = u32::parse_literal("0B1000111011000010");
102        assert_eq!(result, Ok(36546));    
103    }
104    
105    #[test]
106    fn octal_works() {
107        let result = u32::parse_literal("0723642");
108        assert_eq!(result, Ok(239522));    
109    }
110
111    #[test]
112    fn decimal_works() {
113        let result = u32::parse_literal("9823642");
114        assert_eq!(result, Ok(9823642));    
115    }
116
117    #[test]
118    fn hexadecimal_works() {
119        let result = u32::parse_literal("0xA82c6fE");
120        assert_eq!(result, Ok(0xa82c6fe));    
121    }
122
123    #[test]
124    fn fallback_works() {
125        let result = u32::parse_literal_fallback("random text", 0xCAFE);
126        assert_eq!(result, 0xcafe);  
127    }
128
129    #[test]
130    fn underscores_works() {
131        let result = u32::parse_literal("0b1101_0011_1000_0111");
132        assert_eq!(result, Ok(54151));  
133    }
134
135    #[test]
136    fn random_text_fails() {
137        let res = u32::parse_literal("t322545");
138        assert!(res.is_err());
139    }
140
141    #[test]
142    fn empty_char_fails() {
143        let res = u32::parse_literal("''");
144        assert!(res.is_err());
145    }
146
147    #[test]
148    fn multiple_chars_fails() {
149        let res = u32::parse_literal("'ABC'");
150        assert!(res.is_err());
151    }
152
153    #[test]
154    fn nonascii_chars_fails() {
155        let res = u32::parse_literal("'全'");
156        assert!(res.is_err());
157    }
158
159}