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}