datetime_string/common/secfrac_digits.rs
1//! Digits of fractions of a second.
2
3#[cfg(feature = "alloc")]
4mod owned;
5
6use core::{
7 cmp,
8 convert::TryFrom,
9 fmt,
10 ops::{self, RangeTo},
11 str,
12};
13
14use crate::{
15 error::{ComponentKind, Error, ErrorKind},
16 parse::parse_digits8,
17};
18
19#[cfg(feature = "alloc")]
20pub use self::owned::SecfracDigitsString;
21
22/// Range of a milliseconds part.
23const MILLI_RANGE: RangeTo<usize> = ..3;
24/// Range of a microsecodns part.
25const MICRO_RANGE: RangeTo<usize> = ..6;
26/// Range of a milliseconds part.
27const NANO_RANGE: RangeTo<usize> = ..9;
28
29/// Validates the given string as digits of fractions of a second.
30///
31/// This function ensures that the given bytes is not empty and consists of only ASCII digits.
32fn validate_bytes(s: &[u8]) -> Result<(), Error> {
33 if s.is_empty() {
34 return Err(ErrorKind::TooShort.into());
35 }
36
37 if !s.iter().all(u8::is_ascii_digit) {
38 return Err(ErrorKind::InvalidComponentType(ComponentKind::Secfrac).into());
39 }
40
41 Ok(())
42}
43
44/// String slice for digits of fractions of a second.
45///
46/// Note that values of this type cannot be not empty string.
47#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
48#[repr(transparent)]
49// Note that `derive(Serialize)` cannot used here, because it encodes this as
50// `[u8]` rather than as a string.
51//
52// Comparisons implemented for the type are consistent (at least it is intended to be so).
53// See <https://github.com/rust-lang/rust-clippy/issues/2025>.
54// Note that `clippy::derive_ord_xor_partial_ord` would be introduced since Rust 1.47.0.
55#[allow(clippy::derive_hash_xor_eq)]
56#[allow(unknown_lints, clippy::derive_ord_xor_partial_ord)]
57pub struct SecfracDigitsStr([u8]);
58
59impl SecfracDigitsStr {
60 /// Creates a `&SecfracDigitsStr` from the given byte slice.
61 ///
62 /// This performs assertion in debug build, but not in release build.
63 ///
64 /// # Safety
65 ///
66 /// `validate_bytes(s)` should return `Ok(())`.
67 #[inline]
68 #[must_use]
69 pub(crate) unsafe fn from_bytes_maybe_unchecked(s: &[u8]) -> &Self {
70 debug_assert_ok!(validate_bytes(s));
71 &*(s as *const [u8] as *const Self)
72 }
73
74 /// Creates a `&mut SecfracDigitsStr` from the given mutable byte slice.
75 ///
76 /// This performs assertion in debug build, but not in release build.
77 ///
78 /// # Safety
79 ///
80 /// `validate_bytes(s)` should return `Ok(())`.
81 #[inline]
82 #[must_use]
83 pub(crate) unsafe fn from_bytes_maybe_unchecked_mut(s: &mut [u8]) -> &mut Self {
84 debug_assert_ok!(validate_bytes(s));
85 &mut *(s as *mut [u8] as *mut Self)
86 }
87
88 /// Creates a `&mut SecfracDigitsStr` from the given mutable string slice.
89 ///
90 /// This performs assertion in debug build, but not in release build.
91 ///
92 /// # Safety
93 ///
94 /// `validate_bytes(s.as_bytes())` should return `Ok(())`.
95 #[inline]
96 #[must_use]
97 unsafe fn from_str_maybe_unchecked_mut(s: &mut str) -> &mut Self {
98 // This is safe because `SecfracDigitsStr` ensures that the underlying
99 // bytes are ASCII string after modification.
100 Self::from_bytes_maybe_unchecked_mut(s.as_bytes_mut())
101 }
102
103 /// Creates a new `&SecfracDigitsStr` from a string slice.
104 ///
105 /// # Examples
106 ///
107 /// ```
108 /// # use datetime_string::common::SecfracDigitsStr;
109 /// let secfrac = SecfracDigitsStr::from_str("1234")?;
110 /// assert_eq!(secfrac.as_str(), "1234");
111 ///
112 /// assert!(SecfracDigitsStr::from_str("0").is_ok());
113 /// assert!(SecfracDigitsStr::from_str("0000000000").is_ok());
114 /// assert!(SecfracDigitsStr::from_str("9999999999").is_ok());
115 ///
116 /// assert!(SecfracDigitsStr::from_str("").is_err(), "Fractions should not be empty");
117 /// assert!(SecfracDigitsStr::from_str(".0").is_err(), "Only digits are allowed");
118 /// # Ok::<_, datetime_string::Error>(())
119 /// ```
120 #[inline]
121 // `FromStr` trait cannot be implemented for a slice.
122 #[allow(clippy::should_implement_trait)]
123 pub fn from_str(s: &str) -> Result<&Self, Error> {
124 TryFrom::try_from(s)
125 }
126
127 /// Creates a new `&mut SecfracDigitsStr` from a mutable string slice.
128 ///
129 /// # Examples
130 ///
131 /// ```
132 /// # use datetime_string::common::SecfracDigitsStr;
133 /// let mut buf = "1234".to_owned();
134 /// let secfrac = SecfracDigitsStr::from_mut_str(&mut buf)?;
135 /// assert_eq!(secfrac.as_str(), "1234");
136 ///
137 /// secfrac.fill_with_zero();
138 /// assert_eq!(secfrac.as_str(), "0000");
139 ///
140 /// assert_eq!(buf, "0000");
141 /// # Ok::<_, datetime_string::Error>(())
142 /// ```
143 #[inline]
144 pub fn from_mut_str(s: &mut str) -> Result<&mut Self, Error> {
145 TryFrom::try_from(s)
146 }
147
148 /// Creates a new `&SecfracDigitsStr` from a byte slice.
149 ///
150 /// # Examples
151 ///
152 /// ```
153 /// # use datetime_string::common::SecfracDigitsStr;
154 /// let secfrac = SecfracDigitsStr::from_str("1234")?;
155 /// assert_eq!(secfrac.as_str(), "1234");
156 ///
157 /// assert!(SecfracDigitsStr::from_str("0").is_ok());
158 /// assert!(SecfracDigitsStr::from_str("0000000000").is_ok());
159 /// assert!(SecfracDigitsStr::from_str("9999999999").is_ok());
160 ///
161 /// assert!(SecfracDigitsStr::from_str("").is_err(), "Fractions should not be empty");
162 /// assert!(SecfracDigitsStr::from_str(".0").is_err(), "Only digits are allowed");
163 /// # Ok::<_, datetime_string::Error>(())
164 /// ```
165 #[inline]
166 pub fn from_bytes(s: &[u8]) -> Result<&Self, Error> {
167 TryFrom::try_from(s)
168 }
169
170 /// Creates a new `&mut SecfracDigitsStr` from a mutable byte slice.
171 ///
172 /// # Examples
173 ///
174 /// ```
175 /// # use datetime_string::common::SecfracDigitsStr;
176 /// let mut buf: [u8; 4] = *b"1234";
177 /// let secfrac = SecfracDigitsStr::from_bytes_mut(&mut buf)?;
178 /// assert_eq!(secfrac.as_str(), "1234");
179 ///
180 /// secfrac.fill_with_zero();
181 /// assert_eq!(secfrac.as_str(), "0000");
182 ///
183 /// assert_eq!(&buf[..], b"0000");
184 /// # Ok::<_, datetime_string::Error>(())
185 /// ```
186 #[inline]
187 pub fn from_bytes_mut(s: &mut [u8]) -> Result<&mut Self, Error> {
188 TryFrom::try_from(s)
189 }
190
191 /// Returns a string slice.
192 ///
193 /// # Examples
194 ///
195 /// ```
196 /// # use datetime_string::common::SecfracDigitsStr;
197 /// let secfrac = SecfracDigitsStr::from_str("1234")?;
198 ///
199 /// assert_eq!(secfrac.as_str(), "1234");
200 /// # Ok::<_, datetime_string::Error>(())
201 /// ```
202 #[inline]
203 #[must_use]
204 pub fn as_str(&self) -> &str {
205 unsafe {
206 // This is safe because the `SecfracDigitsStr` ensures that the
207 // underlying bytes are ASCII string.
208 debug_assert_safe_version_ok!(str::from_utf8(&self.0));
209 str::from_utf8_unchecked(&self.0)
210 }
211 }
212
213 /// Returns a byte slice.
214 ///
215 /// # Examples
216 ///
217 /// ```
218 /// # use datetime_string::common::SecfracDigitsStr;
219 /// let secfrac = SecfracDigitsStr::from_str("1234")?;
220 ///
221 /// assert_eq!(secfrac.as_str(), "1234");
222 /// # Ok::<_, datetime_string::Error>(())
223 /// ```
224 #[inline]
225 #[must_use]
226 pub fn as_bytes(&self) -> &[u8] {
227 &self.0
228 }
229
230 /// Retruns a milliseconds value in integer.
231 ///
232 /// # Examples
233 ///
234 /// ```
235 /// # use datetime_string::common::SecfracDigitsStr;
236 /// let not_precise = SecfracDigitsStr::from_str("1")?;
237 /// assert_eq!(not_precise.milliseconds(), 100);
238 ///
239 /// let precise = SecfracDigitsStr::from_str("012")?;
240 /// assert_eq!(precise.milliseconds(), 12);
241 ///
242 /// let more_precise = SecfracDigitsStr::from_str("369999")?;
243 /// assert_eq!(more_precise.milliseconds(), 369);
244 /// # Ok::<_, datetime_string::Error>(())
245 /// ```
246 #[inline]
247 #[must_use]
248 pub fn milliseconds(&self) -> u16 {
249 let bytes = &self.0;
250 match self.len() {
251 1 => (bytes[0] - b'0') as u16 * 100,
252 2 => (bytes[0] - b'0') as u16 * 100 + (bytes[1] - b'0') as u16 * 10,
253 _ => {
254 debug_assert!(self.len() >= 3);
255 (bytes[0] - b'0') as u16 * 100
256 + (bytes[1] - b'0') as u16 * 10
257 + (bytes[2] - b'0') as u16
258 }
259 }
260 }
261
262 /// Returns a milliseconds precision substring if there are enough digits.
263 ///
264 /// # Examples
265 ///
266 /// ```
267 /// # use datetime_string::common::SecfracDigitsStr;
268 /// let not_precise = SecfracDigitsStr::from_str("1")?;
269 /// assert_eq!(not_precise.milliseconds_digits(), None);
270 ///
271 /// let precise = SecfracDigitsStr::from_str("012")?;
272 /// assert_eq!(precise.milliseconds_digits().unwrap(), "012");
273 ///
274 /// let more_precise = SecfracDigitsStr::from_str("012345678901")?;
275 /// assert_eq!(more_precise.milliseconds_digits().unwrap(), "012");
276 /// # Ok::<_, datetime_string::Error>(())
277 /// ```
278 #[inline]
279 #[must_use]
280 pub fn milliseconds_digits(&self) -> Option<&SecfracDigitsStr> {
281 self.0.get(MILLI_RANGE).map(|s| unsafe {
282 debug_assert_ok!(validate_bytes(s));
283 debug_assert_safe_version_ok!(<&Self>::try_from(s));
284 // This is safe because `self.0` consists of only ASCII digits,
285 // and so is the substring.
286 Self::from_bytes_maybe_unchecked(s)
287 })
288 }
289
290 /// Returns a milliseconds precision substring if there are enough digits.
291 ///
292 /// # Examples
293 ///
294 /// ```
295 /// # use datetime_string::common::SecfracDigitsStr;
296 /// let mut buf = "012345678901".to_owned();
297 /// let digits = SecfracDigitsStr::from_mut_str(&mut buf)?;
298 /// assert_eq!(digits.as_str(), "012345678901");
299 ///
300 /// digits.milliseconds_digits_mut().unwrap().fill_with_zero();
301 /// assert_eq!(digits.as_str(), "000345678901");
302 /// # Ok::<_, datetime_string::Error>(())
303 /// ```
304 #[inline]
305 #[must_use]
306 pub fn milliseconds_digits_mut(&mut self) -> Option<&mut SecfracDigitsStr> {
307 self.0.get_mut(MILLI_RANGE).map(|s| {
308 unsafe {
309 // This is safe because `self.0` consists of only ASCII digits,
310 // and so is the substring.
311 debug_assert_ok!(Self::from_bytes(s));
312 Self::from_bytes_maybe_unchecked_mut(s)
313 }
314 })
315 }
316
317 /// Returns a milliseconds digits as a fixed bytes slice, if there are enough digits.
318 ///
319 /// # Examples
320 ///
321 /// ```
322 /// # use datetime_string::common::SecfracDigitsStr;
323 /// let not_precise = SecfracDigitsStr::from_str("1")?;
324 /// assert_eq!(not_precise.milliseconds_bytes_fixed_len(), None);
325 ///
326 /// let precise = SecfracDigitsStr::from_str("012")?;
327 /// assert_eq!(precise.milliseconds_bytes_fixed_len(), Some(b"012"));
328 ///
329 /// let more_precise = SecfracDigitsStr::from_str("012345678901")?;
330 /// assert_eq!(more_precise.milliseconds_bytes_fixed_len(), Some(b"012"));
331 /// # Ok::<_, datetime_string::Error>(())
332 /// ```
333 #[inline]
334 #[must_use]
335 pub fn milliseconds_bytes_fixed_len(&self) -> Option<&[u8; 3]> {
336 self.0.get(MILLI_RANGE).map(|s| {
337 debug_assert_eq!(s.len(), 3);
338 debug_assert_safe_version_ok!(<&[u8; 3]>::try_from(s));
339 let ptr = s.as_ptr() as *const [u8; 3];
340 unsafe {
341 // This is safe because the string consists of only ASCII digits.
342 &*ptr
343 }
344 })
345 }
346
347 /// Retruns a microseconds value in integer.
348 ///
349 /// # Examples
350 ///
351 /// ```
352 /// # use datetime_string::common::SecfracDigitsStr;
353 /// let not_precise = SecfracDigitsStr::from_str("1")?;
354 /// assert_eq!(not_precise.microseconds(), 100_000);
355 ///
356 /// let precise = SecfracDigitsStr::from_str("012345")?;
357 /// assert_eq!(precise.microseconds(), 012_345);
358 ///
359 /// let more_precise = SecfracDigitsStr::from_str("123456999")?;
360 /// assert_eq!(more_precise.microseconds(), 123_456);
361 /// # Ok::<_, datetime_string::Error>(())
362 /// ```
363 #[inline]
364 #[must_use]
365 pub fn microseconds(&self) -> u32 {
366 let bytes = &self.0;
367 let len = bytes.len();
368 let len6 = cmp::min(6, len);
369
370 let mut buf: [u8; 8] = [b'0'; 8];
371 // Note that the first two digits should be `0`.
372 buf[2..(2 + len6)].copy_from_slice(&bytes[..len6]);
373 parse_digits8(buf)
374 }
375
376 /// Returns a microseconds precision substring if there are enough digits.
377 ///
378 /// # Examples
379 ///
380 /// ```
381 /// # use datetime_string::common::SecfracDigitsStr;
382 /// let not_precise = SecfracDigitsStr::from_str("1234")?;
383 /// assert_eq!(not_precise.microseconds_digits(), None);
384 ///
385 /// let precise = SecfracDigitsStr::from_str("012345")?;
386 /// assert_eq!(precise.microseconds_digits().unwrap(), "012345");
387 ///
388 /// let more_precise = SecfracDigitsStr::from_str("012345678901")?;
389 /// assert_eq!(more_precise.microseconds_digits().unwrap(), "012345");
390 /// # Ok::<_, datetime_string::Error>(())
391 /// ```
392 #[inline]
393 #[must_use]
394 pub fn microseconds_digits(&self) -> Option<&SecfracDigitsStr> {
395 self.0.get(MICRO_RANGE).map(|s| unsafe {
396 debug_assert_safe_version_ok!(Self::from_bytes(s));
397 // This is safe because `self.0` consists of only ASCII digits,
398 // and so is the substring.
399 SecfracDigitsStr::from_bytes_maybe_unchecked(s)
400 })
401 }
402
403 /// Returns a microseconds precision substring if there are enough digits.
404 ///
405 /// # Examples
406 ///
407 /// ```
408 /// # use datetime_string::common::SecfracDigitsStr;
409 /// let mut buf = "012345678901".to_owned();
410 /// let digits = SecfracDigitsStr::from_mut_str(&mut buf)?;
411 /// assert_eq!(digits.as_str(), "012345678901");
412 ///
413 /// digits.microseconds_digits_mut().unwrap().fill_with_zero();
414 /// assert_eq!(digits.as_str(), "000000678901");
415 /// # Ok::<_, datetime_string::Error>(())
416 /// ```
417 #[inline]
418 #[must_use]
419 pub fn microseconds_digits_mut(&mut self) -> Option<&mut SecfracDigitsStr> {
420 self.0.get_mut(MICRO_RANGE).map(|s| {
421 unsafe {
422 // This is safe because `self.0` consists of only ASCII digits,
423 // and so is the substring.
424 debug_assert_ok!(Self::from_bytes(s));
425 SecfracDigitsStr::from_bytes_maybe_unchecked_mut(s)
426 }
427 })
428 }
429
430 /// Returns a microseconds digits as a fixed bytes slice, if there are enough digits.
431 ///
432 /// # Examples
433 ///
434 /// ```
435 /// # use datetime_string::common::SecfracDigitsStr;
436 /// let not_precise = SecfracDigitsStr::from_str("1234")?;
437 /// assert_eq!(not_precise.microseconds_bytes_fixed_len(), None);
438 ///
439 /// let precise = SecfracDigitsStr::from_str("012345")?;
440 /// assert_eq!(precise.microseconds_bytes_fixed_len(), Some(b"012345"));
441 ///
442 /// let more_precise = SecfracDigitsStr::from_str("012345678901")?;
443 /// assert_eq!(more_precise.microseconds_bytes_fixed_len(), Some(b"012345"));
444 /// # Ok::<_, datetime_string::Error>(())
445 /// ```
446 #[inline]
447 #[must_use]
448 pub fn microseconds_bytes_fixed_len(&self) -> Option<&[u8; 6]> {
449 self.0.get(MICRO_RANGE).map(|s| {
450 debug_assert_eq!(s.len(), 6);
451 debug_assert_safe_version_ok!(<&[u8; 6]>::try_from(s));
452 let ptr = s.as_ptr() as *const [u8; 6];
453 unsafe {
454 // This is safe because the string consists of only ASCII digits.
455 &*ptr
456 }
457 })
458 }
459
460 /// Retruns a nanoseconds value in integer.
461 ///
462 /// # Examples
463 ///
464 /// ```
465 /// # use datetime_string::common::SecfracDigitsStr;
466 /// let not_precise = SecfracDigitsStr::from_str("1")?;
467 /// assert_eq!(not_precise.nanoseconds(), 100_000_000);
468 ///
469 /// let precise = SecfracDigitsStr::from_str("012345678")?;
470 /// assert_eq!(precise.nanoseconds(), 012_345_678);
471 ///
472 /// let more_precise = SecfracDigitsStr::from_str("876543210999")?;
473 /// assert_eq!(more_precise.nanoseconds(), 876_543_210);
474 /// # Ok::<_, datetime_string::Error>(())
475 /// ```
476 #[inline]
477 #[must_use]
478 pub fn nanoseconds(&self) -> u32 {
479 let bytes = &self.0;
480 let len = bytes.len();
481 let len8 = cmp::min(8, len);
482
483 let mut buf: [u8; 8] = [b'0'; 8];
484 buf[..len8].copy_from_slice(&bytes[..len8]);
485 let upper8 = parse_digits8(buf) * 10;
486 if len > 8 {
487 upper8 + (bytes[8] - b'0') as u32
488 } else {
489 upper8
490 }
491 }
492
493 /// Returns a nanoseconds precision substring if there are enough digits.
494 ///
495 /// # Examples
496 ///
497 /// ```
498 /// # use datetime_string::common::SecfracDigitsStr;
499 /// let not_precise = SecfracDigitsStr::from_str("1234")?;
500 /// assert_eq!(not_precise.nanoseconds_digits(), None);
501 ///
502 /// let precise = SecfracDigitsStr::from_str("012345678")?;
503 /// assert_eq!(precise.nanoseconds_digits().unwrap(), "012345678");
504 ///
505 /// let more_precise = SecfracDigitsStr::from_str("012345678901")?;
506 /// assert_eq!(more_precise.nanoseconds_digits().unwrap(), "012345678");
507 /// # Ok::<_, datetime_string::Error>(())
508 /// ```
509 #[inline]
510 #[must_use]
511 pub fn nanoseconds_digits(&self) -> Option<&SecfracDigitsStr> {
512 self.0.get(NANO_RANGE).map(|s| unsafe {
513 debug_assert_safe_version_ok!(Self::from_bytes(s));
514 // This is safe because `self.0` consists of only ASCII digits,
515 // and so is the substring.
516 SecfracDigitsStr::from_bytes_maybe_unchecked(s)
517 })
518 }
519
520 /// Returns a nanoseconds precision substring if there are enough digits.
521 ///
522 /// # Examples
523 ///
524 /// ```
525 /// # use datetime_string::common::SecfracDigitsStr;
526 /// let mut buf = "012345678901".to_owned();
527 /// let digits = SecfracDigitsStr::from_mut_str(&mut buf)?;
528 /// assert_eq!(digits.as_str(), "012345678901");
529 ///
530 /// digits.nanoseconds_digits_mut().unwrap().fill_with_zero();
531 /// assert_eq!(digits.as_str(), "000000000901");
532 /// # Ok::<_, datetime_string::Error>(())
533 /// ```
534 #[inline]
535 #[must_use]
536 pub fn nanoseconds_digits_mut(&mut self) -> Option<&mut SecfracDigitsStr> {
537 self.0.get_mut(NANO_RANGE).map(|s| {
538 unsafe {
539 // This is safe because `self.0` consists of only ASCII digits,
540 // and so is the substring.
541 debug_assert_ok!(Self::from_bytes(s));
542 SecfracDigitsStr::from_bytes_maybe_unchecked_mut(s)
543 }
544 })
545 }
546
547 /// Returns a nanoseconds digits as a fixed bytes slice, if there are enough digits.
548 ///
549 /// # Examples
550 ///
551 /// ```
552 /// # use datetime_string::common::SecfracDigitsStr;
553 /// let not_precise = SecfracDigitsStr::from_str("1234")?;
554 /// assert_eq!(not_precise.nanoseconds_bytes_fixed_len(), None);
555 ///
556 /// let precise = SecfracDigitsStr::from_str("012345678")?;
557 /// assert_eq!(precise.nanoseconds_bytes_fixed_len(), Some(b"012345678"));
558 ///
559 /// let more_precise = SecfracDigitsStr::from_str("012345678901")?;
560 /// assert_eq!(more_precise.nanoseconds_bytes_fixed_len(), Some(b"012345678"));
561 /// # Ok::<_, datetime_string::Error>(())
562 /// ```
563 #[inline]
564 #[must_use]
565 pub fn nanoseconds_bytes_fixed_len(&self) -> Option<&[u8; 9]> {
566 self.0.get(NANO_RANGE).map(|s| {
567 debug_assert_eq!(s.len(), 9);
568 debug_assert_safe_version_ok!(<&[u8; 9]>::try_from(s));
569 let ptr = s.as_ptr() as *const [u8; 9];
570 unsafe {
571 // This is safe because the string consists of only ASCII digits.
572 &*ptr
573 }
574 })
575 }
576
577 /// Fills the secfrac part with zero.
578 ///
579 /// # Examples
580 ///
581 /// ```
582 /// # use datetime_string::common::SecfracDigitsStr;
583 /// let mut buf = "1234".to_owned();
584 /// let secfrac = SecfracDigitsStr::from_mut_str(&mut buf)?;
585 /// assert_eq!(secfrac.as_str(), "1234");
586 ///
587 /// secfrac.fill_with_zero();
588 /// assert_eq!(secfrac.as_str(), "0000");
589 ///
590 /// assert_eq!(buf, "0000");
591 /// # Ok::<_, datetime_string::Error>(())
592 /// ```
593 #[inline]
594 pub fn fill_with_zero(&mut self) {
595 // Use `slice::fill()` once rust-lang/rust#70758 is stabilized.
596 // See <https://github.com/rust-lang/rust/issues/70758>.
597 self.0.iter_mut().for_each(|digit| *digit = b'0');
598 debug_assert!(
599 validate_bytes(&self.0).is_ok(),
600 "The secfrac digits string must be valid after the modification"
601 );
602 }
603
604 /// Fills the secfrac part with zero.
605 ///
606 /// # Examples
607 ///
608 /// ```
609 /// # use datetime_string::common::SecfracDigitsStr;
610 /// let mut buf = "1234".to_owned();
611 /// let secfrac = SecfracDigitsStr::from_mut_str(&mut buf)?;
612 /// assert_eq!(secfrac.as_str(), "1234");
613 ///
614 /// secfrac.fill_with_nine();
615 /// assert_eq!(secfrac.as_str(), "9999");
616 ///
617 /// assert_eq!(buf, "9999");
618 /// # Ok::<_, datetime_string::Error>(())
619 /// ```
620 #[inline]
621 pub fn fill_with_nine(&mut self) {
622 // Use `slice::fill()` once rust-lang/rust#70758 is stabilized.
623 // See <https://github.com/rust-lang/rust/issues/70758>.
624 self.0.iter_mut().for_each(|digit| *digit = b'9');
625 debug_assert!(
626 validate_bytes(&self.0).is_ok(),
627 "The secfrac digits string must be valid after the modification"
628 );
629 }
630}
631
632impl AsRef<[u8]> for SecfracDigitsStr {
633 #[inline]
634 fn as_ref(&self) -> &[u8] {
635 &self.0
636 }
637}
638
639impl AsRef<str> for SecfracDigitsStr {
640 #[inline]
641 fn as_ref(&self) -> &str {
642 self.as_str()
643 }
644}
645
646impl AsRef<SecfracDigitsStr> for SecfracDigitsStr {
647 #[inline]
648 fn as_ref(&self) -> &SecfracDigitsStr {
649 self
650 }
651}
652
653impl AsMut<SecfracDigitsStr> for SecfracDigitsStr {
654 #[inline]
655 fn as_mut(&mut self) -> &mut SecfracDigitsStr {
656 self
657 }
658}
659
660impl<'a> From<&'a SecfracDigitsStr> for &'a str {
661 #[inline]
662 fn from(v: &'a SecfracDigitsStr) -> Self {
663 v.as_str()
664 }
665}
666
667impl<'a> TryFrom<&'a [u8]> for &'a SecfracDigitsStr {
668 type Error = Error;
669
670 #[inline]
671 fn try_from(v: &'a [u8]) -> Result<Self, Self::Error> {
672 validate_bytes(v)?;
673 Ok(unsafe {
674 // This is safe because the string is already validated.
675 SecfracDigitsStr::from_bytes_maybe_unchecked(v)
676 })
677 }
678}
679
680impl<'a> TryFrom<&'a mut [u8]> for &'a mut SecfracDigitsStr {
681 type Error = Error;
682
683 #[inline]
684 fn try_from(v: &'a mut [u8]) -> Result<Self, Self::Error> {
685 validate_bytes(v)?;
686 Ok(unsafe {
687 // This is safe because the string is already validated.
688 SecfracDigitsStr::from_bytes_maybe_unchecked_mut(v)
689 })
690 }
691}
692
693impl<'a> TryFrom<&'a str> for &'a SecfracDigitsStr {
694 type Error = Error;
695
696 #[inline]
697 fn try_from(v: &'a str) -> Result<Self, Self::Error> {
698 Self::try_from(v.as_bytes())
699 }
700}
701
702impl<'a> TryFrom<&'a mut str> for &'a mut SecfracDigitsStr {
703 type Error = Error;
704
705 #[inline]
706 fn try_from(v: &'a mut str) -> Result<Self, Self::Error> {
707 validate_bytes(v.as_bytes())?;
708 Ok(unsafe {
709 // This is safe because the string is already validated and
710 // `SecfracDigitsStr` ensures that the underlying bytes are ASCII
711 // string after modification.
712 SecfracDigitsStr::from_str_maybe_unchecked_mut(v)
713 })
714 }
715}
716
717impl fmt::Display for SecfracDigitsStr {
718 #[inline]
719 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
720 self.as_str().fmt(f)
721 }
722}
723
724impl ops::Deref for SecfracDigitsStr {
725 type Target = str;
726
727 #[inline]
728 fn deref(&self) -> &Self::Target {
729 self.as_str()
730 }
731}
732
733impl_cmp_symmetric!(str, SecfracDigitsStr, &SecfracDigitsStr);
734impl_cmp_symmetric!([u8], SecfracDigitsStr, [u8]);
735impl_cmp_symmetric!([u8], SecfracDigitsStr, &[u8]);
736impl_cmp_symmetric!([u8], &SecfracDigitsStr, [u8]);
737impl_cmp_symmetric!(str, SecfracDigitsStr, str);
738impl_cmp_symmetric!(str, SecfracDigitsStr, &str);
739impl_cmp_symmetric!(str, &SecfracDigitsStr, str);
740
741#[cfg(feature = "serde")]
742#[cfg_attr(docsrs, doc(cfg(feature = "serde")))]
743impl serde::Serialize for SecfracDigitsStr {
744 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
745 where
746 S: serde::Serializer,
747 {
748 serializer.serialize_str(self.as_str())
749 }
750}
751
752/// Items for serde support.
753#[cfg(feature = "serde")]
754mod serde_ {
755 use super::*;
756
757 use serde::de::{Deserialize, Deserializer, Visitor};
758
759 /// Visitor for `&SecfracDigitsStr`.
760 struct StrVisitor;
761
762 impl<'de> Visitor<'de> for StrVisitor {
763 type Value = &'de SecfracDigitsStr;
764
765 #[inline]
766 fn expecting(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
767 f.write_str("digits of fractions of a second")
768 }
769
770 #[inline]
771 fn visit_borrowed_bytes<E>(self, v: &'de [u8]) -> Result<Self::Value, E>
772 where
773 E: serde::de::Error,
774 {
775 Self::Value::try_from(v).map_err(E::custom)
776 }
777
778 #[inline]
779 fn visit_borrowed_str<E>(self, v: &'de str) -> Result<Self::Value, E>
780 where
781 E: serde::de::Error,
782 {
783 Self::Value::try_from(v).map_err(E::custom)
784 }
785 }
786
787 impl<'de> Deserialize<'de> for &'de SecfracDigitsStr {
788 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
789 where
790 D: Deserializer<'de>,
791 {
792 deserializer.deserialize_any(StrVisitor)
793 }
794 }
795}
796
797#[cfg(test)]
798mod tests {
799 #[cfg(feature = "serde")]
800 use super::*;
801
802 use super::validate_bytes as s_validate;
803
804 #[cfg(feature = "serde")]
805 use serde_test::{assert_de_tokens, assert_tokens, Token};
806
807 #[test]
808 fn validate_bytes() {
809 assert!(s_validate(b"0").is_ok());
810 assert!(s_validate(b"9").is_ok());
811 assert!(s_validate(b"1234").is_ok());
812 assert!(s_validate(b"001200").is_ok());
813 assert!(s_validate(b"0000000").is_ok());
814 assert!(s_validate(b"9999999").is_ok());
815 assert!(s_validate(b"00000000000000000000000000000000").is_ok());
816 assert!(s_validate(b"99999999999999999999999999999999").is_ok());
817
818 assert!(s_validate(b"").is_err());
819 assert!(s_validate(b".0").is_err());
820 assert!(s_validate(b"+0").is_err());
821 assert!(s_validate(b"-0").is_err());
822 }
823
824 #[cfg(feature = "serde")]
825 #[test]
826 fn ser_de_str() {
827 let raw: &'static str = "1234";
828 assert_tokens(
829 &SecfracDigitsStr::from_str(raw).unwrap(),
830 &[Token::BorrowedStr(raw)],
831 );
832 }
833
834 #[cfg(feature = "serde")]
835 #[test]
836 fn de_bytes_slice() {
837 let raw: &'static [u8; 4] = b"1234";
838 assert_de_tokens(
839 &SecfracDigitsStr::from_bytes(raw).unwrap(),
840 &[Token::BorrowedBytes(raw)],
841 );
842 }
843}