1 //! Wrap the low-level API into idiomatic serializers. 2 3 use super::format::NumberFormat; 4 use super::num::Number; 5 use super::result::Result; 6 7 // HELPERS 8 9 /// Map partial result to complete result. 10 macro_rules! to_complete { 11 ($cb:expr, $bytes:expr $(,$args:expr)*) => { 12 match $cb($bytes $(,$args)*) { 13 Err(e) => Err(e), 14 Ok((value, processed)) => if processed == $bytes.len() { 15 Ok(value) 16 } else{ 17 Err((ErrorCode::InvalidDigit, processed).into()) 18 } 19 } 20 }; 21 } 22 23 // FROM LEXICAL 24 25 /// Trait for numerical types that can be parsed from bytes. 26 pub trait FromLexical: Number { 27 /// Checked parser for a string-to-number conversion. 28 /// 29 /// This method parses the entire string, returning an error if 30 /// any invalid digits are found during parsing. 31 /// 32 /// Returns a `Result` containing either the parsed value, 33 /// or an error containing any errors that occurred during parsing. 34 /// 35 /// Numeric overflow takes precedence over the presence of an invalid 36 /// digit, and therefore may mask an invalid digit error. 37 /// 38 /// * `bytes` - Slice containing a numeric string. from_lexical(bytes: &[u8]) -> Result<Self>39 fn from_lexical(bytes: &[u8]) -> Result<Self>; 40 41 /// Checked parser for a string-to-number conversion. 42 /// 43 /// This method parses until an invalid digit is found (or the end 44 /// of the string), returning the number of processed digits 45 /// and the parsed value until that point. 46 /// 47 /// Returns a `Result` containing either the parsed value 48 /// and the number of processed digits, or an error containing 49 /// any errors that occurred during parsing. 50 /// 51 /// * `bytes` - Slice containing a numeric string. from_lexical_partial(bytes: &[u8]) -> Result<(Self, usize)>52 fn from_lexical_partial(bytes: &[u8]) -> Result<(Self, usize)>; 53 54 /// Checked parser for a string-to-number conversion. 55 /// 56 /// This method parses the entire string, returning an error if 57 /// any invalid digits are found during parsing. 58 /// 59 /// Returns a `Result` containing either the parsed value, 60 /// or an error containing any errors that occurred during parsing. 61 /// 62 /// Numeric overflow takes precedence over the presence of an invalid 63 /// digit, and therefore may mask an invalid digit error. 64 /// 65 /// * `bytes` - Slice containing a numeric string. 66 /// * `radix` - Radix for the number parsing. 67 /// 68 /// # Panics 69 /// 70 /// Panics if the radix is not in the range `[2, 36]`. 71 #[cfg(feature = "radix")] from_lexical_radix(bytes: &[u8], radix: u8) -> Result<Self>72 fn from_lexical_radix(bytes: &[u8], radix: u8) -> Result<Self>; 73 74 /// Checked parser for a string-to-number conversion. 75 /// 76 /// This method parses until an invalid digit is found (or the end 77 /// of the string), returning the number of processed digits 78 /// and the parsed value until that point. 79 /// 80 /// Returns a `Result` containing either the parsed value 81 /// and the number of processed digits, or an error containing 82 /// any errors that occurred during parsing. 83 /// 84 /// * `bytes` - Slice containing a numeric string. 85 /// * `radix` - Radix for the number parsing. 86 /// 87 /// # Panics 88 /// 89 /// Panics if the radix is not in the range `[2, 36]`. 90 #[cfg(feature = "radix")] from_lexical_partial_radix(bytes: &[u8], radix: u8) -> Result<(Self, usize)>91 fn from_lexical_partial_radix(bytes: &[u8], radix: u8) -> Result<(Self, usize)>; 92 } 93 94 // Implement FromLexical for numeric type. 95 macro_rules! from_lexical { 96 ($cb:expr, $t:ty) => ( 97 impl FromLexical for $t { 98 #[inline] 99 fn from_lexical(bytes: &[u8]) -> Result<$t> 100 { 101 to_complete!($cb, bytes, 10) 102 } 103 104 #[inline] 105 fn from_lexical_partial(bytes: &[u8]) -> Result<($t, usize)> 106 { 107 $cb(bytes, 10) 108 } 109 110 #[cfg(feature = "radix")] 111 #[inline] 112 fn from_lexical_radix(bytes: &[u8], radix: u8) -> Result<$t> 113 { 114 to_complete!($cb, bytes, radix.as_u32()) 115 } 116 117 #[cfg(feature = "radix")] 118 #[inline] 119 fn from_lexical_partial_radix(bytes: &[u8], radix: u8) -> Result<($t, usize)> 120 { 121 $cb(bytes, radix.as_u32()) 122 } 123 } 124 ) 125 } 126 127 // FROM LEXICAL LOSSY 128 129 /// Trait for floating-point types that can be parsed using lossy algorithms from bytes. 130 pub trait FromLexicalLossy: FromLexical { 131 /// Lossy, checked parser for a string-to-number conversion. 132 /// 133 /// This method parses the entire string, returning an error if 134 /// any invalid digits are found during parsing. This parser is 135 /// lossy, so numerical rounding may occur during parsing. 136 /// 137 /// Returns a `Result` containing either the parsed value, 138 /// or an error containing any errors that occurred during parsing. 139 /// 140 /// * `bytes` - Slice containing a numeric string. from_lexical_lossy(bytes: &[u8]) -> Result<Self>141 fn from_lexical_lossy(bytes: &[u8]) -> Result<Self>; 142 143 /// Lossy, checked parser for a string-to-number conversion. 144 /// 145 /// This method parses until an invalid digit is found (or the end 146 /// of the string), returning the number of processed digits 147 /// and the parsed value until that point. This parser is 148 /// lossy, so numerical rounding may occur during parsing. 149 /// 150 /// Returns a `Result` containing either the parsed value 151 /// and the number of processed digits, or an error containing 152 /// any errors that occurred during parsing. 153 /// 154 /// * `bytes` - Slice containing a numeric string. from_lexical_partial_lossy(bytes: &[u8]) -> Result<(Self, usize)>155 fn from_lexical_partial_lossy(bytes: &[u8]) -> Result<(Self, usize)>; 156 157 /// Lossy, checked parser for a string-to-number conversion. 158 /// 159 /// This method parses the entire string, returning an error if 160 /// any invalid digits are found during parsing. This parser is 161 /// lossy, so numerical rounding may occur during parsing. 162 /// 163 /// Returns a `Result` containing either the parsed value, 164 /// or an error containing any errors that occurred during parsing. 165 /// 166 /// * `bytes` - Slice containing a numeric string. 167 /// * `radix` - Radix for the number parsing. 168 /// 169 /// # Panics 170 /// 171 /// Panics if the radix is not in the range `[2, 36]`. 172 #[cfg(feature = "radix")] from_lexical_lossy_radix(bytes: &[u8], radix: u8) -> Result<Self>173 fn from_lexical_lossy_radix(bytes: &[u8], radix: u8) -> Result<Self>; 174 175 /// Lossy, checked parser for a string-to-number conversion. 176 /// 177 /// This method parses until an invalid digit is found (or the end 178 /// of the string), returning the number of processed digits 179 /// and the parsed value until that point. This parser is 180 /// lossy, so numerical rounding may occur during parsing. 181 /// 182 /// Returns a `Result` containing either the parsed value 183 /// and the number of processed digits, or an error containing 184 /// any errors that occurred during parsing. 185 /// 186 /// * `bytes` - Slice containing a numeric string. 187 /// * `radix` - Radix for the number parsing. 188 /// 189 /// # Panics 190 /// 191 /// Panics if the radix is not in the range `[2, 36]`. 192 #[cfg(feature = "radix")] from_lexical_partial_lossy_radix(bytes: &[u8], radix: u8) -> Result<(Self, usize)>193 fn from_lexical_partial_lossy_radix(bytes: &[u8], radix: u8) -> Result<(Self, usize)>; 194 } 195 196 // Implement FromLexicalLossy for numeric type. 197 macro_rules! from_lexical_lossy { 198 ($cb:expr, $t:ty) => ( 199 impl FromLexicalLossy for $t { 200 #[inline] 201 fn from_lexical_lossy(bytes: &[u8]) -> Result<$t> 202 { 203 to_complete!($cb, bytes, 10) 204 } 205 206 #[inline] 207 fn from_lexical_partial_lossy(bytes: &[u8]) -> Result<($t, usize)> 208 { 209 $cb(bytes, 10) 210 } 211 212 #[cfg(feature = "radix")] 213 #[inline] 214 fn from_lexical_lossy_radix(bytes: &[u8], radix: u8) -> Result<$t> 215 { 216 to_complete!($cb, bytes, radix.as_u32()) 217 } 218 219 #[cfg(feature = "radix")] 220 #[inline] 221 fn from_lexical_partial_lossy_radix(bytes: &[u8], radix: u8) -> Result<($t, usize)> 222 { 223 $cb(bytes, radix.as_u32()) 224 } 225 } 226 ) 227 } 228 229 // FROM LEXICAL FORMAT 230 231 /// Trait for number that can be parsed using a custom format specification. 232 #[cfg(feature = "format")] 233 pub trait FromLexicalFormat: FromLexical { 234 /// Checked parser for a string-to-number conversion. 235 /// 236 /// This method parses the entire string, returning an error if 237 /// any invalid digits are found during parsing. The numerical format 238 /// is specified by the format bitflags, which customize the required 239 /// components, digit separators, and other parameters of the number. 240 /// 241 /// Returns a `Result` containing either the parsed value, 242 /// or an error containing any errors that occurred during parsing. 243 /// 244 /// * `bytes` - Slice containing a numeric string. 245 /// * `format` - Numerical format. from_lexical_format(bytes: &[u8], format: NumberFormat) -> Result<Self>246 fn from_lexical_format(bytes: &[u8], format: NumberFormat) -> Result<Self>; 247 248 /// Checked parser for a string-to-number conversion. 249 /// 250 /// This method parses until an invalid digit is found (or the end 251 /// of the string), returning the number of processed digits 252 /// and the parsed value until that point. The numerical format 253 /// is specified by the format bitflags, which customize the required 254 /// components, digit separators, and other parameters of the number. 255 /// 256 /// Returns a `Result` containing either the parsed value 257 /// and the number of processed digits, or an error containing 258 /// any errors that occurred during parsing. 259 /// 260 /// * `bytes` - Slice containing a numeric string. 261 /// * `format` - Numerical format. from_lexical_partial_format(bytes: &[u8], format: NumberFormat) -> Result<(Self, usize)>262 fn from_lexical_partial_format(bytes: &[u8], format: NumberFormat) -> Result<(Self, usize)>; 263 264 /// Checked parser for a string-to-number conversion. 265 /// 266 /// This method parses the entire string, returning an error if 267 /// any invalid digits are found during parsing. The numerical format 268 /// is specified by the format bitflags, which customize the required 269 /// components, digit separators, and other parameters of the number. 270 /// 271 /// Returns a `Result` containing either the parsed value, 272 /// or an error containing any errors that occurred during parsing. 273 /// 274 /// * `bytes` - Slice containing a numeric string. 275 /// * `radix` - Radix for the number parsing. 276 /// * `format` - Numerical format. 277 /// 278 /// # Panics 279 /// 280 /// Panics if the radix is not in the range `[2, 36]`. 281 #[cfg(feature = "radix")] from_lexical_format_radix(bytes: &[u8], radix: u8, format: NumberFormat) -> Result<Self>282 fn from_lexical_format_radix(bytes: &[u8], radix: u8, format: NumberFormat) -> Result<Self>; 283 284 /// Checked parser for a string-to-number conversion. 285 /// 286 /// This method parses until an invalid digit is found (or the end 287 /// of the string), returning the number of processed digits 288 /// and the parsed value until that point. The numerical format 289 /// is specified by the format bitflags, which customize the required 290 /// components, digit separators, and other parameters of the number. 291 /// 292 /// Returns a `Result` containing either the parsed value 293 /// and the number of processed digits, or an error containing 294 /// any errors that occurred during parsing. 295 /// 296 /// * `bytes` - Slice containing a numeric string. 297 /// * `radix` - Radix for the number parsing. 298 /// * `format` - Numerical format. 299 /// 300 /// # Panics 301 /// 302 /// Panics if the radix is not in the range `[2, 36]`. 303 #[cfg(feature = "radix")] from_lexical_partial_format_radix(bytes: &[u8], radix: u8, format: NumberFormat) -> Result<(Self, usize)>304 fn from_lexical_partial_format_radix(bytes: &[u8], radix: u8, format: NumberFormat) -> Result<(Self, usize)>; 305 } 306 307 // Implement FromLexicalFormat for numeric type. 308 #[cfg(feature = "format")] 309 macro_rules! from_lexical_format { 310 ($cb:expr, $t:ty) => ( 311 impl FromLexicalFormat for $t { 312 #[inline] 313 fn from_lexical_format(bytes: &[u8], format: NumberFormat) -> Result<$t> 314 { 315 to_complete!($cb, bytes, 10, format) 316 } 317 318 #[inline] 319 fn from_lexical_partial_format(bytes: &[u8], format: NumberFormat) -> Result<($t, usize)> 320 { 321 $cb(bytes, 10, format) 322 } 323 324 #[cfg(feature = "radix")] 325 #[inline] 326 fn from_lexical_format_radix(bytes: &[u8], radix: u8, format: NumberFormat) -> Result<$t> 327 { 328 to_complete!($cb, bytes, radix.as_u32(), format) 329 } 330 331 #[cfg(feature = "radix")] 332 #[inline] 333 fn from_lexical_partial_format_radix(bytes: &[u8], radix: u8, format: NumberFormat) -> Result<($t, usize)> 334 { 335 $cb(bytes, radix.as_u32(), format) 336 } 337 } 338 ) 339 } 340 341 // FROM LEXICAL LOSSY 342 343 /// Trait for floating-point types that can be parsed using lossy algorithms with a custom format specification. 344 #[cfg(feature = "format")] 345 pub trait FromLexicalLossyFormat: FromLexical { 346 /// Lossy, checked parser for a string-to-number conversion. 347 /// 348 /// This method parses the entire string, returning an error if 349 /// any invalid digits are found during parsing. This parser is 350 /// lossy, so numerical rounding may occur during parsing. The 351 /// numerical format is specified by the format bitflags, which 352 /// customize the required components, digit separators, and other 353 /// parameters of the number. 354 /// 355 /// Returns a `Result` containing either the parsed value, 356 /// or an error containing any errors that occurred during parsing. 357 /// 358 /// * `bytes` - Slice containing a numeric string. 359 /// * `format` - Numerical format. from_lexical_lossy_format(bytes: &[u8], format: NumberFormat) -> Result<Self>360 fn from_lexical_lossy_format(bytes: &[u8], format: NumberFormat) -> Result<Self>; 361 362 /// Lossy, checked parser for a string-to-number conversion. 363 /// 364 /// This method parses until an invalid digit is found (or the end 365 /// of the string), returning the number of processed digits 366 /// and the parsed value until that point. This parser is 367 /// lossy, so numerical rounding may occur during parsing. The 368 /// numerical format is specified by the format bitflags, which 369 /// customize the required components, digit separators, and other 370 /// parameters of the number. 371 /// 372 /// Returns a `Result` containing either the parsed value 373 /// and the number of processed digits, or an error containing 374 /// any errors that occurred during parsing. 375 /// 376 /// * `bytes` - Slice containing a numeric string. 377 /// * `format` - Numerical format. from_lexical_partial_lossy_format(bytes: &[u8], format: NumberFormat) -> Result<(Self, usize)>378 fn from_lexical_partial_lossy_format(bytes: &[u8], format: NumberFormat) -> Result<(Self, usize)>; 379 380 /// Lossy, checked parser for a string-to-number conversion. 381 /// 382 /// This method parses the entire string, returning an error if 383 /// any invalid digits are found during parsing. This parser is 384 /// lossy, so numerical rounding may occur during parsing. The 385 /// numerical format is specified by the format bitflags, which 386 /// customize the required components, digit separators, and other 387 /// parameters of the number. 388 /// 389 /// Returns a `Result` containing either the parsed value, 390 /// or an error containing any errors that occurred during parsing. 391 /// 392 /// * `bytes` - Slice containing a numeric string. 393 /// * `radix` - Radix for the number parsing. 394 /// * `format` - Numerical format. 395 /// 396 /// # Panics 397 /// 398 /// Panics if the radix is not in the range `[2, 36]`. 399 #[cfg(feature = "radix")] from_lexical_lossy_format_radix(bytes: &[u8], radix: u8, format: NumberFormat) -> Result<Self>400 fn from_lexical_lossy_format_radix(bytes: &[u8], radix: u8, format: NumberFormat) -> Result<Self>; 401 402 /// Lossy, checked parser for a string-to-number conversion. 403 /// 404 /// This method parses until an invalid digit is found (or the end 405 /// of the string), returning the number of processed digits 406 /// and the parsed value until that point. This parser is 407 /// lossy, so numerical rounding may occur during parsing. The 408 /// numerical format is specified by the format bitflags, which 409 /// customize the required components, digit separators, and other 410 /// parameters of the number. 411 /// 412 /// Returns a `Result` containing either the parsed value 413 /// and the number of processed digits, or an error containing 414 /// any errors that occurred during parsing. 415 /// 416 /// * `bytes` - Slice containing a numeric string. 417 /// * `radix` - Radix for the number parsing. 418 /// * `format` - Numerical format. 419 /// 420 /// # Panics 421 /// 422 /// Panics if the radix is not in the range `[2, 36]`. 423 #[cfg(feature = "radix")] from_lexical_partial_lossy_format_radix(bytes: &[u8], radix: u8, format: NumberFormat) -> Result<(Self, usize)>424 fn from_lexical_partial_lossy_format_radix(bytes: &[u8], radix: u8, format: NumberFormat) -> Result<(Self, usize)>; 425 } 426 427 // Implement FromLexicalLossyFormat for numeric type. 428 #[cfg(feature = "format")] 429 macro_rules! from_lexical_lossy_format { 430 ($cb:expr, $t:ty) => ( 431 impl FromLexicalLossyFormat for $t { 432 #[inline] 433 fn from_lexical_lossy_format(bytes: &[u8], format: NumberFormat) 434 -> Result<$t> 435 { 436 to_complete!($cb, bytes, 10, format) 437 } 438 439 #[inline] 440 fn from_lexical_partial_lossy_format(bytes: &[u8], format: NumberFormat) 441 -> Result<($t, usize)> 442 { 443 $cb(bytes, 10, format) 444 } 445 446 #[cfg(feature = "radix")] 447 #[inline] 448 fn from_lexical_lossy_format_radix(bytes: &[u8], radix: u8, format: NumberFormat) 449 -> Result<$t> 450 { 451 to_complete!($cb, bytes, radix.as_u32(), format) 452 } 453 454 #[cfg(feature = "radix")] 455 #[inline] 456 fn from_lexical_partial_lossy_format_radix(bytes: &[u8], radix: u8, format: NumberFormat) 457 -> Result<($t, usize)> 458 { 459 $cb(bytes, radix.as_u32(), format) 460 } 461 } 462 ) 463 } 464 465 // TO LEXICAL 466 467 /// Trait for numerical types that can be serialized to bytes. 468 /// 469 /// To determine the number of bytes required to serialize a value to 470 /// string, check the associated constants from a required trait: 471 /// - [`FORMATTED_SIZE`] 472 /// - [`FORMATTED_SIZE_DECIMAL`] 473 /// 474 /// [`FORMATTED_SIZE`]: trait.Number.html#associatedconstant.FORMATTED_SIZE 475 /// [`FORMATTED_SIZE_DECIMAL`]: trait.Number.html#associatedconstant.FORMATTED_SIZE_DECIMAL 476 pub trait ToLexical: Number { 477 /// Serializer for a number-to-string conversion. 478 /// 479 /// Returns a subslice of the input buffer containing the written bytes, 480 /// starting from the same address in memory as the input slice. 481 /// 482 /// * `value` - Number to serialize. 483 /// * `bytes` - Slice containing a numeric string. 484 /// 485 /// # Panics 486 /// 487 /// Panics if the buffer is not of sufficient size. The caller 488 /// must provide a slice of sufficient size. In order to ensure 489 /// the function will not panic, ensure the buffer has at least 490 /// [`FORMATTED_SIZE_DECIMAL`] elements. 491 /// 492 /// [`FORMATTED_SIZE_DECIMAL`]: trait.Number.html#associatedconstant.FORMATTED_SIZE_DECIMAL to_lexical<'a>(self, bytes: &'a mut [u8]) -> &'a mut [u8]493 fn to_lexical<'a>(self, bytes: &'a mut [u8]) -> &'a mut [u8]; 494 495 /// Serializer for a number-to-string conversion. 496 /// 497 /// Returns a subslice of the input buffer containing the written bytes, 498 /// starting from the same address in memory as the input slice. 499 /// 500 /// * `value` - Number to serialize. 501 /// * `radix` - Radix for number encoding. 502 /// * `bytes` - Slice containing a numeric string. 503 /// 504 /// # Panics 505 /// 506 /// Panics if the radix is not in the range `[2, 36]`. 507 /// 508 /// Also panics if the buffer is not of sufficient size. The caller 509 /// must provide a slice of sufficient size. In order to ensure 510 /// the function will not panic, ensure the buffer has at least 511 /// [`FORMATTED_SIZE`] elements. 512 /// 513 /// [`FORMATTED_SIZE`]: trait.Number.html#associatedconstant.FORMATTED_SIZE 514 #[cfg(feature = "radix")] to_lexical_radix<'a>(self, radix: u8, bytes: &'a mut [u8]) -> &'a mut [u8]515 fn to_lexical_radix<'a>(self, radix: u8, bytes: &'a mut [u8]) -> &'a mut [u8]; 516 } 517 518 // Implement ToLexical for numeric type. 519 macro_rules! to_lexical { 520 ($cb:expr, $t:ty) => ( 521 impl ToLexical for $t { 522 #[inline] 523 fn to_lexical<'a>(self, bytes: &'a mut [u8]) 524 -> &'a mut [u8] 525 { 526 assert_buffer!(10, bytes, $t); 527 let len = $cb(self, 10, bytes); 528 &mut index_mut!(bytes[..len]) 529 } 530 531 #[cfg(feature = "radix")] 532 #[inline] 533 fn to_lexical_radix<'a>(self, radix: u8, bytes: &'a mut [u8]) 534 -> &'a mut [u8] 535 { 536 assert_radix!(radix); 537 assert_buffer!(radix, bytes, $t); 538 let len = $cb(self, radix.as_u32(), bytes); 539 &mut index_mut!(bytes[..len]) 540 } 541 } 542 ) 543 } 544