Skip to content

Commit

Permalink
feat(edit): Spanned serialization support
Browse files Browse the repository at this point in the history
Fixes #302
  • Loading branch information
epage committed Jan 13, 2023
1 parent b811b3a commit e30d415
Show file tree
Hide file tree
Showing 16 changed files with 675 additions and 32 deletions.
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 0 additions & 3 deletions crates/serde_spanned/src/spanned.rs
Original file line number Diff line number Diff line change
Expand Up @@ -123,19 +123,16 @@ where
if visitor.next_key()? != Some(START_FIELD) {
return Err(serde::de::Error::custom("spanned start key not found"));
}

let start: usize = visitor.next_value()?;

if visitor.next_key()? != Some(END_FIELD) {
return Err(serde::de::Error::custom("spanned end key not found"));
}

let end: usize = visitor.next_value()?;

if visitor.next_key()? != Some(VALUE_FIELD) {
return Err(serde::de::Error::custom("spanned value key not found"));
}

let value: T = visitor.next_value()?;

Ok(Spanned {
Expand Down
3 changes: 2 additions & 1 deletion crates/toml_edit/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ pre-release-replacements = [
default = []
easy = ["serde"]
perf = ["dep:kstring"]
serde = ["dep:serde", "toml_datetime/serde"]
serde = ["dep:serde", "toml_datetime/serde", "serde_spanned"]
# Provide a method disable_recursion_limit to parse arbitrarily deep structures
# without any consideration for overflowing the stack. Additionally you will
# need to be careful around other recursive operations on the parsed result
Expand All @@ -53,6 +53,7 @@ itertools = "0.10.5"
serde = { version = "1.0.145", features = ["derive"], optional = true }
kstring = { version = "2.0.0", features = ["max_inline"], optional = true }
toml_datetime = { version = "0.5.0", path = "../toml_datetime" }
serde_spanned = { version = "0.5.0", path = "../serde_spanned", features = ["serde"], optional = true }

[dev-dependencies]
serde_json = "1.0.91"
Expand Down
73 changes: 68 additions & 5 deletions crates/toml_edit/src/de/array.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,12 @@ use crate::de::Error;

pub(crate) struct ArrayDeserializer {
input: Vec<crate::Item>,
span: Option<std::ops::Range<usize>>,
}

impl ArrayDeserializer {
pub(crate) fn new(input: Vec<crate::Item>) -> Self {
Self { input }
pub(crate) fn new(input: Vec<crate::Item>, span: Option<std::ops::Range<usize>>) -> Self {
Self { input, span }
}
}

Expand All @@ -20,10 +21,36 @@ impl<'de> serde::Deserializer<'de> for ArrayDeserializer {
visitor.visit_seq(ArraySeqAccess::new(self.input))
}

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 super::is_spanned(name, fields) {
if let Some(span) = self.span.clone() {
return visitor.visit_map(super::SpannedDeserializer::new(self, span));
}
}

self.deserialize_any(visitor)
}

serde::forward_to_deserialize_any! {
bool u8 u16 u32 u64 i8 i16 i32 i64 f32 f64 char str string seq
bytes byte_buf map option unit newtype_struct
ignored_any unit_struct tuple_struct tuple enum identifier struct
ignored_any unit_struct tuple_struct tuple enum identifier
}
}

impl<'de> serde::de::IntoDeserializer<'de, crate::de::Error> for ArrayDeserializer {
type Deserializer = Self;

fn into_deserializer(self) -> Self {
self
}
}

Expand All @@ -37,10 +64,28 @@ impl<'de> serde::Deserializer<'de> for crate::Array {
visitor.visit_seq(ArraySeqAccess::with_array(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 super::is_spanned(name, fields) {
if let Some(span) = self.span() {
return visitor.visit_map(super::SpannedDeserializer::new(self, span));
}
}

self.deserialize_any(visitor)
}

serde::forward_to_deserialize_any! {
bool u8 u16 u32 u64 i8 i16 i32 i64 f32 f64 char str string seq
bytes byte_buf map option unit newtype_struct
ignored_any unit_struct tuple_struct tuple enum identifier struct
ignored_any unit_struct tuple_struct tuple enum identifier
}
}

Expand All @@ -62,10 +107,28 @@ impl<'de> serde::Deserializer<'de> for crate::ArrayOfTables {
visitor.visit_seq(ArraySeqAccess::with_array_of_tables(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 super::is_spanned(name, fields) {
if let Some(span) = self.span() {
return visitor.visit_map(super::SpannedDeserializer::new(self, span));
}
}

self.deserialize_any(visitor)
}

serde::forward_to_deserialize_any! {
bool u8 u16 u32 u64 i8 i16 i32 i64 f32 f64 char str string seq
bytes byte_buf map option unit newtype_struct
ignored_any unit_struct tuple_struct tuple enum identifier struct
ignored_any unit_struct tuple_struct tuple enum identifier
}
}

Expand Down
25 changes: 16 additions & 9 deletions crates/toml_edit/src/de/inline_table.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,13 +34,19 @@ impl<'de> serde::Deserializer<'de> for crate::InlineTable {

fn deserialize_struct<V>(
self,
_name: &'static str,
_fields: &'static [&'static str],
name: &'static str,
fields: &'static [&'static str],
visitor: V,
) -> Result<V::Value, Error>
where
V: serde::de::Visitor<'de>,
{
if super::is_spanned(name, fields) {
if let Some(span) = self.span() {
return visitor.visit_map(super::SpannedDeserializer::new(self, span));
}
}

self.deserialize_any(visitor)
}

Expand Down Expand Up @@ -87,7 +93,7 @@ impl<'de> serde::de::IntoDeserializer<'de, crate::de::Error> for crate::InlineTa
pub(crate) struct InlineTableMapAccess {
iter: indexmap::map::IntoIter<crate::InternalString, crate::table::TableKeyValue>,
span: Option<std::ops::Range<usize>>,
value: Option<(crate::InternalString, crate::Item)>,
value: Option<crate::Item>,
}

impl InlineTableMapAccess {
Expand All @@ -110,15 +116,16 @@ impl<'de> serde::de::MapAccess<'de> for InlineTableMapAccess {
{
match self.iter.next() {
Some((k, v)) => {
let ret = seed.deserialize(k.into_deserializer()).map(Some).map_err(
|mut e: Self::Error| {
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((k, v.value));
});
self.value = Some(v.value);
ret
}
None => Ok(None),
Expand All @@ -130,7 +137,7 @@ impl<'de> serde::de::MapAccess<'de> for InlineTableMapAccess {
V: serde::de::DeserializeSeed<'de>,
{
match self.value.take() {
Some((_k, v)) => {
Some(v) => {
let span = v.span();
seed.deserialize(crate::de::ItemDeserializer::new(v))
.map_err(|mut err| {
Expand Down
34 changes: 33 additions & 1 deletion crates/toml_edit/src/de/item.rs
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,12 @@ impl<'de> serde::Deserializer<'de> for ItemDeserializer {
where
V: serde::de::Visitor<'de>,
{
if super::is_spanned(name, fields) {
if let Some(span) = self.input.span() {
return visitor.visit_map(super::SpannedDeserializer::new(self.input, span));
}
}

if self.validate_struct_keys {
match &self.input {
crate::Item::Table(values) => super::validate_struct_keys(&values.items, fields)?,
Expand Down Expand Up @@ -99,6 +105,14 @@ impl<'de> serde::Deserializer<'de> for ItemDeserializer {
}
}

impl<'de> serde::de::IntoDeserializer<'de, crate::de::Error> for ItemDeserializer {
type Deserializer = Self;

fn into_deserializer(self) -> Self {
self
}
}

impl<'de> serde::Deserializer<'de> for crate::Item {
type Error = Error;

Expand Down Expand Up @@ -168,6 +182,24 @@ impl<'de> serde::Deserializer<'de> for crate::Item {
})
}

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 super::is_spanned(name, fields) {
if let Some(span) = self.span() {
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,
Expand Down Expand Up @@ -217,7 +249,7 @@ impl<'de> serde::Deserializer<'de> for crate::Item {

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 struct
bytes byte_buf map unit
ignored_any unit_struct tuple_struct tuple identifier
}
}
Expand Down
Loading

0 comments on commit e30d415

Please sign in to comment.