From 3917b5dd883db3b2118f8b0a1d9422e0a955bec6 Mon Sep 17 00:00:00 2001 From: Myles Wirth Date: Wed, 18 Mar 2026 17:39:45 -0400 Subject: [PATCH] serde: deserializaiton support --- src/de.rs | 1030 ++++++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 829 insertions(+), 201 deletions(-) diff --git a/src/de.rs b/src/de.rs index a1a1d06..be75c2f 100644 --- a/src/de.rs +++ b/src/de.rs @@ -2,234 +2,862 @@ use serde::{de, Deserialize}; use thiserror::Error; use winnow::{stream::Recoverable, Located}; -use crate::{v2_parser::KdlParseError, KdlParseFailure}; +use std::fmt; -/// serde deserializer for KDL documents -#[derive(Debug)] -pub struct Deserializer<'de> { - input: Recoverable, KdlParseError>, +use serde::de::{self, DeserializeSeed, Deserializer as _, MapAccess, SeqAccess, Visitor}; +use serde::Deserialize; + +use crate::{KdlDocument, KdlEntry, KdlNode, KdlValue}; + +/// Errors that can occur during KDL deserialization. +#[derive(Debug, Clone)] +pub struct Error { + msg: String, } -impl<'de> Deserializer<'de> { - /// Create a new deserializer from a string - pub fn from_str(input: &'de str) -> Self { - Self { - input: Recoverable::new(Located::new(input)), +impl fmt::Display for Error { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "{}", self.msg) + } +} + +impl std::error::Error for Error {} + +impl de::Error for Error { + fn custom(msg: T) -> Self { + Error { + msg: msg.to_string(), } } } -/// Deserialize a type from a KDL string -pub fn from_str<'a, T>(input: &'a str) -> Result +impl From for Error { + fn from(e: crate::KdlError) -> Self { + Error { + msg: format!("{}", e), + } + } +} + +/// Helper to produce a `StrDeserializer` with our error type. +fn str_deserializer(s: &str) -> de::value::StrDeserializer<'_, Error> { + de::IntoDeserializer::into_deserializer(s) +} + +/// Deserialize a type from a KDL string. +/// +/// # Example +/// +/// ```rust +/// use serde::Deserialize; +/// +/// #[derive(Deserialize, Debug, PartialEq)] +/// struct Config { +/// name: String, +/// port: u16, +/// } +/// +/// let kdl = r#" +/// name "my-app" +/// port 8080 +/// "#; +/// +/// let config: Config = kdl::de::from_str(kdl).unwrap(); +/// assert_eq!(config, Config { name: "my-app".into(), port: 8080 }); +/// ``` +pub fn from_str<'a, T>(input: &'a str) -> Result where T: Deserialize<'a>, { + let doc: KdlDocument = input.parse().map_err(Error::from)?; + let de = DocumentDeserializer { doc: &doc }; + T::deserialize(de) } -#[derive(Debug, Error)] -struct DeError(String); - -impl std::fmt::Display for DeError { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "{}", self.0) - } +struct ValueDeserializer<'a> { + value: &'a KdlValue, } -impl de::Error for DeError { - fn custom(msg: T) -> Self { - DeError(msg.to_string()) - } -} +impl<'de, 'a> de::Deserializer<'de> for ValueDeserializer<'a> { + type Error = Error; -struct KdlVisitor; - -impl<'de> de::Visitor<'de> for KdlVisitor { - type Value = (); - - fn expecting<'a>(&self, formatter: &mut std::fmt::Formatter<'a>) -> std::fmt::Result { - write!(formatter, "a KDL value") - } - - fn visit_map(self, mut map: A) -> Result - where - A: de::MapAccess<'de>, - { - while let Some(key) = map.next_key()? { - match key { - "type" => { - let value = map.next_value::()?; - println!("type: {}", value); + fn deserialize_any>(self, visitor: V) -> Result { + match self.value { + KdlValue::String(s) => visitor.visit_str(s), + KdlValue::Integer(n) => { + if let Ok(i) = i64::try_from(*n) { + visitor.visit_i64(i) + } else if let Ok(u) = u64::try_from(*n) { + visitor.visit_u64(u) + } else { + visitor.visit_i128(*n) } - "value" => { - let value = map.next_value::()?; - println!("value: {}", value); + } + KdlValue::Float(f) => visitor.visit_f64(*f), + KdlValue::Bool(b) => visitor.visit_bool(*b), + KdlValue::Null => visitor.visit_unit(), + } + } + + fn deserialize_option>(self, visitor: V) -> Result { + match self.value { + KdlValue::Null => visitor.visit_none(), + _ => visitor.visit_some(self), + } + } + + fn deserialize_newtype_struct>( + self, + _name: &'static str, + visitor: V, + ) -> Result { + visitor.visit_newtype_struct(self) + } + + fn deserialize_enum>( + self, + _name: &'static str, + _variants: &'static [&'static str], + visitor: V, + ) -> Result { + match self.value { + KdlValue::String(s) => visitor.visit_enum(str_deserializer(s.as_str())), + _ => Err(de::Error::custom("expected a string for unit enum variant")), + } + } + + fn deserialize_string>(self, visitor: V) -> Result { + match self.value { + KdlValue::String(s) => visitor.visit_string(s.clone()), + _ => self.deserialize_any(visitor), + } + } + + fn deserialize_str>(self, visitor: V) -> Result { + match self.value { + KdlValue::String(s) => visitor.visit_str(s), + _ => self.deserialize_any(visitor), + } + } + + serde::forward_to_deserialize_any! { + bool i8 i16 i32 i64 i128 u8 u16 u32 u64 u128 f32 f64 char + bytes byte_buf unit unit_struct seq tuple + tuple_struct map struct identifier ignored_any + } +} + +struct DocumentDeserializer<'a> { + doc: &'a KdlDocument, +} + +impl<'de, 'a> de::Deserializer<'de> for DocumentDeserializer<'a> { + type Error = Error; + + fn deserialize_any>(self, visitor: V) -> Result { + self.deserialize_map(visitor) + } + + fn deserialize_map>(self, visitor: V) -> Result { + visitor.visit_map(DocumentMapAccess::new(self.doc)) + } + + fn deserialize_struct>( + self, + _name: &'static str, + _fields: &'static [&'static str], + visitor: V, + ) -> Result { + self.deserialize_map(visitor) + } + + fn deserialize_seq>(self, visitor: V) -> Result { + visitor.visit_seq(NodeListSeqAccess { + iter: self.doc.nodes().iter(), + }) + } + + fn deserialize_option>(self, visitor: V) -> Result { + if self.doc.nodes().is_empty() { + visitor.visit_none() + } else { + visitor.visit_some(self) + } + } + + fn deserialize_newtype_struct>( + self, + _name: &'static str, + visitor: V, + ) -> Result { + visitor.visit_newtype_struct(self) + } + + fn deserialize_unit>(self, visitor: V) -> Result { + visitor.visit_unit() + } + + fn deserialize_unit_struct>( + self, + _name: &'static str, + visitor: V, + ) -> Result { + visitor.visit_unit() + } + + fn deserialize_enum>( + self, + _name: &'static str, + _variants: &'static [&'static str], + visitor: V, + ) -> Result { + // For enums at document level, treat as a single-node document where + // the node name is the variant. + let nodes = self.doc.nodes(); + if nodes.len() == 1 { + visitor.visit_enum(NodeEnumAccess { node: &nodes[0] }) + } else { + Err(de::Error::custom( + "expected exactly one node for enum deserialization", + )) + } + } + + serde::forward_to_deserialize_any! { + bool i8 i16 i32 + i64 i128 u8 u16 + u32 u64 u128 f32 + f64 char str string + bytes byte_buf tuple + tuple_struct identifier ignored_any + } +} + +/// Groups nodes by name, producing deduplicated keys. Nodes that share a name +/// are collected into a Vec so they can be deserialized as sequences. +struct DocumentMapAccess<'a> { + /// Ordered unique keys (node names in first-seen order). + keys: Vec<&'a str>, + + /// All nodes grouped by name, preserving order within each group. + groups: std::collections::HashMap<&'a str, Vec<&'a KdlNode>>, + + /// Current index into `keys`. + idx: usize, +} + +impl<'a> DocumentMapAccess<'a> { + fn new(doc: &'a KdlDocument) -> Self { + let mut keys = Vec::new(); + let mut groups: std::collections::HashMap<&'a str, Vec<&'a KdlNode>> = + std::collections::HashMap::new(); + for node in doc.nodes() { + let name = node.name().value(); + if !groups.contains_key(name) { + keys.push(name); + } + groups.entry(name).or_default().push(node); + } + DocumentMapAccess { + keys, + groups, + idx: 0, + } + } +} + +impl<'de, 'a> MapAccess<'de> for DocumentMapAccess<'a> { + type Error = Error; + + fn next_key_seed>( + &mut self, + seed: K, + ) -> Result, Self::Error> { + if self.idx >= self.keys.len() { + return Ok(None); + } + let key = self.keys[self.idx]; + seed.deserialize(str_deserializer(key)).map(Some) + } + + fn next_value_seed>( + &mut self, + seed: V, + ) -> Result { + let key = self.keys[self.idx]; + self.idx += 1; + let nodes = self.groups.get(key).unwrap(); + if nodes.len() == 1 { + seed.deserialize(NodeDeserializer { node: nodes[0] }) + } else { + // Multiple nodes with same name → sequence + seed.deserialize(NodeGroupDeserializer { nodes }) + } + } +} + +struct NodeDeserializer<'a> { + node: &'a KdlNode, +} + +impl<'a> NodeDeserializer<'a> { + fn args(&self) -> Vec<&'a KdlEntry> { + self.node + .entries() + .iter() + .filter(|e| e.name().is_none()) + .collect() + } + + fn props(&self) -> Vec<&'a KdlEntry> { + self.node + .entries() + .iter() + .filter(|e| e.name().is_some()) + .collect() + } + + /// Returns true if this node has only a single argument and nothing else. + fn is_scalar(&self) -> bool { + let args = self.args(); + let props = self.props(); + args.len() == 1 && props.is_empty() && self.node.children().is_none() + } + + /// Returns true if this node is "empty" (no args, no props, no children). + fn is_empty(&self) -> bool { + self.node.entries().is_empty() && self.node.children().is_none() + } +} + +impl<'de, 'a> de::Deserializer<'de> for NodeDeserializer<'a> { + type Error = Error; + + fn deserialize_any>(self, visitor: V) -> Result { + if self.is_empty() { + // Node with no data → null/unit + return visitor.visit_unit(); + } + if self.is_scalar() { + // Single argument → deserialize as scalar + let entry = self.args()[0]; + return ValueDeserializer { + value: entry.value(), + } + .deserialize_any(visitor); + } + + let args = self.args(); + let props = self.props(); + let has_children = self.node.children().is_some(); + + if !args.is_empty() && props.is_empty() && !has_children { + // Only positional args → sequence + return visitor.visit_seq(ArgSeqAccess { + iter: args.into_iter(), + }); + } + + // Has properties and/or children → map + self.deserialize_map(visitor) + } + + fn deserialize_bool>(self, visitor: V) -> Result { + if self.is_scalar() { + ValueDeserializer { + value: self.args()[0].value(), + } + .deserialize_any(visitor) + } else { + Err(de::Error::custom("expected a boolean value")) + } + } + + fn deserialize_i8>(self, visitor: V) -> Result { + self.deserialize_scalar(visitor) + } + fn deserialize_i16>(self, visitor: V) -> Result { + self.deserialize_scalar(visitor) + } + fn deserialize_i32>(self, visitor: V) -> Result { + self.deserialize_scalar(visitor) + } + fn deserialize_i64>(self, visitor: V) -> Result { + self.deserialize_scalar(visitor) + } + fn deserialize_i128>(self, visitor: V) -> Result { + self.deserialize_scalar(visitor) + } + fn deserialize_u8>(self, visitor: V) -> Result { + self.deserialize_scalar(visitor) + } + fn deserialize_u16>(self, visitor: V) -> Result { + self.deserialize_scalar(visitor) + } + fn deserialize_u32>(self, visitor: V) -> Result { + self.deserialize_scalar(visitor) + } + fn deserialize_u64>(self, visitor: V) -> Result { + self.deserialize_scalar(visitor) + } + fn deserialize_u128>(self, visitor: V) -> Result { + self.deserialize_scalar(visitor) + } + fn deserialize_f32>(self, visitor: V) -> Result { + self.deserialize_scalar(visitor) + } + fn deserialize_f64>(self, visitor: V) -> Result { + self.deserialize_scalar(visitor) + } + fn deserialize_char>(self, visitor: V) -> Result { + self.deserialize_scalar(visitor) + } + fn deserialize_str>(self, visitor: V) -> Result { + self.deserialize_scalar(visitor) + } + fn deserialize_string>(self, visitor: V) -> Result { + self.deserialize_scalar(visitor) + } + fn deserialize_bytes>(self, visitor: V) -> Result { + self.deserialize_scalar(visitor) + } + fn deserialize_byte_buf>(self, visitor: V) -> Result { + self.deserialize_scalar(visitor) + } + + fn deserialize_option>(self, visitor: V) -> Result { + if self.is_empty() { + visitor.visit_none() + } else if self.is_scalar() { + let val = self.args()[0].value(); + if matches!(val, KdlValue::Null) { + visitor.visit_none() + } else { + visitor.visit_some(self) + } + } else { + visitor.visit_some(self) + } + } + + fn deserialize_unit>(self, visitor: V) -> Result { + visitor.visit_unit() + } + + fn deserialize_unit_struct>( + self, + _name: &'static str, + visitor: V, + ) -> Result { + visitor.visit_unit() + } + + fn deserialize_newtype_struct>( + self, + _name: &'static str, + visitor: V, + ) -> Result { + visitor.visit_newtype_struct(self) + } + + fn deserialize_seq>(self, visitor: V) -> Result { + let args = self.args(); + + if !args.is_empty() && self.node.children().is_none() { + // Arguments → sequence + visitor.visit_seq(ArgSeqAccess { + iter: args.into_iter(), + }) + } else if let Some(children) = self.node.children() { + // Children → sequence of nodes + visitor.visit_seq(NodeListSeqAccess { + iter: children.nodes().iter(), + }) + } else { + // Empty → empty sequence + visitor.visit_seq(ArgSeqAccess { + iter: Vec::new().into_iter(), + }) + } + } + + fn deserialize_tuple>( + self, + _len: usize, + visitor: V, + ) -> Result { + self.deserialize_seq(visitor) + } + + fn deserialize_tuple_struct>( + self, + _name: &'static str, + _len: usize, + visitor: V, + ) -> Result { + self.deserialize_seq(visitor) + } + + fn deserialize_map>(self, visitor: V) -> Result { + visitor.visit_map(NodeMapAccess::new(self.node)) + } + + fn deserialize_struct>( + self, + _name: &'static str, + _fields: &'static [&'static str], + visitor: V, + ) -> Result { + self.deserialize_map(visitor) + } + + fn deserialize_enum>( + self, + _name: &'static str, + _variants: &'static [&'static str], + visitor: V, + ) -> Result { + // If the node is a scalar string, treat it as a unit variant name. + if self.is_scalar() { + if let KdlValue::String(s) = self.args()[0].value() { + return visitor.visit_enum(str_deserializer(s.as_str())); + } + } + + // Otherwise, try treating the node as an externally-tagged enum: + // if there's exactly one child node, use its name as variant, body as data. + if let Some(children) = self.node.children() { + let child_nodes = children.nodes(); + if child_nodes.len() == 1 { + return visitor.visit_enum(NodeEnumAccess { + node: &child_nodes[0], + }); + } + } + + // For nodes with properties but no children, try MAP-STYLE + let props = self.props(); + if props.len() == 1 && self.args().is_empty() && self.node.children().is_none() { + let prop = props[0]; + let name = prop.name().unwrap().value(); + return visitor.visit_enum(PropertyEnumAccess { + key: name, + value: prop.value(), + }); + } + + // Fall back: just node name is variant + visitor.visit_enum(NodeEnumAccess { node: self.node }) + } + + fn deserialize_identifier>(self, visitor: V) -> Result { + self.deserialize_str(visitor) + } + + fn deserialize_ignored_any>(self, visitor: V) -> Result { + visitor.visit_unit() + } +} + +impl<'a> NodeDeserializer<'a> { + fn deserialize_scalar<'de, V: Visitor<'de>>(self, visitor: V) -> Result { + if self.is_scalar() { + ValueDeserializer { + value: self.args()[0].value(), + } + .deserialize_any(visitor) + } else { + self.deserialize_any(visitor) + } + } +} + +struct ArgSeqAccess<'a> { + iter: std::vec::IntoIter<&'a KdlEntry>, +} + +impl<'de, 'a> SeqAccess<'de> for ArgSeqAccess<'a> { + type Error = Error; + + fn next_element_seed>( + &mut self, + seed: T, + ) -> Result, Self::Error> { + match self.iter.next() { + Some(entry) => seed + .deserialize(ValueDeserializer { + value: entry.value(), + }) + .map(Some), + None => Ok(None), + } + } +} + +struct NodeListSeqAccess<'a> { + iter: std::slice::Iter<'a, KdlNode>, +} + +impl<'de, 'a> SeqAccess<'de> for NodeListSeqAccess<'a> { + type Error = Error; + + fn next_element_seed>( + &mut self, + seed: T, + ) -> Result, Self::Error> { + match self.iter.next() { + Some(node) => seed.deserialize(NodeDeserializer { node }).map(Some), + None => Ok(None), + } + } +} + +struct NodeGroupDeserializer<'a> { + nodes: &'a [&'a KdlNode], +} + +impl<'de, 'a> de::Deserializer<'de> for NodeGroupDeserializer<'a> { + type Error = Error; + + fn deserialize_any>(self, visitor: V) -> Result { + self.deserialize_seq(visitor) + } + + fn deserialize_seq>(self, visitor: V) -> Result { + visitor.visit_seq(NodeGroupSeqAccess { + iter: self.nodes.iter(), + }) + } + + serde::forward_to_deserialize_any! { + bool i8 i16 i32 i64 i128 u8 u16 u32 u64 u128 f32 f64 char str string + bytes byte_buf option unit unit_struct newtype_struct tuple + tuple_struct map struct enum identifier ignored_any + } +} + +struct NodeGroupSeqAccess<'a> { + iter: std::slice::Iter<'a, &'a KdlNode>, +} + +impl<'de, 'a> SeqAccess<'de> for NodeGroupSeqAccess<'a> { + type Error = Error; + + fn next_element_seed>( + &mut self, + seed: T, + ) -> Result, Self::Error> { + match self.iter.next() { + Some(node) => seed.deserialize(NodeDeserializer { node }).map(Some), + None => Ok(None), + } + } +} + +struct NodeMapAccess<'a> { + /// Properties and children combined as (key, value_source). + entries: Vec<(&'a str, NodeMapValue<'a>)>, + idx: usize, +} + +enum NodeMapValue<'a> { + Arg(&'a KdlValue), + SingleNode(&'a KdlNode), + MultiNode(Vec<&'a KdlNode>), +} + +impl<'a> NodeMapAccess<'a> { + fn new(node: &'a KdlNode) -> Self { + let mut entries: Vec<(&'a str, NodeMapValue<'a>)> = Vec::new(); + + // Add the first argument as "-" if there are args and also props/children + // (for mixed nodes). Otherwise arguments are not included in map mode. + let args: Vec<_> = node + .entries() + .iter() + .filter(|e| e.name().is_none()) + .collect(); + let props: Vec<_> = node + .entries() + .iter() + .filter(|e| e.name().is_some()) + .collect(); + + // If there are only args and no props/children, we shouldn't be in map mode. + // But if we are (struct requested), put args as "-" entries. + if !args.is_empty() && (props.is_empty() && node.children().is_none()) { + for arg in args.iter() { + entries.push(("-", NodeMapValue::Arg(arg.value()))); + } + } + + // Add properties + for prop in &props { + let name = prop.name().unwrap().value(); + entries.push((name, NodeMapValue::Arg(prop.value()))); + } + + // Add children (grouped by node name) + if let Some(children) = node.children() { + let mut child_keys: Vec<&str> = Vec::new(); + let mut child_groups: std::collections::HashMap<&str, Vec<&KdlNode>> = + std::collections::HashMap::new(); + for child in children.nodes() { + let name = child.name().value(); + if !child_groups.contains_key(name) { + child_keys.push(name); } - _ => { - map.next_value::()?; + child_groups.entry(name).or_default().push(child); + } + for key in child_keys { + let group = child_groups.remove(key).unwrap(); + if group.len() == 1 { + entries.push((key, NodeMapValue::SingleNode(group[0]))); + } else { + entries.push((key, NodeMapValue::MultiNode(group))); } } } + NodeMapAccess { entries, idx: 0 } + } +} + +impl<'de, 'a> MapAccess<'de> for NodeMapAccess<'a> { + type Error = Error; + + fn next_key_seed>( + &mut self, + seed: K, + ) -> Result, Self::Error> { + if self.idx >= self.entries.len() { + return Ok(None); + } + let key = self.entries[self.idx].0; + seed.deserialize(str_deserializer(key)).map(Some) + } + + fn next_value_seed>( + &mut self, + seed: V, + ) -> Result { + let (_, ref value) = self.entries[self.idx]; + self.idx += 1; + match value { + NodeMapValue::Arg(v) => seed.deserialize(ValueDeserializer { value: v }), + NodeMapValue::SingleNode(node) => seed.deserialize(NodeDeserializer { node }), + NodeMapValue::MultiNode(nodes) => seed.deserialize(NodeGroupDeserializer { nodes }), + } + } +} + +struct NodeEnumAccess<'a> { + node: &'a KdlNode, +} + +impl<'de, 'a> de::EnumAccess<'de> for NodeEnumAccess<'a> { + type Error = Error; + type Variant = NodeVariantAccess<'a>; + + fn variant_seed>( + self, + seed: V, + ) -> Result<(V::Value, Self::Variant), Self::Error> { + let variant_name = self.node.name().value(); + let val = seed.deserialize(str_deserializer(variant_name))?; + Ok((val, NodeVariantAccess { node: self.node })) + } +} + +struct NodeVariantAccess<'a> { + node: &'a KdlNode, +} + +impl<'de, 'a> de::VariantAccess<'de> for NodeVariantAccess<'a> { + type Error = Error; + + fn unit_variant(self) -> Result<(), Self::Error> { Ok(()) } + + fn newtype_variant_seed>( + self, + seed: T, + ) -> Result { + seed.deserialize(NodeDeserializer { node: self.node }) + } + + fn tuple_variant>( + self, + _len: usize, + visitor: V, + ) -> Result { + de::Deserializer::deserialize_seq(NodeDeserializer { node: self.node }, visitor) + } + + fn struct_variant>( + self, + _fields: &'static [&'static str], + visitor: V, + ) -> Result { + de::Deserializer::deserialize_map(NodeDeserializer { node: self.node }, visitor) + } } -impl<'de, 'a> de::Deserializer<'de> for &'a mut Deserializer<'de> { - type Error = DeError; +struct PropertyEnumAccess<'a> { + key: &'a str, + value: &'a KdlValue, +} - fn deserialize_any(self, visitor: V) -> Result - where - V: de::Visitor<'de>, - { - self.deserialize_map(visitor) - } +impl<'de, 'a> de::EnumAccess<'de> for PropertyEnumAccess<'a> { + type Error = Error; + type Variant = PropertyVariantAccess<'a>; - fn deserialize_bool(self, visitor: V) -> Result - where - V: de::Visitor<'de>, - { - todo!() - } - - fn deserialize_char(self, visitor: V) -> Result - where - V: de::Visitor<'de>, - { - todo!() - } - - fn deserialize_str(self, visitor: V) -> Result - where - V: de::Visitor<'de>, - { - todo!() - } - - fn deserialize_string(self, visitor: V) -> Result - where - V: de::Visitor<'de>, - { - todo!() - } - - fn deserialize_bytes(self, visitor: V) -> Result - where - V: de::Visitor<'de>, - { - todo!() - } - - fn deserialize_byte_buf(self, visitor: V) -> Result - where - V: de::Visitor<'de>, - { - todo!() - } - - fn deserialize_option(self, visitor: V) -> Result - where - V: de::Visitor<'de>, - { - todo!() - } - - fn deserialize_unit(self, visitor: V) -> Result - where - V: de::Visitor<'de>, - { - todo!() - } - - fn deserialize_unit_struct( + fn variant_seed>( self, - name: &'static str, - visitor: V, - ) -> Result - where - V: de::Visitor<'de>, - { - todo!() - } - - fn deserialize_newtype_struct( - self, - name: &'static str, - visitor: V, - ) -> Result - where - V: de::Visitor<'de>, - { - todo!() - } - - fn deserialize_seq(self, visitor: V) -> Result - where - V: de::Visitor<'de>, - { - todo!() - } - - fn deserialize_tuple(self, len: usize, visitor: V) -> Result - where - V: de::Visitor<'de>, - { - todo!() - } - - fn deserialize_tuple_struct( - self, - name: &'static str, - len: usize, - visitor: V, - ) -> Result - where - V: de::Visitor<'de>, - { - todo!() - } - - fn deserialize_map(self, visitor: V) -> Result - where - V: de::Visitor<'de>, - { - todo!() - } - - fn deserialize_struct( - self, - name: &'static str, - fields: &'static [&'static str], - visitor: V, - ) -> Result - where - V: de::Visitor<'de>, - { - todo!() - } - - fn deserialize_enum( - self, - name: &'static str, - variants: &'static [&'static str], - visitor: V, - ) -> Result - where - V: de::Visitor<'de>, - { - todo!() - } - - fn deserialize_identifier(self, visitor: V) -> Result - where - V: de::Visitor<'de>, - { - todo!() - } - - fn deserialize_ignored_any(self, visitor: V) -> Result - where - V: de::Visitor<'de>, - { - todo!() + seed: V, + ) -> Result<(V::Value, Self::Variant), Self::Error> { + let val = seed.deserialize(str_deserializer(self.key))?; + Ok((val, PropertyVariantAccess { value: self.value })) } } + +struct PropertyVariantAccess<'a> { + value: &'a KdlValue, +} + +impl<'de, 'a> de::VariantAccess<'de> for PropertyVariantAccess<'a> { + type Error = Error; + + fn unit_variant(self) -> Result<(), Self::Error> { + Ok(()) + } + + fn newtype_variant_seed>( + self, + seed: T, + ) -> Result { + seed.deserialize(ValueDeserializer { value: self.value }) + } + + fn tuple_variant>( + self, + _len: usize, + _visitor: V, + ) -> Result { + Err(de::Error::custom( + "tuple variants not supported from KDL properties", + )) + } + + fn struct_variant>( + self, + _fields: &'static [&'static str], + _visitor: V, + ) -> Result { + Err(de::Error::custom( + "struct variants not supported from KDL properties", + )) + } +} +