Skip to content

Commit

Permalink
Add helper to deserialize into Option or Result
Browse files Browse the repository at this point in the history
  • Loading branch information
romac committed May 15, 2024
1 parent 40cbf6a commit 7293402
Show file tree
Hide file tree
Showing 3 changed files with 136 additions and 4 deletions.
4 changes: 2 additions & 2 deletions src/de.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,12 @@ mod error;
pub use error::Error;

mod helpers;
pub use helpers::{As, Integer, Same};
pub use helpers::{As, Integer, Option, Result, Same};

mod deserializer;

#[doc(hidden)]
pub fn decode_value<T>(value: Value) -> Result<T, Error>
pub fn decode_value<T>(value: Value) -> std::result::Result<T, Error>
where
T: DeserializeOwned,
{
Expand Down
64 changes: 64 additions & 0 deletions src/de/helpers.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use num_bigint::BigInt;
use serde::{Deserialize, Serialize};

pub use serde_with::{As, Same};

Expand Down Expand Up @@ -71,3 +72,66 @@ pub use serde_with::{As, Same};
/// itf::from_value::<Vec<FooBarMixInt>>(json.clone()).unwrap();
/// ```
pub type Integer = serde_with::TryFromInto<BigInt>;

/// Helper for `serde` to deserialize types isomorphic to [`std::option::Option`].
///
/// To be used in conjunction with [`As`].
pub type Option<T> = serde_with::FromInto<QuintOption<T>>;

#[derive(
Copy, Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize,
)]
#[serde(tag = "tag", content = "value")]
pub enum QuintOption<T> {
#[default]
None,
Some(T),
}

impl<T> From<std::option::Option<T>> for QuintOption<T> {
fn from(opt: std::option::Option<T>) -> Self {
match opt {
Some(value) => QuintOption::Some(value),
None => QuintOption::None,
}
}
}

impl<T> From<QuintOption<T>> for std::option::Option<T> {
fn from(opt: QuintOption<T>) -> Self {
match opt {
QuintOption::Some(value) => Some(value),
QuintOption::None => None,
}
}
}

/// Helper for `serde` to deserialize types isomorphic to [`std::result::Result`].
///
/// To be used in conjunction with [`As`].
pub type Result<T, E> = serde_with::FromInto<QuintResult<T, E>>;

#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
#[serde(tag = "tag", content = "value")]
pub enum QuintResult<T, E> {
Ok(T),
Err(E),
}

impl<T, E> From<std::result::Result<T, E>> for QuintResult<T, E> {
fn from(opt: std::result::Result<T, E>) -> Self {
match opt {
Ok(value) => QuintResult::Ok(value),
Err(e) => QuintResult::Err(e),
}
}
}

impl<T, E> From<QuintResult<T, E>> for std::result::Result<T, E> {
fn from(opt: QuintResult<T, E>) -> Self {
match opt {
QuintResult::Ok(value) => Ok(value),
QuintResult::Err(e) => Err(e),
}
}
}
72 changes: 70 additions & 2 deletions tests/sum_types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ fn parse_trace() {
}

#[test]
fn test_deserialize_some() {
fn test_deserialize_adhoc_some() {
let some_itf = json!({
"tag": "Some",
"value": {"#bigint": "1"},
Expand All @@ -39,7 +39,7 @@ fn test_deserialize_some() {
}

#[test]
fn test_deserialize_none() {
fn test_deserialize_adhoc_none() {
let none_itf = json!({
"tag": "None",
"value": {},
Expand Down Expand Up @@ -93,3 +93,71 @@ fn test_deserialize_enum() {
let foobar = itf::from_value::<Enum>(foobar_itf).unwrap();
assert_eq!(foobar, Enum::FooBar("hello".to_string(), 42.into(), true));
}

#[derive(Debug, PartialEq, Deserialize)]
struct FooOption {
#[serde(with = "As::<itf::de::Option::<_>>")]
foo: Option<u64>,
}

#[test]
#[allow(clippy::disallowed_names)]
fn test_deserialize_option_some() {
let some_itf = json!({
"foo": {
"tag": "Some",
"value": 42,
}
});

let some_foo = itf::from_value::<FooOption>(some_itf).unwrap();
assert_eq!(some_foo, FooOption { foo: Some(42) });
}

#[test]
#[allow(clippy::disallowed_names)]
fn test_deserialize_option_none() {
let none_itf = json!({
"foo": {
"tag": "None",
"value": {},
}
});

let none_foo = itf::from_value::<FooOption>(none_itf).unwrap();
assert_eq!(none_foo, FooOption { foo: None });
}

#[derive(Debug, PartialEq, Deserialize)]
struct FooResult {
#[serde(with = "As::<itf::de::Result::<_, _>>")]
foo: Result<u64, u64>,
}

#[test]
#[allow(clippy::disallowed_names)]
fn test_deserialize_result_ok() {
let ok_itf = json!({
"foo": {
"tag": "Ok",
"value": 42,
}
});

let ok = itf::from_value::<FooResult>(ok_itf).unwrap();
assert_eq!(ok.foo, Ok(42));
}

#[test]
#[allow(clippy::disallowed_names)]
fn test_deserialize_result_err() {
let err_itf = json!({
"foo": {
"tag": "Err",
"value": 42,
}
});

let err = itf::from_value::<FooResult>(err_itf).unwrap();
assert_eq!(err.foo, Err(42));
}

0 comments on commit 7293402

Please sign in to comment.