@@ -49,7 +49,7 @@ pub const POWERS_10: [i32; DIG_PER_DEC + 1] = [
49
49
///
50
50
/// * serialization/deserialization to/from binary format
51
51
/// (see `read_bin` and `write_bin` functions);
52
- /// * parsing from decimal string/buffer (see `Decimal::parse_bytes `, `FromStr` impl);
52
+ /// * parsing from decimal string/buffer (see `Decimal::parse_str_bytes `, `FromStr` impl);
53
53
/// * conversion to decimal string (using `Display`).
54
54
///
55
55
/// # Notes
@@ -58,7 +58,7 @@ pub const POWERS_10: [i32; DIG_PER_DEC + 1] = [
58
58
/// i.e. both `rhs` and `lhs` will be serialized into temporary buffers;
59
59
/// * even though MySql's `string2decimal` function allows scientific notation,
60
60
/// this implementation denies it.
61
- #[ derive( Default , Debug , Eq ) ]
61
+ #[ derive( Default , Debug , Eq , Clone ) ]
62
62
pub struct Decimal {
63
63
/// The number of *decimal* digits (NOT number of `Digit`s!) before the point.
64
64
intg : usize ,
@@ -75,13 +75,33 @@ impl Decimal {
75
75
decimal_bin_size ( self . intg + self . frac , self . frac )
76
76
}
77
77
78
+ /// See [`Decimal::parse_str_bytes`].
79
+ #[ deprecated = "use parse_str_bytes" ]
78
80
pub fn parse_bytes ( bytes : & [ u8 ] ) -> Result < Self , ParseDecimalError > {
79
81
match std:: str:: from_utf8 ( bytes) {
80
82
Ok ( string) => Decimal :: from_str ( string) ,
81
83
Err ( _) => Err ( ParseDecimalError ) ,
82
84
}
83
85
}
84
86
87
+ /// Runs `Decimal::from_str` on the given bytes.
88
+ pub fn parse_str_bytes ( bytes : & [ u8 ] ) -> Result < Self , ParseDecimalError > {
89
+ macro_rules! decimal_str {
90
+ ( $x: ident) => {
91
+ if $x
92
+ . iter( )
93
+ . all( |x| x. is_ascii_digit( ) || * x == b'+' || matches!( x, b'-' ..=b'.' ) )
94
+ {
95
+ // SAFETY: UTF-8 is asserted by the if condition
96
+ Some ( unsafe { std:: str :: from_utf8_unchecked( $x) } )
97
+ } else {
98
+ None
99
+ }
100
+ } ;
101
+ }
102
+ Decimal :: from_str ( decimal_str ! ( bytes) . ok_or ( ParseDecimalError ) ?)
103
+ }
104
+
85
105
pub fn write_bin < T : Write > ( & self , mut output : T ) -> io:: Result < ( ) > {
86
106
// result bits must be inverted if the sign is negative,
87
107
// we'll XOR it with `mask` to achieve this.
@@ -139,6 +159,27 @@ impl Decimal {
139
159
output. write_all ( & out_buf)
140
160
}
141
161
162
+ /// Reads packed representation of a [`Decimal`].
163
+ ///
164
+ /// Packed representation is:
165
+ ///
166
+ /// 1. precision (u8)
167
+ /// 2. scale (u8)
168
+ /// 3. serialized decimal value (see [`Decimal::read_bin`])
169
+ pub fn read_packed < T : Read > ( mut input : T , keep_precision : bool ) -> io:: Result < Self > {
170
+ let mut precision_and_scale = [ 0_u8 , 0_u8 ] ;
171
+ input. read_exact ( & mut precision_and_scale) ?;
172
+ Self :: read_bin (
173
+ input,
174
+ precision_and_scale[ 0 ] as usize ,
175
+ precision_and_scale[ 1 ] as usize ,
176
+ keep_precision,
177
+ )
178
+ }
179
+
180
+ /// Reads serialized representation of a decimal value.
181
+ ///
182
+ /// The value is usually written in the packed form (see [`Decimal::read_packed`]).
142
183
pub fn read_bin < T : Read > (
143
184
mut input : T ,
144
185
precision : usize ,
@@ -158,10 +199,10 @@ impl Decimal {
158
199
159
200
// is it negative or not
160
201
let mask = if buffer. first ( ) . copied ( ) . unwrap_or ( 0 ) & 0x80 == 0 {
161
- // positive, so mask should do noghing
202
+ // positive, so mask should do nothing
162
203
0
163
204
} else {
164
- // negative, so mask snould invert bits
205
+ // negative, so mask should invert bits
165
206
-1
166
207
} ;
167
208
0 commit comments