1#![warn(missing_docs)]
2#![doc = include_str!("../README.md")]
3
4pub mod error;
5mod to_scalar;
6
7use core::net::{IpAddr, Ipv4Addr, Ipv6Addr};
8
9use error::AnyErr;
10use facet_core::{Def, Facet, StructKind};
11use facet_reflect::{ScalarType, Wip};
12use log::trace;
13use toml_edit::{DocumentMut, Item, TomlError};
14use yansi::Paint as _;
15
16pub fn from_str<T: Facet>(toml: &str) -> Result<T, AnyErr> {
18 trace!("Starting deserialization");
19
20 let wip = Wip::alloc::<T>();
21
22 let docs: DocumentMut = toml.parse().map_err(|e| TomlError::to_string(&e))?;
23 let wip = deserialize_item(wip, docs.as_item())?;
24
25 let heap_value = wip.build().map_err(|e| AnyErr(e.to_string()))?;
26 let result = heap_value
27 .materialize::<T>()
28 .map_err(|e| AnyErr(e.to_string()))?;
29
30 trace!("Finished deserialization");
31
32 Ok(result)
33}
34
35fn deserialize_item<'a>(wip: Wip<'a>, item: &Item) -> Result<Wip<'a>, AnyErr> {
36 trace!("Deserializing {}", item.type_name().blue());
37
38 match wip.shape().def {
39 Def::Scalar(_) => deserialize_as_scalar(wip, item),
40 Def::List(_) => deserialize_as_list(wip, item),
41 Def::Map(_) => deserialize_as_map(wip, item),
42 Def::Struct(_) => deserialize_as_struct(wip, item),
43 Def::Enum(_) => deserialize_as_enum(wip, item),
44 Def::Option(_) => deserialize_as_option(wip, item),
45 Def::SmartPointer(_) => deserialize_as_smartpointer(wip, item),
46 _ => Err(AnyErr(format!("Unsupported type: {:?}", wip.shape()))),
47 }
48}
49
50fn deserialize_as_struct<'a>(mut wip: Wip<'a>, item: &Item) -> Result<Wip<'a>, AnyErr> {
51 trace!("Deserializing {}", "struct".blue());
52
53 if item.is_value() && !item.is_inline_table() {
55 let shape = wip.shape();
57 if let Def::Struct(def) = shape.def {
58 if def.fields.len() > 1 {
59 return Err(AnyErr(
60 "Failed trying to parse a single value as a struct with multiple fields".into(),
61 ));
62 }
63 }
64
65 let field_index = 0;
66 wip = wip
67 .field(field_index)
68 .map_err(|e| AnyErr(format!("Unit struct is missing value: {}", e)))?;
69 wip = deserialize_item(wip, item)?;
70 wip = wip.pop().map_err(|e| AnyErr(e.to_string()))?;
71 return Ok(wip);
72 }
73
74 let table = item.as_table_like().ok_or_else(|| {
76 AnyErr(format!(
77 "Expected table like structure, got {}",
78 item.type_name()
79 ))
80 })?;
81
82 for (k, v) in table.iter() {
83 let field_index = wip
84 .field_index(k)
85 .ok_or_else(|| AnyErr(format!("Field '{}' not found", k)))?;
86 wip = wip
87 .field(field_index)
88 .map_err(|e| AnyErr(format!("Field '{}' error: {}", k, e)))?;
89 wip = deserialize_item(wip, v)
90 .map_err(|e| AnyErr(format!("Error deserializing field '{}': {}", k, e)))?;
91 wip = wip.pop().map_err(|e| AnyErr(e.to_string()))?;
92 }
93
94 trace!("Finished deserializing {}", "struct".blue());
95
96 Ok(wip)
97}
98
99fn deserialize_as_enum<'a>(wip: Wip<'a>, item: &Item) -> Result<Wip<'a>, AnyErr> {
100 trace!("Deserializing {}", "enum".blue());
101
102 let wip = match item {
103 Item::None => todo!(),
104
105 Item::Value(value) => {
106 trace!("Entering {}", "value".cyan());
107
108 if let Some(inline_table) = value.as_inline_table() {
110 if let Some((key, field)) = inline_table.iter().next() {
111 trace!(
112 "Entering {} with key {}",
113 "inline table".cyan(),
114 key.cyan().bold()
115 );
116
117 if inline_table.len() > 1 {
118 return Err(AnyErr(
119 "Cannot parse enum from inline table because it got multiple fields"
120 .to_string(),
121 ));
122 } else {
123 return build_enum_from_variant_name(
124 wip,
125 key,
126 &Item::Value(field.clone()),
128 );
129 }
130 } else {
131 return Err(AnyErr(
132 "Inline table doesn't have any fields to parse into enum variant"
133 .to_string(),
134 ));
135 }
136 }
137
138 let variant_name = value
139 .as_str()
140 .ok_or_else(|| format!("Expected string, got: {}", value.type_name()))?;
141
142 build_enum_from_variant_name(wip, variant_name, item)?
143 }
144
145 Item::Table(table) => {
146 if let Some((key, field)) = table.iter().next() {
147 trace!("Entering {} with key {}", "table".cyan(), key.cyan().bold());
148
149 if table.len() > 1 {
150 return Err(AnyErr(
151 "Cannot parse enum from inline table because it got multiple fields"
152 .to_string(),
153 ));
154 } else {
155 build_enum_from_variant_name(wip, key, field)?
156 }
157 } else {
158 return Err(AnyErr(
159 "Inline table doesn't have any fields to parse into enum variant".to_string(),
160 ));
161 }
162 }
163
164 Item::ArrayOfTables(_array_of_tables) => todo!(),
165 };
166
167 trace!("Finished deserializing {}", "enum".blue());
168
169 Ok(wip)
170}
171
172fn build_enum_from_variant_name<'a>(
173 mut wip: Wip<'a>,
174 variant_name: &str,
175 item: &Item,
176) -> Result<Wip<'a>, AnyErr> {
177 wip = wip
179 .variant_named(variant_name)
180 .map_err(|e| AnyErr(e.to_string()))?;
181 let variant = wip.selected_variant().unwrap();
183
184 if variant.data.kind == StructKind::Unit {
185 return Ok(wip);
187 }
188
189 for (index, field) in variant.data.fields.iter().enumerate() {
191 wip = wip
192 .field_named(field.name)
193 .map_err(|e| format!("Field by name on enum does not exist: {e}"))?;
194
195 if let Some(item) = item.as_table_like() {
197 let field_name = if let StructKind::TupleStruct | StructKind::Tuple = variant.data.kind
199 {
200 &index.to_string()
201 } else {
202 field.name
204 };
205
206 let Some(field) = item.get(field_name) else {
208 return Err(format!("TOML field '{}' not found", field_name).into());
209 };
210
211 wip = deserialize_item(wip, field)?;
212
213 wip = wip.pop().map_err(|e| AnyErr(e.to_string()))?;
214 } else if item.is_value() {
215 wip = deserialize_item(wip, item)?;
216 } else {
217 return Err(format!("TOML {} is not a recognized type", item.type_name()).into());
218 }
219 }
220
221 Ok(wip)
222}
223
224fn deserialize_as_list<'a>(mut wip: Wip<'a>, item: &Item) -> Result<Wip<'a>, AnyErr> {
225 trace!("Deserializing {}", "list".blue());
226
227 let Some(item) = item.as_array() else {
229 return Err(AnyErr(format!(
230 "Item is not an array but a {}",
231 item.type_name()
232 )));
233 };
234
235 if item.is_empty() {
236 return wip
238 .put_empty_list()
239 .map_err(|e| AnyErr(format!("Can not put empty list: {e}")));
240 }
241
242 wip = wip
244 .begin_pushback()
245 .map_err(|e| format!("Can not start filling list: {e}"))?;
246
247 for value in item.iter() {
249 wip = wip
251 .push()
252 .map_err(|e| format!("Can not start field: {e}"))?;
253
254 wip = deserialize_item(
255 wip,
256 &Item::Value(value.clone()),
258 )?;
259
260 wip = wip
262 .pop()
263 .map_err(|e| format!("Can not finish field: {e}"))?;
264 }
265
266 trace!("Finished deserializing {}", "list".blue());
267
268 Ok(wip)
269}
270
271fn deserialize_as_map<'a>(mut wip: Wip<'a>, item: &Item) -> Result<Wip<'a>, AnyErr> {
272 trace!("Deserializing {}", "map".blue());
273
274 let table = item.as_table_like().ok_or_else(|| {
276 AnyErr(format!(
277 "Expected table like structure, got {}",
278 item.type_name()
279 ))
280 })?;
281
282 if table.is_empty() {
283 return wip
285 .put_empty_map()
286 .map_err(|e| AnyErr(format!("Can not put empty map: {e}")));
287 }
288
289 wip = wip
291 .begin_map_insert()
292 .map_err(|e| format!("Can not start filling map: {e}"))?;
293
294 for (k, v) in table.iter() {
296 wip = wip
298 .push_map_key()
299 .map_err(|e| format!("Can not start field: {e}"))?;
300
301 trace!("Push {} {}", "key".cyan(), k.cyan().bold());
302
303 match ScalarType::try_from_shape(wip.shape())
305 .ok_or_else(|| format!("Unsupported scalar type: {}", wip.shape()))?
306 {
307 #[cfg(feature = "std")]
308 ScalarType::String => {
309 wip = wip.put(k.to_string()).map_err(|e| AnyErr(e.to_string()))?
310 }
311 #[cfg(feature = "std")]
312 ScalarType::CowStr => {
313 wip = wip
314 .put(std::borrow::Cow::Owned(k.to_string()))
315 .map_err(|e| AnyErr(e.to_string()))?
316 }
317 _ => {
318 return Err(AnyErr(format!(
319 "Can not convert {} to map key",
320 wip.shape()
321 )));
322 }
323 };
324
325 trace!("Push {}", "value".cyan());
326
327 wip = wip
329 .push_map_value()
330 .map_err(|e| format!("Can not start value: {e}"))?;
331
332 wip = deserialize_item(wip, v)?;
334
335 wip = wip
337 .pop()
338 .map_err(|e| format!("Can not finish value: {e}"))?;
339 }
340
341 trace!("Finished deserializing {}", "map".blue());
342
343 Ok(wip)
344}
345
346fn deserialize_as_option<'a>(mut _wip: Wip<'a>, _item: &Item) -> Result<Wip<'a>, AnyErr> {
347 trace!("Deserializing {}", "option".blue());
348
349 trace!("Finished deserializing {}", "option".blue());
350
351 todo!();
352}
353
354fn deserialize_as_smartpointer<'a>(mut _wip: Wip<'a>, _item: &Item) -> Result<Wip<'a>, AnyErr> {
355 trace!("Deserializing {}", "smart pointer".blue());
356
357 trace!("Finished deserializing {}", "smart pointer".blue());
358
359 todo!();
360}
361
362fn deserialize_as_scalar<'a>(mut wip: Wip<'a>, item: &Item) -> Result<Wip<'a>, AnyErr> {
363 trace!("Deserializing {}", "scalar".blue());
364
365 match ScalarType::try_from_shape(wip.shape())
366 .ok_or_else(|| format!("Unsupported scalar type: {}", wip.shape()))?
367 {
368 ScalarType::Bool => {
369 wip = wip
370 .put(to_scalar::boolean(item)?)
371 .map_err(|e| AnyErr(e.to_string()))?
372 }
373 #[cfg(feature = "std")]
374 ScalarType::String => {
375 wip = wip
376 .put(to_scalar::string(item)?)
377 .map_err(|e| AnyErr(e.to_string()))?
378 }
379 #[cfg(feature = "std")]
380 ScalarType::CowStr => {
381 wip = wip
382 .put(std::borrow::Cow::Owned(to_scalar::string(item)?))
383 .map_err(|e| AnyErr(e.to_string()))?
384 }
385 ScalarType::F32 => {
386 wip = wip
387 .put(to_scalar::number::<f32>(item)?)
388 .map_err(|e| AnyErr(e.to_string()))?
389 }
390 ScalarType::F64 => {
391 wip = wip
392 .put(to_scalar::number::<f64>(item)?)
393 .map_err(|e| AnyErr(e.to_string()))?
394 }
395 ScalarType::U8 => {
396 wip = wip
397 .put(to_scalar::number::<u8>(item)?)
398 .map_err(|e| AnyErr(e.to_string()))?
399 }
400 ScalarType::U16 => {
401 wip = wip
402 .put(to_scalar::number::<u16>(item)?)
403 .map_err(|e| AnyErr(e.to_string()))?
404 }
405 ScalarType::U32 => {
406 wip = wip
407 .put(to_scalar::number::<u32>(item)?)
408 .map_err(|e| AnyErr(e.to_string()))?
409 }
410 ScalarType::U64 => {
411 wip = wip
412 .put(to_scalar::number::<u64>(item)?)
413 .map_err(|e| AnyErr(e.to_string()))?
414 }
415 ScalarType::USize => {
416 wip = wip
417 .put(to_scalar::number::<usize>(item)?)
418 .map_err(|e| AnyErr(e.to_string()))?
419 }
420 ScalarType::I8 => {
421 wip = wip
422 .put(to_scalar::number::<i8>(item)?)
423 .map_err(|e| AnyErr(e.to_string()))?
424 }
425 ScalarType::I16 => {
426 wip = wip
427 .put(to_scalar::number::<i16>(item)?)
428 .map_err(|e| AnyErr(e.to_string()))?
429 }
430 ScalarType::I32 => {
431 wip = wip
432 .put(to_scalar::number::<i32>(item)?)
433 .map_err(|e| AnyErr(e.to_string()))?
434 }
435 ScalarType::I64 => {
436 wip = wip
437 .put(to_scalar::number::<i64>(item)?)
438 .map_err(|e| AnyErr(e.to_string()))?
439 }
440 ScalarType::ISize => {
441 wip = wip
442 .put(to_scalar::number::<isize>(item)?)
443 .map_err(|e| AnyErr(e.to_string()))?
444 }
445 #[cfg(feature = "std")]
446 ScalarType::SocketAddr => {
447 wip = wip
448 .put(to_scalar::from_str::<std::net::SocketAddr>(
449 item,
450 "socket address",
451 )?)
452 .map_err(|e| AnyErr(e.to_string()))?
453 }
454 ScalarType::IpAddr => {
455 wip = wip
456 .put(to_scalar::from_str::<IpAddr>(item, "ip address")?)
457 .map_err(|e| AnyErr(e.to_string()))?
458 }
459 ScalarType::Ipv4Addr => {
460 wip = wip
461 .put(to_scalar::from_str::<Ipv4Addr>(item, "ipv4 address")?)
462 .map_err(|e| AnyErr(e.to_string()))?
463 }
464 ScalarType::Ipv6Addr => {
465 wip = wip
466 .put(to_scalar::from_str::<Ipv6Addr>(item, "ipv6 address")?)
467 .map_err(|e| AnyErr(e.to_string()))?
468 }
469 _ => return Err(AnyErr(format!("Unsupported scalar type: {}", wip.shape()))),
470 }
471
472 trace!("Finished deserializing {}", "scalar".blue());
473
474 Ok(wip)
475}