Skip to content

Commit

Permalink
feat: Introduce OwnedValueDeserialize
Browse files Browse the repository at this point in the history
  • Loading branch information
fasterthanlime committed Sep 14, 2024
1 parent 5bea4ed commit f4b128e
Show file tree
Hide file tree
Showing 4 changed files with 60 additions and 10 deletions.
17 changes: 9 additions & 8 deletions merde/examples/return-deserialize.rs
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
use merde::json::JsonSerialize;
use merde::{CowStr, IntoStatic, ValueDeserialize, WithLifetime};
use merde::{CowStr, OwnedValueDeserialize, Value};

fn deser_and_staticify<T>(s: String) -> Result<T, merde_json::MerdeJsonError<'static>>
fn deser_and_return<T>(s: String) -> Result<T, merde_json::MerdeJsonError<'static>>
where
for<'s> T: WithLifetime<'s>,
for<'s> <T as WithLifetime<'s>>::Lifetimed: ValueDeserialize<'s> + IntoStatic<Output = T>,
T: OwnedValueDeserialize,
{
let deserialized: <T as WithLifetime>::Lifetimed =
merde_json::from_str_via_value(&s).map_err(|e| e.to_static())?;
Ok(deserialized.into_static())
// here `s` is a `String`, but pretend we're making
// a network request intead — the point is is that we
// need to borrow from a local from the function body.
let value: Value = merde_json::from_str_via_value(&s).map_err(|e| e.to_static())?;
Ok(T::owned_from_value(Some(value))?)
}

fn main() {
Expand All @@ -34,7 +35,7 @@ fn main() {

assert_eq!(person, person2);

let person3 = deser_and_staticify::<Person>(serialized).unwrap();
let person3 = deser_and_return::<Person>(serialized).unwrap();
println!("{:?}", person3);

assert_eq!(person, person3);
Expand Down
33 changes: 32 additions & 1 deletion merde_core/src/deserialize.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,37 @@
use std::{borrow::Cow, hash::Hash, str::FromStr};

use crate::{Array, CowStr, Map, MerdeError, Value, ValueType};
use crate::{Array, CowStr, IntoStatic, Map, MerdeError, Value, ValueType, WithLifetime};

/// Lifetime-erased version of [`ValueDeserialize`] — if you want to declare a function
/// that returns something that is deserialized from a local, that something you return
/// needs to be owned, which is really hard to express normally — that's where `OwnedValueDeserialize`
/// comes in.
///
/// For more detail, see the `return-deserialize` example.
pub trait OwnedValueDeserialize
where
Self: Sized + 'static,
{
fn owned_from_value_ref(value: Option<&Value<'_>>) -> Result<Self, MerdeError>;
fn owned_from_value(value: Option<Value<'_>>) -> Result<Self, MerdeError>;
}

impl<T> OwnedValueDeserialize for T
where
T: 'static,
for<'s> T: WithLifetime<'s>,
for<'s> <T as WithLifetime<'s>>::Lifetimed: ValueDeserialize<'s> + IntoStatic<Output = T>,
{
fn owned_from_value_ref<'val, 's>(value: Option<&'val Value<'s>>) -> Result<Self, MerdeError> {
let t = <T as WithLifetime<'s>>::Lifetimed::from_value_ref(value)?;
Ok(t.into_static())
}

fn owned_from_value<'s>(value: Option<Value<'s>>) -> Result<Self, MerdeError> {
let t = <T as WithLifetime<'s>>::Lifetimed::from_value(value)?;
Ok(t.into_static())
}
}

/// Types that can be deserialized from a [`Value`].
///
Expand Down
1 change: 1 addition & 0 deletions merde_core/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ mod value;
pub use value::Value;

mod deserialize;
pub use deserialize::OwnedValueDeserialize;
pub use deserialize::ValueDeserialize;

/// Interpret a &[`Value`] as an instance of type `T`. This may involve
Expand Down
19 changes: 18 additions & 1 deletion merde_json/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,9 @@ mod jiter_lite;
mod parser;

use jiter_lite::errors::JiterError;
use merde_core::{Array, CowStr, IntoStatic, Map, MerdeError, Value, ValueDeserialize};
use merde_core::{
Array, CowStr, IntoStatic, Map, MerdeError, OwnedValueDeserialize, Value, ValueDeserialize,
};
use parser::json_bytes_to_value;

use std::borrow::Cow;
Expand Down Expand Up @@ -597,6 +599,21 @@ where
Ok(merde_core::from_value(value)?)
}

/// Deserialize an instance of type `T` from a string of JSON text, making
/// sure the result is owned.
pub fn owned_from_str_via_value<T>(s: &str) -> Result<T, MerdeJsonError<'_>>
where
T: OwnedValueDeserialize,
{
let value = json_bytes_to_value(s.as_bytes()).map_err(|e| MerdeJsonError::JiterError {
err: e,
source: Some(s.into()),
})?;
Ok(merde_core::OwnedValueDeserialize::owned_from_value(Some(
value,
))?)
}

/// Serialize the given data structure as a String of JSON.
pub fn to_string<T: JsonSerialize>(value: &T) -> String {
value.to_json_string()
Expand Down

0 comments on commit f4b128e

Please sign in to comment.