datetime_string/common/secfrac_digits/
owned.rs

1//! Digits of fractions of a second.
2#![cfg(feature = "alloc")]
3
4use core::{convert::TryFrom, fmt, ops, str};
5
6use alloc::{string::String, vec::Vec};
7
8use crate::{ConversionError, Error};
9
10use super::{validate_bytes, SecfracDigitsStr};
11
12/// String slice for digits of fractions of a second.
13///
14/// Available when `alloc` feature is enabled.
15///
16/// Note that values of this type cannot be not empty string.
17///
18/// To create a value of this type, use [`str::parse`] method or
19/// [`std::convert::TryFrom`] trait, or convert from `&SecfracDigitsStr`.
20///
21/// # Examples
22///
23/// ```
24/// # use datetime_string::common::SecfracDigitsString;
25/// use datetime_string::common::SecfracDigitsStr;
26/// use std::convert::TryFrom;
27///
28/// let try_from = SecfracDigitsString::try_from("1234")?;
29///
30/// let parse = "1234".parse::<SecfracDigitsString>()?;
31/// let parse2: SecfracDigitsString = "1234".parse()?;
32///
33/// let to_owned = SecfracDigitsStr::from_str("1234")?.to_owned();
34/// let into: SecfracDigitsString = SecfracDigitsStr::from_str("1234")?.into();
35/// # Ok::<_, datetime_string::Error>(())
36/// ```
37///
38/// [`time-secfrac`]: https://tools.ietf.org/html/rfc3339#section-5.6
39#[cfg_attr(docsrs, doc(cfg(feature = "serde")))]
40#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
41#[repr(transparent)]
42// Note that `derive(Serialize)` cannot used here, because it encodes this as
43// `[u8; 8]` rather than as a string.
44//
45// Comparisons implemented for the type are consistent (at least it is intended to be so).
46// See <https://github.com/rust-lang/rust-clippy/issues/2025>.
47// Note that `clippy::derive_ord_xor_partial_ord` would be introduced since Rust 1.47.0.
48#[allow(clippy::derive_hash_xor_eq)]
49#[allow(unknown_lints, clippy::derive_ord_xor_partial_ord)]
50pub struct SecfracDigitsString(Vec<u8>);
51
52impl SecfracDigitsString {
53    /// Creates a `SecfracDigitsString` from the given bytes.
54    ///
55    /// This performs assertion in debug build, but not in release build.
56    ///
57    /// # Safety
58    ///
59    /// `validate_bytes(&s)` should return `Ok(())`.
60    #[inline]
61    #[must_use]
62    unsafe fn from_bytes_maybe_unchecked(s: Vec<u8>) -> Self {
63        debug_assert_ok!(validate_bytes(&s));
64        Self(s)
65    }
66
67    /// Returns a `&SecfracDigitsStr` for the string.
68    ///
69    /// # Examples
70    ///
71    /// ```
72    /// # use datetime_string::common::SecfracDigitsString;
73    /// use datetime_string::common::SecfracDigitsStr;
74    ///
75    /// let secfrac = "1234".parse::<SecfracDigitsString>()?;
76    ///
77    /// // Usually you don't need to call `as_deref()` explicitly, because
78    /// // `Deref<Target = SecfracDigitsStr>` trait is implemented.
79    /// let _: &SecfracDigitsStr = secfrac.as_deref();
80    /// # Ok::<_, datetime_string::Error>(())
81    /// ```
82    #[inline]
83    #[must_use]
84    pub fn as_deref(&self) -> &SecfracDigitsStr {
85        unsafe {
86            // This is safe because `self.0` is already validated.
87            debug_assert_safe_version_ok!(SecfracDigitsStr::from_bytes(&self.0));
88            SecfracDigitsStr::from_bytes_maybe_unchecked(&self.0)
89        }
90    }
91
92    /// Returns a `&mut SecfracDigitsStr` for the string.
93    ///
94    /// # Examples
95    ///
96    /// ```
97    /// # use datetime_string::common::SecfracDigitsString;
98    /// use datetime_string::common::SecfracDigitsStr;
99    ///
100    /// let mut secfrac = "1234".parse::<SecfracDigitsString>()?;
101    ///
102    /// // Usually you don't need to call `as_deref_mut()` explicitly, because
103    /// // `DerefMut` trait is implemented.
104    /// let _: &mut SecfracDigitsStr = secfrac.as_deref_mut();
105    /// # Ok::<_, datetime_string::Error>(())
106    /// ```
107    #[inline]
108    #[must_use]
109    pub fn as_deref_mut(&mut self) -> &mut SecfracDigitsStr {
110        unsafe {
111            // This is safe because `self.0` is already validated.
112            debug_assert_ok!(SecfracDigitsStr::from_bytes(&self.0));
113            SecfracDigitsStr::from_bytes_maybe_unchecked_mut(&mut self.0)
114        }
115    }
116}
117
118impl core::borrow::Borrow<SecfracDigitsStr> for SecfracDigitsString {
119    #[inline]
120    fn borrow(&self) -> &SecfracDigitsStr {
121        self.as_deref()
122    }
123}
124
125impl core::borrow::BorrowMut<SecfracDigitsStr> for SecfracDigitsString {
126    #[inline]
127    fn borrow_mut(&mut self) -> &mut SecfracDigitsStr {
128        self.as_deref_mut()
129    }
130}
131
132impl alloc::borrow::ToOwned for SecfracDigitsStr {
133    type Owned = SecfracDigitsString;
134
135    #[inline]
136    fn to_owned(&self) -> Self::Owned {
137        self.into()
138    }
139}
140
141impl AsRef<[u8]> for SecfracDigitsString {
142    #[inline]
143    fn as_ref(&self) -> &[u8] {
144        &self.0
145    }
146}
147
148impl AsRef<str> for SecfracDigitsString {
149    #[inline]
150    fn as_ref(&self) -> &str {
151        self.as_str()
152    }
153}
154
155impl AsRef<SecfracDigitsStr> for SecfracDigitsString {
156    #[inline]
157    fn as_ref(&self) -> &SecfracDigitsStr {
158        self
159    }
160}
161
162impl AsMut<SecfracDigitsStr> for SecfracDigitsString {
163    #[inline]
164    fn as_mut(&mut self) -> &mut SecfracDigitsStr {
165        self
166    }
167}
168
169impl From<SecfracDigitsString> for Vec<u8> {
170    #[inline]
171    fn from(v: SecfracDigitsString) -> Vec<u8> {
172        v.0
173    }
174}
175
176impl From<SecfracDigitsString> for String {
177    #[inline]
178    fn from(v: SecfracDigitsString) -> String {
179        unsafe {
180            // This is safe because a valid `SecfracDigitsString` is an ASCII string.
181            debug_assert_ok!(str::from_utf8(&v.0));
182            String::from_utf8_unchecked(v.0)
183        }
184    }
185}
186
187impl From<&SecfracDigitsStr> for SecfracDigitsString {
188    fn from(v: &SecfracDigitsStr) -> Self {
189        unsafe {
190            // This is safe because the value is already validated.
191            debug_assert_ok!(validate_bytes(&v.0));
192            Self::from_bytes_maybe_unchecked(v.0.into())
193        }
194    }
195}
196
197impl TryFrom<&[u8]> for SecfracDigitsString {
198    type Error = Error;
199
200    #[inline]
201    fn try_from(v: &[u8]) -> Result<Self, Self::Error> {
202        SecfracDigitsStr::from_bytes(v).map(Into::into)
203    }
204}
205
206impl TryFrom<&str> for SecfracDigitsString {
207    type Error = Error;
208
209    #[inline]
210    fn try_from(v: &str) -> Result<Self, Self::Error> {
211        SecfracDigitsStr::from_str(v).map(Into::into)
212    }
213}
214
215impl TryFrom<Vec<u8>> for SecfracDigitsString {
216    type Error = ConversionError<Vec<u8>>;
217
218    #[inline]
219    fn try_from(v: Vec<u8>) -> Result<Self, Self::Error> {
220        match validate_bytes(&v) {
221            Ok(_) => Ok(unsafe {
222                // This is safe because the value is successfully validated.
223                Self::from_bytes_maybe_unchecked(v)
224            }),
225            Err(e) => Err(ConversionError::new(v, e)),
226        }
227    }
228}
229
230impl TryFrom<String> for SecfracDigitsString {
231    type Error = ConversionError<String>;
232
233    #[inline]
234    fn try_from(v: String) -> Result<Self, Self::Error> {
235        match validate_bytes(v.as_bytes()) {
236            Ok(_) => Ok(unsafe {
237                // This is safe because the value is successfully validated.
238                Self::from_bytes_maybe_unchecked(v.into_bytes())
239            }),
240            Err(e) => Err(ConversionError::new(v, e)),
241        }
242    }
243}
244
245impl fmt::Display for SecfracDigitsString {
246    #[inline]
247    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
248        self.as_deref().fmt(f)
249    }
250}
251
252impl ops::Deref for SecfracDigitsString {
253    type Target = SecfracDigitsStr;
254
255    #[inline]
256    fn deref(&self) -> &Self::Target {
257        self.as_deref()
258    }
259}
260
261impl ops::DerefMut for SecfracDigitsString {
262    #[inline]
263    fn deref_mut(&mut self) -> &mut Self::Target {
264        self.as_deref_mut()
265    }
266}
267
268impl str::FromStr for SecfracDigitsString {
269    type Err = Error;
270
271    #[inline]
272    fn from_str(s: &str) -> Result<Self, Self::Err> {
273        Self::try_from(s)
274    }
275}
276
277impl_cmp_symmetric!(SecfracDigitsStr, SecfracDigitsString, &SecfracDigitsString);
278impl_cmp_symmetric!(SecfracDigitsStr, SecfracDigitsString, SecfracDigitsStr);
279impl_cmp_symmetric!(SecfracDigitsStr, SecfracDigitsString, &SecfracDigitsStr);
280impl_cmp_symmetric!(str, SecfracDigitsString, str);
281impl_cmp_symmetric!(str, SecfracDigitsString, &str);
282impl_cmp_symmetric!(str, &SecfracDigitsString, str);
283impl_cmp_symmetric!([u8], SecfracDigitsString, [u8]);
284impl_cmp_symmetric!([u8], SecfracDigitsString, &[u8]);
285impl_cmp_symmetric!([u8], &SecfracDigitsString, [u8]);
286
287#[cfg(feature = "serde")]
288#[cfg_attr(docsrs, doc(cfg(feature = "serde")))]
289impl serde::Serialize for SecfracDigitsString {
290    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
291    where
292        S: serde::Serializer,
293    {
294        serializer.serialize_str(self.as_str())
295    }
296}
297
298/// Items for serde support.
299#[cfg(feature = "serde")]
300mod serde_ {
301    use super::*;
302
303    use serde::de::{Deserialize, Deserializer, Visitor};
304
305    /// Visitor for `SecfracDigitsString`.
306    struct StringVisitor;
307
308    impl<'de> Visitor<'de> for StringVisitor {
309        type Value = SecfracDigitsString;
310
311        #[inline]
312        fn expecting(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
313            f.write_str("digits of fractions of a second")
314        }
315
316        #[inline]
317        fn visit_bytes<E>(self, v: &[u8]) -> Result<Self::Value, E>
318        where
319            E: serde::de::Error,
320        {
321            Self::Value::try_from(v).map_err(E::custom)
322        }
323
324        #[inline]
325        fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
326        where
327            E: serde::de::Error,
328        {
329            Self::Value::try_from(v).map_err(E::custom)
330        }
331    }
332
333    impl<'de> Deserialize<'de> for SecfracDigitsString {
334        fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
335        where
336            D: Deserializer<'de>,
337        {
338            deserializer.deserialize_any(StringVisitor)
339        }
340    }
341}
342
343#[cfg(feature = "serde")]
344#[cfg(test)]
345mod tests {
346    use super::*;
347
348    use serde_test::{assert_de_tokens, assert_tokens, Token};
349
350    #[test]
351    fn ser_de_string() {
352        let raw: &'static str = "1234";
353        assert_tokens(
354            &SecfracDigitsString::try_from(raw).unwrap(),
355            &[Token::Str(raw)],
356        );
357    }
358
359    #[test]
360    fn de_bytes() {
361        let raw: &'static [u8; 4] = b"1234";
362        assert_de_tokens(
363            &SecfracDigitsString::try_from(&raw[..]).unwrap(),
364            &[Token::Bytes(raw)],
365        );
366    }
367}