1#[cfg(not(feature = "alloc"))]
4compile_error!("feature `alloc` is required");
5
6mod error;
7
8use core::borrow::Borrow as _;
9
10use alloc::{
11 borrow::Cow,
12 string::{String, ToString as _},
13 vec::Vec,
14};
15
16pub use error::YamlSerError;
17use facet_serialize::{Serialize, Serializer};
18use yaml_rust2::{
19 Yaml, YamlEmitter,
20 yaml::{Array, Hash},
21};
22
23pub struct YamlSerializer<'shape> {
25 key_stack: Vec<Cow<'shape, str>>,
27 yaml: Yaml,
29 current: KeyOrValue,
31}
32
33impl<'shape> YamlSerializer<'shape> {
34 pub fn new() -> Self {
36 Self {
37 key_stack: Vec::new(),
38 yaml: Yaml::BadValue,
39 current: KeyOrValue::Value,
40 }
41 }
42
43 pub fn into_raw_document(self) -> Yaml {
45 self.yaml
46 }
47
48 pub fn into_string(self) -> String {
50 let mut output = String::new();
51 let mut emitter = YamlEmitter::new(&mut output);
52 emitter.dump(&self.yaml).unwrap();
53
54 output
55 }
56
57 fn write_value(&mut self, value: Yaml) -> Result<(), YamlSerError> {
59 match self.current {
60 KeyOrValue::Value => {
62 if let Some(array) = self.current_mut().as_mut_vec() {
63 array.push(value);
65 } else if value == Yaml::Null {
66 self.remove_current();
68 } else {
69 self.set_current(value);
71 }
72 }
73 KeyOrValue::Key => {
75 let yaml_type = type_name(&value);
76 let map_key = value
77 .into_string()
78 .ok_or(YamlSerError::InvalidKeyConversion { yaml_type })?;
79 self.push_key(map_key.into(), "map key");
80 }
81 }
82
83 Ok(())
84 }
85
86 fn push_key(&mut self, key: Cow<'shape, str>, type_name: &'static str) {
88 #[cfg(feature = "log")]
89 log::trace!("Push {type_name} {}", self.display_full_key());
90 #[cfg(not(feature = "log"))]
91 let _ = type_name;
92
93 self.current_mut()
95 .as_mut_hash()
96 .unwrap()
97 .insert(Yaml::String(key.clone().into_owned()), Yaml::BadValue);
98
99 self.key_stack.push(key);
101 }
102
103 fn pop_key(&mut self, type_name: &'static str) -> Option<Cow<'shape, str>> {
105 #[cfg(feature = "log")]
106 log::trace!("Pop {type_name} {}", self.display_full_key());
107 #[cfg(not(feature = "log"))]
108 let _ = type_name;
109
110 self.key_stack.pop()
111 }
112
113 fn set_current(&mut self, yaml: Yaml) {
115 #[cfg(feature = "log")]
116 log::trace!("Set {} to {}", self.display_full_key(), type_name(&yaml));
117
118 *self.current_mut() = yaml;
119 }
120
121 fn remove_current(&mut self) {
125 let key = self.key_stack.last().unwrap().to_string();
126
127 let mut item = &mut self.yaml;
129 for key in &self.key_stack[0..self.key_stack.len() - 1] {
130 item = &mut item[key.borrow()];
131 }
132
133 item.as_mut_hash().unwrap().remove(&Yaml::String(key));
135 }
136
137 fn current_mut(&'_ mut self) -> &'_ mut Yaml {
139 self.key_stack
140 .iter()
141 .fold(&mut self.yaml, |item, key| &mut item[key.borrow()])
142 }
143
144 #[cfg(feature = "log")]
146 fn display_full_key(&self) -> String {
147 if self.key_stack.is_empty() {
148 return "root".to_string();
149 }
150
151 let mut output = "[".to_string();
152 let mut first = true;
153 for key in &self.key_stack {
154 output = format!("{output}{}{}", if first { "" } else { "." }, key);
156 first = false;
157 }
158 format!("{output}]")
159 }
160}
161
162impl<'shape> Default for YamlSerializer<'shape> {
163 fn default() -> Self {
164 Self::new()
165 }
166}
167
168impl<'shape> Serializer<'shape> for YamlSerializer<'shape> {
169 type Error = YamlSerError;
170
171 fn serialize_u64(&mut self, value: u64) -> Result<(), Self::Error> {
172 let yaml_number = TryInto::<i64>::try_into(value)
173 .map_err(|_| YamlSerError::InvalidNumberToI64Conversion { source_type: "u64" })?;
174 self.write_value(Yaml::Integer(yaml_number))
175 }
176
177 fn serialize_u128(&mut self, value: u128) -> Result<(), Self::Error> {
178 let yaml_number = TryInto::<i64>::try_into(value).map_err(|_| {
179 YamlSerError::InvalidNumberToI64Conversion {
180 source_type: "u128",
181 }
182 })?;
183 self.write_value(Yaml::Integer(yaml_number))
184 }
185
186 fn serialize_i64(&mut self, value: i64) -> Result<(), Self::Error> {
187 self.write_value(Yaml::Integer(value))
188 }
189
190 fn serialize_i128(&mut self, value: i128) -> Result<(), Self::Error> {
191 let yaml_number = TryInto::<i64>::try_into(value).map_err(|_| {
192 YamlSerError::InvalidNumberToI64Conversion {
193 source_type: "i128",
194 }
195 })?;
196 self.write_value(Yaml::Integer(yaml_number))
197 }
198
199 fn serialize_f64(&mut self, value: f64) -> Result<(), Self::Error> {
200 self.write_value(Yaml::Real(value.to_string()))
201 }
202
203 fn serialize_bool(&mut self, value: bool) -> Result<(), Self::Error> {
204 self.write_value(Yaml::Boolean(value))
205 }
206
207 fn serialize_char(&mut self, value: char) -> Result<(), Self::Error> {
208 self.write_value(Yaml::String(value.to_string()))
209 }
210
211 fn serialize_str(&mut self, value: &str) -> Result<(), Self::Error> {
212 self.write_value(Yaml::String(value.to_string()))
213 }
214
215 fn serialize_bytes(&mut self, _value: &[u8]) -> Result<(), Self::Error> {
216 Err(YamlSerError::UnsupportedByteArray)
217 }
218
219 fn serialize_none(&mut self) -> Result<(), Self::Error> {
220 self.write_value(Yaml::Null)
221 }
222
223 fn serialize_unit(&mut self) -> Result<(), Self::Error> {
224 self.write_value(Yaml::Null)
225 }
226
227 fn serialize_unit_variant(
228 &mut self,
229 _variant_index: usize,
230 _variant_name: &'shape str,
231 ) -> Result<(), Self::Error> {
232 todo!()
233 }
234
235 fn start_object(&mut self, _len: Option<usize>) -> Result<(), Self::Error> {
236 self.set_current(Yaml::Hash(Hash::new()));
237
238 Ok(())
239 }
240
241 fn start_array(&mut self, _len: Option<usize>) -> Result<(), Self::Error> {
242 self.set_current(Yaml::Array(Array::new()));
243
244 Ok(())
245 }
246
247 fn start_map(&mut self, _len: Option<usize>) -> Result<(), Self::Error> {
248 self.set_current(Yaml::Hash(Hash::new()));
249
250 Ok(())
251 }
252
253 fn serialize_field_name(&mut self, name: &'shape str) -> Result<(), Self::Error> {
254 self.push_key(Cow::Borrowed(name), "field");
255
256 Ok(())
257 }
258
259 fn begin_map_key(&mut self) -> Result<(), Self::Error> {
260 self.current = KeyOrValue::Key;
261
262 Ok(())
263 }
264
265 fn end_map_key(&mut self) -> Result<(), Self::Error> {
266 self.current = KeyOrValue::Value;
267
268 Ok(())
269 }
270
271 fn end_map_value(&mut self) -> Result<(), Self::Error> {
272 self.pop_key("map item");
273
274 Ok(())
275 }
276
277 fn end_field(&mut self) -> Result<(), Self::Error> {
278 self.pop_key("field");
279
280 Ok(())
281 }
282}
283
284#[derive(Clone, Copy, PartialEq, Eq)]
286enum KeyOrValue {
287 Key,
289 Value,
291}
292
293#[cfg(feature = "alloc")]
295pub fn to_string<'a, T: facet_core::Facet<'a>>(value: &'a T) -> Result<String, YamlSerError> {
296 let mut serializer = YamlSerializer::new();
297 value.serialize(&mut serializer)?;
298
299 Ok(serializer.into_string())
300}
301
302fn type_name(yaml: &Yaml) -> &'static str {
304 match yaml {
305 Yaml::Real(_) => "real",
306 Yaml::Integer(_) => "integer",
307 Yaml::String(_) => "string",
308 Yaml::Boolean(_) => "boolean",
309 Yaml::Array(_) => "array",
310 Yaml::Hash(_) => "hash",
311 Yaml::Alias(_) => "alias",
312 Yaml::Null => "null",
313 Yaml::BadValue => "bad value",
314 }
315}