Skip to content

Commit

Permalink
Fix Value::map_metadata_recursively
Browse files Browse the repository at this point in the history
Fixes #3
  • Loading branch information
timothee-haudebourg committed Oct 19, 2023
1 parent 5ba4dc6 commit ec4bd7e
Show file tree
Hide file tree
Showing 3 changed files with 131 additions and 44 deletions.
5 changes: 4 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ serde_json = [ "dep:serde_json", "json-number/serde_json" ]
json-number = { version = "0.4.6", features = [ "smallnumberbuf" ] }
smallvec = "1.9"
smallstr = "0.3"
locspan = "0.7.3"
locspan = "0.8.2"
locspan-derive = "0.6"
indexmap = "1.9.1"
decoded-char = "0.1"
Expand All @@ -38,6 +38,9 @@ serde_json = { version = "1.0", optional = true }
[dev-dependencies]
serde = { version = "1.0", features = [ "derive" ] }

[patch.crates-io]
locspan = { path = "/home/work/Documents/Community/parsing/locspan" }

[[example]]
name = "serde"
required-features = ["serde"]
Expand Down
100 changes: 73 additions & 27 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -443,26 +443,37 @@ impl<M> Value<M> {
}

/// Recursively maps the metadata inside the value.
pub fn map_metadata<N>(self, mut f: impl FnMut(M) -> N) -> Value<N> {
fn map_metadata_mut_ref<N, F>(self, f: &mut F) -> Value<N>
where
F: FnMut(M) -> N,
{
match self {
Self::Null => Value::Null,
Self::Boolean(b) => Value::Boolean(b),
Self::Number(n) => Value::Number(n),
Self::String(s) => Value::String(s),
Self::Array(a) => Value::Array(
a.into_iter()
.map(|Meta(item, meta)| Meta(item.map_metadata(&mut f), f(meta)))
.map(|Meta(item, meta)| Meta(item.map_metadata_mut_ref::<N, F>(f), f(meta)))
.collect(),
),
Self::Object(o) => Value::Object(o.map_metadata(f)),
Self::Object(o) => Value::Object(o.map_metadata_mut_ref::<N, F>(f)),
}
}

/// Recursively maps the metadata inside the value.
pub fn map_metadata<N, F>(self, mut f: F) -> Value<N>
where
F: FnMut(M) -> N,
{
self.map_metadata_mut_ref(&mut f)
}

/// Tries to recursively maps the metadata inside the value.
pub fn try_map_metadata<N, E>(
self,
mut f: impl FnMut(M) -> Result<N, E>,
) -> Result<Value<N>, E> {
fn try_map_metadata_mut_ref<N, E, F>(self, f: &mut F) -> Result<Value<N>, E>
where
F: FnMut(M) -> Result<N, E>,
{
match self {
Self::Null => Ok(Value::Null),
Self::Boolean(b) => Ok(Value::Boolean(b)),
Expand All @@ -471,14 +482,23 @@ impl<M> Value<M> {
Self::Array(a) => {
let mut items = Vec::with_capacity(a.len());
for item in a {
items.push(item.try_map_metadata_recursively(&mut f)?)
use locspan::TryMapMetadataRecursively;
items.push(item.try_map_metadata_recursively_mut_ref::<F>(&mut *f)?)
}
Ok(Value::Array(items))
}
Self::Object(o) => Ok(Value::Object(o.try_map_metadata(f)?)),
Self::Object(o) => Ok(Value::Object(o.try_map_metadata_mut_ref::<N, E, F>(f)?)),
}
}

/// Tries to recursively maps the metadata inside the value.
pub fn try_map_metadata<N, E, F>(self, mut f: F) -> Result<Value<N>, E>
where
F: FnMut(M) -> Result<N, E>,
{
self.try_map_metadata_mut_ref::<N, E, F>(&mut f)
}

/// Move and return the value, leaves `null` in its place.
#[inline(always)]
pub fn take(&mut self) -> Self {
Expand Down Expand Up @@ -563,19 +583,22 @@ impl<'a, M: 'a> Traversal<'a> for Meta<Value<M>, M> {
impl<M, N> locspan::MapMetadataRecursively<M, N> for Value<M> {
type Output = Value<N>;

fn map_metadata_recursively<F: FnMut(M) -> N>(self, f: F) -> Value<N> {
self.map_metadata(f)
fn map_metadata_recursively_mut_ref<F>(self, f: &mut F) -> Value<N>
where
F: FnMut(M) -> N,
{
self.map_metadata_mut_ref::<N, F>(f)
}
}

impl<M, N, E> locspan::TryMapMetadataRecursively<M, N, E> for Value<M> {
type Output = Value<N>;

fn try_map_metadata_recursively<F: FnMut(M) -> Result<N, E>>(
self,
f: F,
) -> Result<Value<N>, E> {
self.try_map_metadata(f)
fn try_map_metadata_recursively_mut_ref<F>(self, f: &mut F) -> Result<Value<N>, E>
where
F: FnMut(M) -> Result<N, E>,
{
self.try_map_metadata_mut_ref::<N, E, F>(f)
}
}

Expand Down Expand Up @@ -711,11 +734,7 @@ impl<'a, M> StrippedFragmentRef<'a, M> {

impl<'a, M> Clone for StrippedFragmentRef<'a, M> {
fn clone(&self) -> Self {
match self {
Self::Value(v) => Self::Value(*v),
Self::Entry(e) => Self::Entry(e),
Self::Key(k) => Self::Key(k),
}
*self
}
}

Expand Down Expand Up @@ -790,11 +809,7 @@ impl<'a, M> locspan::Strip for FragmentRef<'a, M> {

impl<'a, M> Clone for FragmentRef<'a, M> {
fn clone(&self) -> Self {
match self {
Self::Value(v) => Self::Value(*v),
Self::Entry(e) => Self::Entry(e),
Self::Key(k) => Self::Key(*k),
}
*self
}
}

Expand Down Expand Up @@ -874,10 +889,40 @@ impl<'a, M> Iterator for Traverse<'a, M> {
}

#[cfg(test)]
#[cfg(feature = "canonicalize")]
mod tests {
use super::*;

#[test]
fn map_recursively() {
let value: Meta<Value<()>, ()> = json!({
"b": 0.00000000001,
"c": {
"foo": true,
"bar": false
},
"a": [ "foo", "bar" ]
});

value.map_metadata_recursively(|_| ());
}

#[test]
fn try_map_recursively() {
let value: Meta<Value<()>, ()> = json!({
"b": 0.00000000001,
"c": {
"foo": true,
"bar": false
},
"a": [ "foo", "bar" ]
});

value
.try_map_metadata_recursively::<_, std::convert::Infallible, _>(|_| Ok(()))
.unwrap();
}

#[cfg(feature = "canonicalize")]
#[test]
fn canonicalize_01() {
let mut value: Meta<Value<()>, ()> = json!({
Expand All @@ -897,6 +942,7 @@ mod tests {
)
}

#[cfg(feature = "canonicalize")]
#[test]
fn canonicalize_02() {
let mut value = Value::parse_str(
Expand Down
70 changes: 54 additions & 16 deletions src/object.rs
Original file line number Diff line number Diff line change
Expand Up @@ -94,23 +94,42 @@ impl<M> Entry<M> {
self.value.into_metadata()
}

pub fn map_metadata<N>(self, mut f: impl FnMut(M) -> N) -> Entry<N> {
pub(crate) fn map_metadata_mut_ref<N, F>(self, f: &mut F) -> Entry<N>
where
F: FnMut(M) -> N,
{
use locspan::MapMetadataRecursively;
Entry {
key: self.key.map_metadata(&mut f),
value: self.value.map_metadata_recursively(f),
key: self.key.map_metadata(&mut *f),
value: self.value.map_metadata_recursively_mut_ref(f),
}
}

pub fn try_map_metadata<N, E>(
self,
mut f: impl FnMut(M) -> Result<N, E>,
) -> Result<Entry<N>, E> {
pub fn map_metadata<N, F>(self, mut f: F) -> Entry<N>
where
F: FnMut(M) -> N,
{
self.map_metadata_mut_ref::<N, F>(&mut f)
}

pub(crate) fn try_map_metadata_mut_ref<N, E, F>(self, f: &mut F) -> Result<Entry<N>, E>
where
F: FnMut(M) -> Result<N, E>,
{
use locspan::TryMapMetadataRecursively;
Ok(Entry {
key: self.key.try_map_metadata(&mut f)?,
value: self.value.try_map_metadata_recursively(f)?,
key: self.key.try_map_metadata(&mut *f)?,
value: self.value.try_map_metadata_recursively_mut_ref::<F>(f)?,
})
}

pub fn try_map_metadata<N, E, F>(self, mut f: F) -> Result<Entry<N>, E>
where
F: FnMut(M) -> Result<N, E>,
{
self.try_map_metadata_mut_ref(&mut f)
}

pub fn as_pair(&self) -> (&Meta<Key, M>, &MetaValue<M>) {
(&self.key, &self.value)
}
Expand Down Expand Up @@ -467,11 +486,14 @@ impl<M> Object<M> {
}

/// Recursively maps the metadata inside the object.
pub fn map_metadata<N>(self, mut f: impl FnMut(M) -> N) -> Object<N> {
pub(crate) fn map_metadata_mut_ref<N, F>(self, f: &mut F) -> Object<N>
where
F: FnMut(M) -> N,
{
let entries = self
.entries
.into_iter()
.map(|entry| entry.map_metadata(&mut f))
.map(|entry| entry.map_metadata_mut_ref::<N, F>(f))
.collect();

Object {
Expand All @@ -480,14 +502,22 @@ impl<M> Object<M> {
}
}

/// Recursively maps the metadata inside the object.
pub fn map_metadata<N, F>(self, mut f: F) -> Object<N>
where
F: FnMut(M) -> N,
{
self.map_metadata_mut_ref::<N, F>(&mut f)
}

/// Tries to recursively maps the metadata inside the object.
pub fn try_map_metadata<N, E>(
self,
mut f: impl FnMut(M) -> Result<N, E>,
) -> Result<Object<N>, E> {
pub(crate) fn try_map_metadata_mut_ref<N, E, F>(self, f: &mut F) -> Result<Object<N>, E>
where
F: FnMut(M) -> Result<N, E>,
{
let mut entries = Vec::with_capacity(self.len());
for entry in self.entries {
entries.push(entry.try_map_metadata(&mut f)?)
entries.push(entry.try_map_metadata_mut_ref::<N, E, F>(&mut *f)?)
}

Ok(Object {
Expand All @@ -496,6 +526,14 @@ impl<M> Object<M> {
})
}

/// Tries to recursively maps the metadata inside the object.
pub fn try_map_metadata<N, E, F>(self, mut f: F) -> Result<Object<N>, E>
where
F: FnMut(M) -> Result<N, E>,
{
self.try_map_metadata_mut_ref(&mut f)
}

/// Sort the entries by key name.
///
/// Entries with the same key are sorted by value.
Expand Down

0 comments on commit ec4bd7e

Please sign in to comment.