use deserr::errors::{JsonError, QueryParamError};
use deserr::{
deserialize, take_cf_content, DeserializeError, Deserr, ErrorKind, Sequence, Value, ValueKind,
};
use serde_json::json;
#[allow(dead_code)]
#[derive(Debug, Deserr)]
#[deserr(deny_unknown_fields)]
struct Query {
name: String,
filter: Filter,
}
#[allow(dead_code)]
#[derive(Debug)]
enum Filter {
Array(Vec<Filter>),
Direct(String),
}
impl<E: DeserializeError> Deserr<E> for Filter {
fn deserialize_from_value<V: deserr::IntoValue>(
value: deserr::Value<V>,
location: deserr::ValuePointerRef,
) -> Result<Self, E> {
match value {
Value::String(s) => Ok(Filter::Direct(s)),
Value::Sequence(seq) => Ok(Filter::Array(
seq.into_iter()
.enumerate()
.map(|(index, value)| {
Self::deserialize_from_value(value.into_value(), location.push_index(index))
})
.collect::<Result<Vec<Self>, E>>()?,
)),
value => {
Err(take_cf_content(E::error(
None,
ErrorKind::IncorrectValueKind {
actual: value,
accepted: &[ValueKind::String, ValueKind::Sequence],
},
location,
)))
}
}
}
}
fn main() {
let filter = deserialize::<Filter, serde_json::Value, JsonError>(json!("jorts")).unwrap();
insta::assert_debug_snapshot!(filter, @r###"
Direct(
"jorts",
)
"###);
let filter = deserialize::<Filter, _, JsonError>(json!([
"jorts",
"the",
["most", ["famous", "catto"], "in", "the"],
"world"
]))
.unwrap();
insta::assert_debug_snapshot!(filter, @r###"
Array(
[
Direct(
"jorts",
),
Direct(
"the",
),
Array(
[
Direct(
"most",
),
Array(
[
Direct(
"famous",
),
Direct(
"catto",
),
],
),
Direct(
"in",
),
Direct(
"the",
),
],
),
Direct(
"world",
),
],
)
"###);
let error = deserialize::<Filter, _, JsonError>(json!(["jorts", "is", ["a", 10]])).unwrap_err();
insta::assert_snapshot!(error, @"Invalid value type at `[2][1]`: expected a string or an array, but found a positive integer: `10`");
let error =
deserialize::<Filter, _, QueryParamError>(json!(["jorts", "is", "a", 10])).unwrap_err();
insta::assert_snapshot!(error, @"Invalid value type for parameter `[3]`: expected a string, but found an integer: `10`");
let filter =
deserialize::<Query, _, JsonError>(json!({ "name": "jorts", "filter": "catto" })).unwrap();
insta::assert_debug_snapshot!(filter, @r###"
Query {
name: "jorts",
filter: Direct(
"catto",
),
}
"###);
}