use crate::codes;
use crate::decoder::Decoder;
use crate::issue::{Issue, Issues};
use crate::path::Path;
use serde_json::{Map, Value};
pub fn one_of<A>(alternatives: A) -> OneOf<A> {
OneOf(alternatives)
}
#[derive(Clone, Copy, Debug)]
pub struct OneOf<A>(A);
mod sealed {
pub trait Sealed<I: ?Sized> {}
}
pub trait Alternatives<I: ?Sized>: sealed::Sealed<I> {
type Output;
#[doc(hidden)]
fn first_success(&self, input: &I, path: &Path<'_>) -> Result<Self::Output, Vec<Issues>>;
}
impl<I: ?Sized, A: Alternatives<I>> Decoder<I> for OneOf<A> {
type Output = A::Output;
fn decode_at(&self, input: &I, path: &Path<'_>) -> Result<A::Output, Issues> {
self.0.first_success(input, path).map_err(|failures| {
let candidates: Vec<Value> = failures
.iter()
.enumerate()
.map(|(i, issues)| {
let mut candidate = Map::new();
candidate.insert("candidate".into(), i.into());
candidate.insert("issues".into(), issues.to_json());
Value::Object(candidate)
})
.collect();
Issue::at_path(path, codes::ONE_OF_FAILED)
.with_meta("candidates", candidates)
.into()
})
}
}
macro_rules! alternatives {
($First:ident $first:tt $(, $T:ident $idx:tt)*) => {
impl<I: ?Sized, $First: Decoder<I>, $($T: Decoder<I, Output = $First::Output>),*>
sealed::Sealed<I> for ($First, $($T,)*)
{
}
impl<I: ?Sized, $First: Decoder<I>, $($T: Decoder<I, Output = $First::Output>),*>
Alternatives<I> for ($First, $($T,)*)
{
type Output = $First::Output;
fn first_success(
&self,
input: &I,
path: &Path<'_>,
) -> Result<Self::Output, Vec<Issues>> {
let mut failures = Vec::new();
match self.$first.decode_at(input, path) {
Ok(value) => return Ok(value),
Err(issues) => failures.push(issues),
}
$(
match self.$idx.decode_at(input, path) {
Ok(value) => return Ok(value),
Err(issues) => failures.push(issues),
}
)*
Err(failures)
}
}
};
}
alternatives!(A 0);
alternatives!(A 0, B 1);
alternatives!(A 0, B 1, C 2);
alternatives!(A 0, B 1, C 2, D 3);
alternatives!(A 0, B 1, C 2, D 3, E 4);
alternatives!(A 0, B 1, C 2, D 3, E 4, F 5);
alternatives!(A 0, B 1, C 2, D 3, E 4, F 5, G 6);
alternatives!(A 0, B 1, C 2, D 3, E 4, F 5, G 6, H 7);
alternatives!(A 0, B 1, C 2, D 3, E 4, F 5, G 6, H 7, J 8);
alternatives!(A 0, B 1, C 2, D 3, E 4, F 5, G 6, H 7, J 8, K 9);
alternatives!(A 0, B 1, C 2, D 3, E 4, F 5, G 6, H 7, J 8, K 9, L 10);
alternatives!(A 0, B 1, C 2, D 3, E 4, F 5, G 6, H 7, J 8, K 9, L 10, M 11);
alternatives!(A 0, B 1, C 2, D 3, E 4, F 5, G 6, H 7, J 8, K 9, L 10, M 11, N 12);
alternatives!(A 0, B 1, C 2, D 3, E 4, F 5, G 6, H 7, J 8, K 9, L 10, M 11, N 12, O 13);
alternatives!(A 0, B 1, C 2, D 3, E 4, F 5, G 6, H 7, J 8, K 9, L 10, M 11, N 12, O 13, P 14);
alternatives!(A 0, B 1, C 2, D 3, E 4, F 5, G 6, H 7, J 8, K 9, L 10, M 11, N 12, O 13, P 14, Q 15);