use crate::{CharClass, Inpt, RecursionGuard};
use crate::{InptError, ResultExt};
use inpt_macros::impl_inpt_as;
use std::collections::{BTreeSet, HashSet};
use std::fmt;
use std::rc::Rc;
use std::sync::Arc;
use std::{cmp::Eq, hash::Hash, marker::PhantomData, str::FromStr};
impl<'s> Inpt<'s> for () {
fn step(
text: &'s str,
end: bool,
_trimmed: CharClass,
_guard: &mut RecursionGuard,
) -> crate::InptStep<'s, Self> {
crate::InptStep {
data: if end && !text.is_empty() {
Err(InptError::expected::<Self>(text))
} else {
Ok(())
},
rest: text,
}
}
fn default_trim(_inherited: CharClass) -> CharClass {
CharClass(&[])
}
}
impl<'s> Inpt<'s> for &'s str {
fn step(
text: &'s str,
_end: bool,
_trimmed: CharClass,
_guard: &mut RecursionGuard,
) -> crate::InptStep<'s, Self> {
crate::InptStep {
data: Ok(text),
rest: "",
}
}
}
impl<'s> Inpt<'s> for char {
fn step(
text: &'s str,
end: bool,
_trimmed: CharClass,
_guard: &mut RecursionGuard,
) -> crate::InptStep<'s, Self> {
let c = text.chars().next();
let rest = &text[c.map(|c| c.len_utf8()).unwrap_or(0)..];
crate::InptStep {
data: if end && !rest.is_empty() {
Err(InptError::expected::<char>(text))
} else {
c.ok_or(InptError::expected_at_start::<Self>())
},
rest,
}
}
}
impl<'s> Inpt<'s> for String {
fn step(
text: &'s str,
_end: bool,
_trimmed: CharClass,
_guard: &mut RecursionGuard,
) -> crate::InptStep<'s, Self> {
crate::InptStep {
data: Ok(text.to_string()),
rest: "",
}
}
}
impl<'s, T: Inpt<'s>> Inpt<'s> for crate::error::InptResult<'s, T> {
fn step(
text: &'s str,
end: bool,
trimmed: CharClass,
guard: &mut RecursionGuard,
) -> crate::InptStep<'s, Self> {
guard.check(text, |guard| {
let step = T::step(text, end, trimmed, guard);
crate::InptStep {
data: Ok(step.data),
rest: step.rest,
}
})
}
fn default_trim(inherited: CharClass) -> CharClass {
T::default_trim(inherited)
}
}
impl_inpt_as!(
impl<'s, T: Inpt<'s>> Box<T> as T => |data| Box::new(data),
impl<'s, T: Inpt<'s>> Rc<T> as T => |data| Rc::new(data),
impl<'s, T: Inpt<'s>> Arc<T> as T => |data| Arc::new(data),
);
#[derive(Inpt)]
#[inpt(regex = r"(-?\d+(?:\.\d+)?(?:e-?\d+)?)", trim = r"\s,;")]
pub struct Num<T: FromStr>
where
T::Err: fmt::Display,
{
#[inpt(from_str)]
pub inner: T,
}
impl_inpt_as!(
impl f32 as Num<f32> => |num| num.inner,
impl f64 as Num<f64> => |num| num.inner,
impl u8 as Num<u8> => |num| num.inner,
impl i8 as Num<i8> => |num| num.inner,
impl u16 as Num<u16> => |num| num.inner,
impl i16 as Num<i16> => |num| num.inner,
impl u32 as Num<u32> => |num| num.inner,
impl i32 as Num<i32> => |num| num.inner,
impl u64 as Num<u64> => |num| num.inner,
impl i64 as Num<i64> => |num| num.inner,
impl usize as Num<usize> => |num| num.inner,
impl isize as Num<isize> => |num| num.inner,
);
#[cfg(feature = "num-bigint")]
impl_inpt_as!(
impl num_bigint::BigInt as Num<num_bigint::BigInt> => |num| num.inner,
impl num_bigint::BigUint as Num<num_bigint::BigUint> => |num| num.inner,
);
#[derive(Inpt)]
pub struct Sequence<'s, I, T>
where
T: Inpt<'s>,
I: FromIterator<T>,
{
#[inpt(from_iter = "T")]
pub inner: I,
#[inpt(skip)]
item: PhantomData<&'s T>,
}
impl_inpt_as!(
impl<'s, T: Inpt<'s>> Vec<T> as Sequence<'s, Self, T> => |seq| seq.inner,
impl<'s, T: Inpt<'s> + Ord> BTreeSet<T> as Sequence<'s, Self, T> => |seq| seq.inner,
impl<'s, T: Inpt<'s> + Hash + Eq> HashSet<T> as Sequence<'s, Self, T> => |seq| seq.inner,
);
impl<'s, T: Inpt<'s>, const N: usize> Inpt<'s> for [T; N] {
fn step(
text: &'s str,
end: bool,
trimmed: CharClass,
guard: &mut RecursionGuard,
) -> crate::InptStep<'s, Self> {
guard.check(text, |guard| {
let mut data = [(); N].map(|()| Option::<T>::None);
let mut rest = text;
let trim_each = T::default_trim(trimmed);
for i in 0..N {
rest = trim_each.trim(rest, end && i + 1 == N);
let step = T::step(rest, end && i + 1 == N, trim_each, guard);
rest = step.rest;
data[i] = match step.data {
Ok(seq) => Some(seq),
Err(err) => {
return crate::InptStep {
data: Err(err).within(text).expected::<Self>(),
rest,
}
}
};
}
crate::InptStep {
data: Ok(data.map(|opt| opt.unwrap())),
rest,
}
})
}
fn default_trim(inherited: CharClass) -> CharClass {
T::default_trim(inherited)
}
}
inpt_macros::generate_inpt_impls!();