Skip to main content

deser_core/
std_only_impls.rs

1//! `Serialize` and `Deserialize` for leaf types that are only in `std`.
2//!
3//! The ones that are in `core` and `alloc` are in `std_impls`.
4use std::ffi::{OsStr, OsString};
5use std::path::{Path, PathBuf};
6use std::sync::{Mutex, OnceLock, RwLock};
7
8use alloc::borrow::Cow;
9use alloc::boxed::Box;
10use alloc::string::String;
11
12use crate::adapters::Same;
13use crate::de::impls::{Via, deserialize_via, via_handle};
14use crate::de::{Deserialize, SinkHandle, Slot, default_atom};
15use crate::error::{Error, ErrorKind};
16use crate::event::Atom;
17use crate::ser::{Describe, Emit, Serialize};
18use crate::{State, Text};
19
20// OnceLock
21
22/// Serializes like an `Option`: as the value if it's set, as null if not.
23impl<T: Serialize + Send> Serialize for OnceLock<T> {
24    fn serialize<'a>(this: &'a Self, state: &mut State) -> Result<Emit<'a>, Error> {
25        match this.get() {
26            Some(value) => T::serialize(value, state),
27            None => Ok(Emit::Atom(Atom::Null)),
28        }
29    }
30
31    fn finish(this: &Self, state: &mut State) -> Result<(), Error> {
32        match this.get() {
33            Some(value) => T::finish(value, state),
34            None => Ok(()),
35        }
36    }
37
38    fn is_optional(value: &Self) -> bool {
39        value.get().is_none()
40    }
41
42    fn container_shape(this: &Self) -> crate::ContainerShape {
43        match this.get() {
44            Some(value) => T::container_shape(value),
45            None => crate::ContainerShape::new(),
46        }
47    }
48
49    fn describe(this: &Self, d: &mut dyn Describe) {
50        match this.get() {
51            Some(value) => {
52                d.some();
53                T::describe(value, d);
54            }
55            None => d.none(),
56        }
57    }
58}
59
60impl<T: Send> Via<Option<T>> for OnceLock<T> {
61    #[inline]
62    fn convert(value: Option<T>) -> Result<Self, Error> {
63        Ok(match value {
64            Some(value) => OnceLock::from(value),
65            None => OnceLock::new(),
66        })
67    }
68}
69
70/// Deserializes like an `Option`: null and missing values are not set.
71impl<'de, T: Deserialize<'de>> Deserialize<'de> for OnceLock<T> {
72    fn deserialize_into<'out>(
73        out: &'out mut Option<Self>,
74        state: &mut State,
75    ) -> SinkHandle<'out, 'de> {
76        via_handle::<Option<T>, Self, Same>(out, state)
77    }
78
79    fn expecting() -> Cow<'static, str> {
80        T::expecting()
81    }
82
83    fn initial_value() -> Option<Self> {
84        Some(OnceLock::new())
85    }
86}
87
88// Paths
89
90/// Serializes as a string.  Paths which are not valid UTF-8 fail to
91/// serialize.
92impl Serialize for Path {
93    begin_without_finish!();
94
95    fn serialize<'a>(this: &'a Self, _state: &mut State) -> Result<Emit<'a>, Error> {
96        match this.to_str() {
97            Some(value) => Ok(Emit::Atom(Atom::Str(Text::borrowed(value)))),
98            None => Err(Error::new(
99                ErrorKind::InvalidValue,
100                "path contains invalid UTF-8 characters",
101            )),
102        }
103    }
104}
105
106impl Serialize for PathBuf {
107    begin_without_finish!();
108
109    fn serialize<'a>(value: &'a Self, state: &mut State) -> Result<Emit<'a>, Error> {
110        Path::serialize(value.as_path(), state)
111    }
112}
113
114impl<'de> Deserialize<'de> for PathBuf {
115    fn deserialize_atom(slot: &mut Slot<Self>, atom: Atom, state: &mut State) -> Result<(), Error> {
116        match atom {
117            Atom::Str(value) => {
118                slot.set(PathBuf::from(value.into_owned()));
119                Ok(())
120            }
121            other => default_atom(slot, other, state),
122        }
123    }
124
125    fn expecting() -> Cow<'static, str> {
126        Cow::Borrowed("path")
127    }
128
129    slot_atom_into!();
130}
131
132impl Via<PathBuf> for Box<Path> {
133    #[inline]
134    fn convert(value: PathBuf) -> Result<Self, Error> {
135        Ok(value.into_boxed_path())
136    }
137}
138
139deserialize_via! {
140    [] Box<Path> => PathBuf;
141}
142
143// OS strings
144
145/// Serializes as a string like [`Path`].  OS strings which are not valid
146/// UTF-8 fail to serialize.
147impl Serialize for OsStr {
148    begin_without_finish!();
149
150    fn serialize<'a>(this: &'a Self, _state: &mut State) -> Result<Emit<'a>, Error> {
151        match this.to_str() {
152            Some(value) => Ok(Emit::Atom(Atom::Str(Text::borrowed(value)))),
153            None => Err(Error::new(
154                ErrorKind::InvalidValue,
155                "OS string contains invalid UTF-8 characters",
156            )),
157        }
158    }
159}
160
161impl Serialize for OsString {
162    begin_without_finish!();
163
164    fn serialize<'a>(value: &'a Self, state: &mut State) -> Result<Emit<'a>, Error> {
165        OsStr::serialize(value.as_os_str(), state)
166    }
167}
168
169impl Via<String> for OsString {
170    #[inline]
171    fn convert(value: String) -> Result<Self, Error> {
172        Ok(OsString::from(value))
173    }
174}
175
176impl Via<OsString> for Box<OsStr> {
177    #[inline]
178    fn convert(value: OsString) -> Result<Self, Error> {
179        Ok(value.into_boxed_os_str())
180    }
181}
182
183deserialize_via! {
184    [] OsString => String;
185    [] Box<OsStr> => OsString;
186}
187
188// Locks
189
190// `Mutex` and `RwLock` are only deserialized: serializing would have to hold
191// the lock guard until the value is serialized, but serializations can move
192// between threads which guards must not.
193
194impl<T: Send> Via<T> for Mutex<T> {
195    #[inline]
196    fn convert(value: T) -> Result<Self, Error> {
197        Ok(Mutex::new(value))
198    }
199}
200
201impl<T: Send> Via<T> for RwLock<T> {
202    #[inline]
203    fn convert(value: T) -> Result<Self, Error> {
204        Ok(RwLock::new(value))
205    }
206}
207
208deserialize_via! {
209    [T: Deserialize<'de>] Mutex<T> => T;
210    [T: Deserialize<'de>] RwLock<T> => T;
211}