Skip to content

Commit

Permalink
feat: Implement Eq for values
Browse files Browse the repository at this point in the history
This allows us to support deserializing `HashMap<Value, Value>` for example.

Closes #90

Closes #61
  • Loading branch information
fasterthanlime committed Oct 6, 2024
1 parent 8884861 commit d13ba63
Show file tree
Hide file tree
Showing 8 changed files with 56 additions and 7 deletions.
10 changes: 10 additions & 0 deletions Cargo.lock

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

15 changes: 15 additions & 0 deletions merde/examples/yaml.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
use std::collections::HashMap;

use merde::Value;
use merde_core::Deserializer;
use merde_yaml::YamlDeserializer;

Expand Down Expand Up @@ -73,4 +76,16 @@ fn main() {
let result: ComplexStruct = de.deserialize().unwrap();

println!("Deserialized ComplexStruct: {result:#?}");

let yaml_map = r#"
1: 100
"two": 200.5
true: "three hundred"
[1, 2, 3]: { "nested": "value" }
"#;

let mut de = YamlDeserializer::new(yaml_map);
let result: HashMap<Value, Value> = de.deserialize().unwrap();

println!("Deserialized HashMap: {result:#?}");
}
1 change: 1 addition & 0 deletions merde_core/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ categories = ["encoding", "parser-implementations"]

[dependencies]
compact_str = { version = "0.8.0", optional = true }
ordered-float = "4.3.0"
rubicon = "3.4.9"
rusqlite = { version = "0.32.1", optional = true }
serde = { version = "1", optional = true }
Expand Down
2 changes: 1 addition & 1 deletion merde_core/src/array.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use std::ops::{Deref, DerefMut};
use crate::{value::Value, IntoStatic};

/// An array of [`Value`] items
#[derive(PartialEq, Clone)]
#[derive(PartialEq, Eq, Hash, Clone)]
#[repr(transparent)]
pub struct Array<'s>(pub Vec<Value<'s>>);

Expand Down
2 changes: 1 addition & 1 deletion merde_core/src/deserialize.rs
Original file line number Diff line number Diff line change
Expand Up @@ -562,7 +562,7 @@ impl<'s> Deserialize<'s> for Value<'s> {
{
match de.next()? {
Event::Int(i) => Ok(Value::Int(i)),
Event::Float(f) => Ok(Value::Float(f)),
Event::Float(f) => Ok(Value::Float(f.into())),
Event::Str(s) => Ok(Value::Str(s)),
Event::Bool(b) => Ok(Value::Bool(b)),
Event::Null => Ok(Value::Null),
Expand Down
12 changes: 11 additions & 1 deletion merde_core/src/map.rs
Original file line number Diff line number Diff line change
@@ -1,15 +1,25 @@
use std::{
collections::HashMap,
hash::{Hash, Hasher},
ops::{Deref, DerefMut},
};

use crate::{value::Value, CowStr, IntoStatic};

/// A map, dictionary, object, whatever — with string keys.
#[derive(PartialEq, Clone)]
#[derive(PartialEq, Eq, Clone)]
#[repr(transparent)]
pub struct Map<'s>(pub HashMap<CowStr<'s>, Value<'s>>);

impl Hash for Map<'_> {
fn hash<H: Hasher>(&self, state: &mut H) {
for (k, v) in self.iter() {
k.hash(state);
v.hash(state);
}
}
}

impl std::fmt::Debug for Map<'_> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
self.0.fmt(f)
Expand Down
19 changes: 16 additions & 3 deletions merde_core/src/value.rs
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
use std::{borrow::Cow, collections::HashMap};

use ordered_float::OrderedFloat;

use crate::{array::Array, map::Map, CowStr, IntoStatic, MerdeError, ValueType};

/// Think [`serde_json::Value`](https://docs.rs/serde_json/1.0.128/serde_json/enum.Value.html), but with a small string optimization,
/// copy-on-write strings, etc. Might include other value types later.
#[derive(Debug, PartialEq, Clone)]
#[derive(Debug, PartialEq, Eq, Hash, Clone)]
pub enum Value<'s> {
Int(i64),
Float(f64),
Float(OrderedFloat<f64>),
Str(CowStr<'s>),
Bytes(Cow<'s, [u8]>),
Null,
Expand Down Expand Up @@ -42,7 +44,7 @@ impl<'s> From<i64> for Value<'s> {

impl<'s> From<f64> for Value<'s> {
fn from(v: f64) -> Self {
Value::Float(v)
Value::Float(v.into())
}
}

Expand Down Expand Up @@ -183,4 +185,15 @@ impl<'s> Value<'s> {
}),
}
}

#[inline(always)]
pub fn as_f64(&self) -> Result<f64, MerdeError<'static>> {
match self {
Value::Float(n) => Ok(n.into_inner()),
_ => Err(MerdeError::MismatchedType {
expected: ValueType::Float,
found: self.value_type(),
}),
}
}
}
2 changes: 1 addition & 1 deletion merde_json/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -206,7 +206,7 @@ impl JsonSerialize for Value<'_> {
Value::Null => serializer.write_null(),
Value::Bool(b) => serializer.write_bool(*b),
Value::Int(i) => serializer.write_i64(*i),
Value::Float(f) => serializer.write_f64(*f),
Value::Float(f) => serializer.write_f64(f.into_inner()),
Value::Str(s) => serializer.write_str(s),
Value::Bytes(_b) => {
// TODO: we're going to need to make json_serialize return
Expand Down

0 comments on commit d13ba63

Please sign in to comment.