facet_toml/
lib.rs

1#![warn(missing_docs)]
2#![doc = include_str!("../README.md")]
3
4pub mod error;
5mod to_scalar;
6
7use std::{
8    borrow::Cow,
9    net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr},
10    num::NonZero,
11};
12
13use error::AnyErr;
14use facet_core::{Facet, Opaque, VariantKind};
15use facet_reflect::{PokeEnumNoVariant, PokeStruct, PokeUninit, PokeValueUninit};
16use toml_edit::{DocumentMut, Item, TomlError};
17
18/// Deserializes a TOML string into a value of type `T` that implements `Facet`.
19pub fn from_str<T: Facet>(toml: &str) -> Result<T, AnyErr> {
20    let (poke, _guard) = PokeUninit::alloc::<T>();
21    let opaque = from_str_opaque(poke, toml)?;
22    Ok(unsafe { opaque.read::<T>() })
23}
24
25fn from_str_opaque<'mem>(poke: PokeUninit<'mem>, toml: &str) -> Result<Opaque<'mem>, AnyErr> {
26    let docs: DocumentMut = toml.parse().map_err(|e| TomlError::to_string(&e))?;
27    deserialize_item(poke, docs.as_item())
28}
29
30fn deserialize_item<'mem>(poke: PokeUninit<'mem>, item: &Item) -> Result<Opaque<'mem>, AnyErr> {
31    match poke {
32        PokeUninit::Scalar(poke) => deserialize_as_scalar(poke, item),
33        PokeUninit::List(_) => todo!(),
34        PokeUninit::Map(_) => todo!(),
35        PokeUninit::Struct(poke) => deserialize_as_struct(poke, item),
36        PokeUninit::Enum(poke) => deserialize_as_enum(poke, item),
37        _ => todo!("unsupported poke type"),
38    }
39}
40
41fn deserialize_as_struct<'mem>(
42    mut poke: PokeStruct<'mem>,
43    item: &Item,
44) -> Result<Opaque<'mem>, AnyErr> {
45    // Parse as a the inner struct type if item is a single value and the struct is a unit struct
46    if item.is_value() {
47        // Only allow unit structs
48        if poke.def().fields.len() > 1 {
49            return Err(
50                "Failed trying to parse a single value as a struct with multiple fields".into(),
51            );
52        }
53
54        return deserialize_item(
55            poke.field(0)
56                .map_err(|e| format!("Unit struct is missing value: {e}"))?,
57            item,
58        );
59    }
60
61    // Otherwise we expect a table
62    let table = item
63        .as_table_like()
64        .ok_or_else(|| format!("Expected table like structure, got {}", item.type_name()))?;
65
66    for (k, v) in table.iter() {
67        let (index, field_poke) = poke
68            .field_by_name(k)
69            .map_err(|e| format!("Field '{}' error: {}", k, e))?;
70        let _v = deserialize_item(field_poke, v)
71            .map_err(|e| format!("Error deserializing field '{}': {}", k, e))?;
72        unsafe {
73            poke.mark_initialized(index);
74        }
75    }
76
77    Ok(poke.build_in_place())
78}
79
80fn deserialize_as_enum<'mem>(
81    poke: PokeEnumNoVariant<'mem>,
82    item: &Item,
83) -> Result<Opaque<'mem>, AnyErr> {
84    // Item is a single value, try to get the variant with the name
85    if item.is_value() {
86        let value = item
87            .as_str()
88            .ok_or_else(|| format!("Expokected string, got: {}", item.type_name()))?;
89
90        let variant = poke
91            .variant_by_name(value)
92            .ok_or_else(|| format!("Enum does not have a variant named '{value}'"))?;
93
94        if variant.kind != VariantKind::Unit {
95            return Err(format!("variant '{value}' is not a unit variant").into());
96        }
97
98        Ok(poke
99            .set_variant_by_name(value)
100            .map_err(|err| err.to_string())?
101            .build_in_place())
102    } else {
103        todo!()
104    }
105}
106
107fn deserialize_as_scalar<'mem>(
108    poke: PokeValueUninit<'mem>,
109    item: &Item,
110) -> Result<Opaque<'mem>, AnyErr> {
111    let shape = poke.shape();
112
113    Ok(if shape.is_type::<String>() {
114        poke.put(to_scalar::string(item)?)
115    } else if shape.is_type::<Cow<'_, str>>() {
116        poke.put(Cow::Owned(to_scalar::string(item)?))
117    } else if shape.is_type::<bool>() {
118        poke.put(to_scalar::boolean(item)?)
119    } else if shape.is_type::<f64>() {
120        poke.put(to_scalar::number::<f64>(item)?)
121    } else if shape.is_type::<f32>() {
122        poke.put(to_scalar::number::<f32>(item)?)
123    } else if shape.is_type::<usize>() {
124        poke.put(to_scalar::number::<usize>(item)?)
125    } else if shape.is_type::<u128>() {
126        poke.put(to_scalar::number::<u128>(item)?)
127    } else if shape.is_type::<u64>() {
128        poke.put(to_scalar::number::<u64>(item)?)
129    } else if shape.is_type::<u32>() {
130        poke.put(to_scalar::number::<u32>(item)?)
131    } else if shape.is_type::<u16>() {
132        poke.put(to_scalar::number::<u16>(item)?)
133    } else if shape.is_type::<u8>() {
134        poke.put(to_scalar::number::<u8>(item)?)
135    } else if shape.is_type::<isize>() {
136        poke.put(to_scalar::number::<isize>(item)?)
137    } else if shape.is_type::<i128>() {
138        poke.put(to_scalar::number::<i128>(item)?)
139    } else if shape.is_type::<i64>() {
140        poke.put(to_scalar::number::<i64>(item)?)
141    } else if shape.is_type::<i32>() {
142        poke.put(to_scalar::number::<i32>(item)?)
143    } else if shape.is_type::<i16>() {
144        poke.put(to_scalar::number::<i16>(item)?)
145    } else if shape.is_type::<i8>() {
146        poke.put(to_scalar::number::<i8>(item)?)
147    } else if shape.is_type::<NonZero<usize>>() {
148        // TODO: create a to_scalar::nonzero_number method when we can use a trait to do so
149        poke.put(
150            NonZero::new(to_scalar::number::<usize>(item)?)
151                .ok_or("Could not convert number to non-zero variant")?,
152        )
153    } else if shape.is_type::<NonZero<u128>>() {
154        poke.put(
155            NonZero::new(to_scalar::number::<u128>(item)?)
156                .ok_or("Could not convert number to non-zero variant")?,
157        )
158    } else if shape.is_type::<NonZero<u64>>() {
159        poke.put(
160            NonZero::new(to_scalar::number::<u64>(item)?)
161                .ok_or("Could not convert number to non-zero variant")?,
162        )
163    } else if shape.is_type::<NonZero<u32>>() {
164        poke.put(
165            NonZero::new(to_scalar::number::<u32>(item)?)
166                .ok_or("Could not convert number to non-zero variant")?,
167        )
168    } else if shape.is_type::<NonZero<u16>>() {
169        poke.put(
170            NonZero::new(to_scalar::number::<u16>(item)?)
171                .ok_or("Could not convert number to non-zero variant")?,
172        )
173    } else if shape.is_type::<NonZero<u8>>() {
174        poke.put(
175            NonZero::new(to_scalar::number::<u8>(item)?)
176                .ok_or("Could not convert number to non-zero variant")?,
177        )
178    } else if shape.is_type::<NonZero<isize>>() {
179        poke.put(
180            NonZero::new(to_scalar::number::<isize>(item)?)
181                .ok_or("Could not convert number to non-zero variant")?,
182        )
183    } else if shape.is_type::<NonZero<i128>>() {
184        poke.put(
185            NonZero::new(to_scalar::number::<i128>(item)?)
186                .ok_or("Could not convert number to non-zero variant")?,
187        )
188    } else if shape.is_type::<NonZero<i64>>() {
189        poke.put(
190            NonZero::new(to_scalar::number::<i64>(item)?)
191                .ok_or("Could not convert number to non-zero variant")?,
192        )
193    } else if shape.is_type::<NonZero<i32>>() {
194        poke.put(
195            NonZero::new(to_scalar::number::<i32>(item)?)
196                .ok_or("Could not convert number to non-zero variant")?,
197        )
198    } else if shape.is_type::<NonZero<i16>>() {
199        poke.put(
200            NonZero::new(to_scalar::number::<i16>(item)?)
201                .ok_or("Could not convert number to non-zero variant")?,
202        )
203    } else if shape.is_type::<NonZero<i8>>() {
204        poke.put(
205            NonZero::new(to_scalar::number::<i8>(item)?)
206                .ok_or("Could not convert number to non-zero variant")?,
207        )
208    } else if shape.is_type::<SocketAddr>() {
209        poke.put(to_scalar::from_str::<SocketAddr>(item, "socket address")?)
210    } else if shape.is_type::<IpAddr>() {
211        poke.put(to_scalar::from_str::<IpAddr>(item, "ip address")?)
212    } else if shape.is_type::<Ipv4Addr>() {
213        poke.put(to_scalar::from_str::<Ipv4Addr>(item, "ipv4 address")?)
214    } else if shape.is_type::<Ipv6Addr>() {
215        poke.put(to_scalar::from_str::<Ipv6Addr>(item, "ipv6 address")?)
216    } else {
217        return Err(format!("Unsupported scalar type: {}", poke.shape()).into());
218    })
219}