datetime_string/rfc3339/partial_time/
owned.rs1#![cfg(feature = "alloc")]
5
6use core::{convert::TryFrom, fmt, ops, str};
7
8use alloc::{string::String, vec::Vec};
9
10use crate::{ConversionError, Error};
11
12use super::{validate_bytes, PartialTimeStr};
13
14#[cfg_attr(docsrs, doc(cfg(feature = "alloc")))]
42#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
43#[repr(transparent)]
44#[allow(clippy::derive_hash_xor_eq)]
51#[allow(unknown_lints, clippy::derive_ord_xor_partial_ord)]
52pub struct PartialTimeString(Vec<u8>);
53
54impl PartialTimeString {
55 #[inline]
63 #[must_use]
64 unsafe fn from_bytes_maybe_unchecked(s: Vec<u8>) -> Self {
65 debug_assert_ok!(validate_bytes(&s));
66 Self(s)
67 }
68
69 #[inline]
85 #[must_use]
86 pub fn as_deref(&self) -> &PartialTimeStr {
87 unsafe {
88 debug_assert_safe_version_ok!(PartialTimeStr::from_bytes(&self.0));
90 PartialTimeStr::from_bytes_maybe_unchecked(&self.0)
91 }
92 }
93
94 #[inline]
110 #[must_use]
111 pub fn as_deref_mut(&mut self) -> &mut PartialTimeStr {
112 unsafe {
113 debug_assert_ok!(PartialTimeStr::from_bytes(&self.0));
115 PartialTimeStr::from_bytes_maybe_unchecked_mut(&mut self.0)
116 }
117 }
118}
119
120impl core::borrow::Borrow<PartialTimeStr> for PartialTimeString {
121 #[inline]
122 fn borrow(&self) -> &PartialTimeStr {
123 self.as_deref()
124 }
125}
126
127impl core::borrow::BorrowMut<PartialTimeStr> for PartialTimeString {
128 #[inline]
129 fn borrow_mut(&mut self) -> &mut PartialTimeStr {
130 self.as_deref_mut()
131 }
132}
133
134impl alloc::borrow::ToOwned for PartialTimeStr {
135 type Owned = PartialTimeString;
136
137 #[inline]
138 fn to_owned(&self) -> Self::Owned {
139 self.into()
140 }
141}
142
143impl AsRef<[u8]> for PartialTimeString {
144 #[inline]
145 fn as_ref(&self) -> &[u8] {
146 self.as_bytes()
147 }
148}
149
150impl AsRef<str> for PartialTimeString {
151 #[inline]
152 fn as_ref(&self) -> &str {
153 self.as_str()
154 }
155}
156
157impl AsRef<PartialTimeStr> for PartialTimeString {
158 #[inline]
159 fn as_ref(&self) -> &PartialTimeStr {
160 self
161 }
162}
163
164impl AsMut<PartialTimeStr> for PartialTimeString {
165 #[inline]
166 fn as_mut(&mut self) -> &mut PartialTimeStr {
167 self
168 }
169}
170
171impl From<PartialTimeString> for Vec<u8> {
172 #[inline]
173 fn from(v: PartialTimeString) -> Vec<u8> {
174 v.0
175 }
176}
177
178impl From<PartialTimeString> for String {
179 #[inline]
180 fn from(v: PartialTimeString) -> String {
181 unsafe {
182 debug_assert_ok!(str::from_utf8(&v.0));
184 String::from_utf8_unchecked(v.0)
185 }
186 }
187}
188
189impl From<&PartialTimeStr> for PartialTimeString {
190 fn from(v: &PartialTimeStr) -> Self {
191 unsafe {
192 debug_assert_ok!(validate_bytes(&v.0));
194 Self::from_bytes_maybe_unchecked(v.0.into())
195 }
196 }
197}
198
199impl TryFrom<&[u8]> for PartialTimeString {
200 type Error = Error;
201
202 #[inline]
203 fn try_from(v: &[u8]) -> Result<Self, Self::Error> {
204 PartialTimeStr::from_bytes(v).map(Into::into)
205 }
206}
207
208impl TryFrom<&str> for PartialTimeString {
209 type Error = Error;
210
211 #[inline]
212 fn try_from(v: &str) -> Result<Self, Self::Error> {
213 PartialTimeStr::from_str(v).map(Into::into)
214 }
215}
216
217impl TryFrom<Vec<u8>> for PartialTimeString {
218 type Error = ConversionError<Vec<u8>>;
219
220 #[inline]
221 fn try_from(v: Vec<u8>) -> Result<Self, Self::Error> {
222 match validate_bytes(&v) {
223 Ok(_) => Ok(unsafe {
224 Self::from_bytes_maybe_unchecked(v)
226 }),
227 Err(e) => Err(ConversionError::new(v, e)),
228 }
229 }
230}
231
232impl TryFrom<String> for PartialTimeString {
233 type Error = ConversionError<String>;
234
235 #[inline]
236 fn try_from(v: String) -> Result<Self, Self::Error> {
237 match validate_bytes(v.as_bytes()) {
238 Ok(_) => Ok(unsafe {
239 Self::from_bytes_maybe_unchecked(v.into_bytes())
241 }),
242 Err(e) => Err(ConversionError::new(v, e)),
243 }
244 }
245}
246
247impl fmt::Display for PartialTimeString {
248 #[inline]
249 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
250 self.as_deref().fmt(f)
251 }
252}
253
254impl ops::Deref for PartialTimeString {
255 type Target = PartialTimeStr;
256
257 #[inline]
258 fn deref(&self) -> &Self::Target {
259 self.as_deref()
260 }
261}
262
263impl ops::DerefMut for PartialTimeString {
264 #[inline]
265 fn deref_mut(&mut self) -> &mut Self::Target {
266 self.as_deref_mut()
267 }
268}
269
270impl str::FromStr for PartialTimeString {
271 type Err = Error;
272
273 #[inline]
274 fn from_str(s: &str) -> Result<Self, Self::Err> {
275 Self::try_from(s)
276 }
277}
278
279impl_cmp_symmetric!(PartialTimeStr, PartialTimeString, &PartialTimeString);
280impl_cmp_symmetric!(PartialTimeStr, PartialTimeString, PartialTimeStr);
281impl_cmp_symmetric!(PartialTimeStr, PartialTimeString, &PartialTimeStr);
282impl_cmp_symmetric!(str, PartialTimeString, str);
283impl_cmp_symmetric!(str, PartialTimeString, &str);
284impl_cmp_symmetric!(str, &PartialTimeString, str);
285impl_cmp_symmetric!([u8], PartialTimeString, [u8]);
286impl_cmp_symmetric!([u8], PartialTimeString, &[u8]);
287impl_cmp_symmetric!([u8], &PartialTimeString, [u8]);
288
289#[cfg(feature = "serde")]
290#[cfg_attr(docsrs, doc(cfg(feature = "serde")))]
291impl serde::Serialize for PartialTimeString {
292 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
293 where
294 S: serde::Serializer,
295 {
296 serializer.serialize_str(self.as_str())
297 }
298}
299
300#[cfg(feature = "serde")]
302mod serde_ {
303 use super::*;
304
305 use serde::de::{Deserialize, Deserializer, Visitor};
306
307 struct StringVisitor;
309
310 impl<'de> Visitor<'de> for StringVisitor {
311 type Value = PartialTimeString;
312
313 #[inline]
314 fn expecting(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
315 f.write_str("RFC 3339 partial-time string")
316 }
317
318 #[inline]
319 fn visit_bytes<E>(self, v: &[u8]) -> Result<Self::Value, E>
320 where
321 E: serde::de::Error,
322 {
323 Self::Value::try_from(v).map_err(E::custom)
324 }
325
326 #[inline]
327 fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
328 where
329 E: serde::de::Error,
330 {
331 Self::Value::try_from(v).map_err(E::custom)
332 }
333 }
334
335 impl<'de> Deserialize<'de> for PartialTimeString {
336 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
337 where
338 D: Deserializer<'de>,
339 {
340 deserializer.deserialize_any(StringVisitor)
341 }
342 }
343}
344
345#[cfg(feature = "serde")]
346#[cfg(test)]
347mod tests {
348 use super::*;
349
350 use serde_test::{assert_de_tokens, assert_tokens, Token};
351
352 #[test]
353 fn ser_de_string() {
354 let raw: &'static str = "12:34:56.7890";
355 assert_tokens(
356 &PartialTimeString::try_from(raw).unwrap(),
357 &[Token::Str(raw)],
358 );
359 }
360
361 #[test]
362 fn de_bytes() {
363 let raw: &'static [u8; 13] = b"12:34:56.7890";
364 assert_de_tokens(
365 &PartialTimeString::try_from(&raw[..]).unwrap(),
366 &[Token::Bytes(raw)],
367 );
368 }
369}