aboutsummaryrefslogtreecommitdiff
path: root/src/de/table.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/de/table.rs')
-rw-r--r--src/de/table.rs213
1 files changed, 213 insertions, 0 deletions
diff --git a/src/de/table.rs b/src/de/table.rs
new file mode 100644
index 0000000..0b6183e
--- /dev/null
+++ b/src/de/table.rs
@@ -0,0 +1,213 @@
+use serde::de::IntoDeserializer;
+
+use crate::de::Error;
+
+pub(crate) struct TableDeserializer {
+ span: Option<std::ops::Range<usize>>,
+ items: crate::table::KeyValuePairs,
+}
+
+// Note: this is wrapped by `Deserializer` and `ValueDeserializer` and any trait methods
+// implemented here need to be wrapped there
+impl<'de> serde::Deserializer<'de> for TableDeserializer {
+ type Error = Error;
+
+ fn deserialize_any<V>(self, visitor: V) -> Result<V::Value, Self::Error>
+ where
+ V: serde::de::Visitor<'de>,
+ {
+ visitor.visit_map(crate::de::TableMapAccess::new(self))
+ }
+
+ // `None` is interpreted as a missing field so be sure to implement `Some`
+ // as a present field.
+ fn deserialize_option<V>(self, visitor: V) -> Result<V::Value, Error>
+ where
+ V: serde::de::Visitor<'de>,
+ {
+ visitor.visit_some(self)
+ }
+
+ fn deserialize_newtype_struct<V>(
+ self,
+ _name: &'static str,
+ visitor: V,
+ ) -> Result<V::Value, Error>
+ where
+ V: serde::de::Visitor<'de>,
+ {
+ visitor.visit_newtype_struct(self)
+ }
+
+ fn deserialize_struct<V>(
+ self,
+ name: &'static str,
+ fields: &'static [&'static str],
+ visitor: V,
+ ) -> Result<V::Value, Error>
+ where
+ V: serde::de::Visitor<'de>,
+ {
+ if serde_spanned::__unstable::is_spanned(name, fields) {
+ if let Some(span) = self.span.clone() {
+ return visitor.visit_map(super::SpannedDeserializer::new(self, span));
+ }
+ }
+
+ self.deserialize_any(visitor)
+ }
+
+ // Called when the type to deserialize is an enum, as opposed to a field in the type.
+ fn deserialize_enum<V>(
+ self,
+ _name: &'static str,
+ _variants: &'static [&'static str],
+ visitor: V,
+ ) -> Result<V::Value, Error>
+ where
+ V: serde::de::Visitor<'de>,
+ {
+ if self.items.is_empty() {
+ Err(crate::de::Error::custom(
+ "wanted exactly 1 element, found 0 elements",
+ self.span,
+ ))
+ } else if self.items.len() != 1 {
+ Err(crate::de::Error::custom(
+ "wanted exactly 1 element, more than 1 element",
+ self.span,
+ ))
+ } else {
+ visitor.visit_enum(crate::de::TableMapAccess::new(self))
+ }
+ }
+
+ serde::forward_to_deserialize_any! {
+ bool u8 u16 u32 u64 i8 i16 i32 i64 f32 f64 char str string seq
+ bytes byte_buf map unit
+ ignored_any unit_struct tuple_struct tuple identifier
+ }
+}
+
+impl<'de> serde::de::IntoDeserializer<'de, crate::de::Error> for TableDeserializer {
+ type Deserializer = TableDeserializer;
+
+ fn into_deserializer(self) -> Self::Deserializer {
+ self
+ }
+}
+
+impl crate::Table {
+ pub(crate) fn into_deserializer(self) -> TableDeserializer {
+ TableDeserializer {
+ span: self.span(),
+ items: self.items,
+ }
+ }
+}
+
+impl crate::InlineTable {
+ pub(crate) fn into_deserializer(self) -> TableDeserializer {
+ TableDeserializer {
+ span: self.span(),
+ items: self.items,
+ }
+ }
+}
+
+pub(crate) struct TableMapAccess {
+ iter: indexmap::map::IntoIter<crate::InternalString, crate::table::TableKeyValue>,
+ span: Option<std::ops::Range<usize>>,
+ value: Option<(crate::InternalString, crate::Item)>,
+}
+
+impl TableMapAccess {
+ pub(crate) fn new(input: TableDeserializer) -> Self {
+ Self {
+ iter: input.items.into_iter(),
+ span: input.span,
+ value: None,
+ }
+ }
+}
+
+impl<'de> serde::de::MapAccess<'de> for TableMapAccess {
+ type Error = Error;
+
+ fn next_key_seed<K>(&mut self, seed: K) -> Result<Option<K::Value>, Self::Error>
+ where
+ K: serde::de::DeserializeSeed<'de>,
+ {
+ match self.iter.next() {
+ Some((k, v)) => {
+ let ret = seed
+ .deserialize(super::KeyDeserializer::new(k, v.key.span()))
+ .map(Some)
+ .map_err(|mut e: Self::Error| {
+ if e.span().is_none() {
+ e.set_span(v.key.span());
+ }
+ e
+ });
+ self.value = Some((v.key.into(), v.value));
+ ret
+ }
+ None => Ok(None),
+ }
+ }
+
+ fn next_value_seed<V>(&mut self, seed: V) -> Result<V::Value, Self::Error>
+ where
+ V: serde::de::DeserializeSeed<'de>,
+ {
+ match self.value.take() {
+ Some((k, v)) => {
+ let span = v.span();
+ seed.deserialize(crate::de::ValueDeserializer::new(v))
+ .map_err(|mut e: Self::Error| {
+ if e.span().is_none() {
+ e.set_span(span);
+ }
+ e.add_key(k.as_str().to_owned());
+ e
+ })
+ }
+ None => {
+ panic!("no more values in next_value_seed, internal error in ValueDeserializer")
+ }
+ }
+ }
+}
+
+impl<'de> serde::de::EnumAccess<'de> for TableMapAccess {
+ type Error = Error;
+ type Variant = super::TableEnumDeserializer;
+
+ fn variant_seed<V>(mut self, seed: V) -> Result<(V::Value, Self::Variant), Self::Error>
+ where
+ V: serde::de::DeserializeSeed<'de>,
+ {
+ let (key, value) = match self.iter.next() {
+ Some(pair) => pair,
+ None => {
+ return Err(Error::custom(
+ "expected table with exactly 1 entry, found empty table",
+ self.span,
+ ));
+ }
+ };
+
+ let val = seed
+ .deserialize(key.into_deserializer())
+ .map_err(|mut e: Self::Error| {
+ if e.span().is_none() {
+ e.set_span(value.key.span());
+ }
+ e
+ })?;
+
+ let variant = super::TableEnumDeserializer::new(value.value);
+
+ Ok((val, variant))
+ }
+}