use std::fmt::{Debug, Display};
use std::convert::Infallible;
use std::borrow::Cow;
pub trait IntoProp<'d> {
fn into_prop<E: Extend<Cow<'d, str>>>(self, values: &mut E);
}
pub trait FromProp<'d>: Sized {
type Err: Display + Debug;
fn from_prop(values: &'d [Cow<'d, str>]) -> std::result::Result<Self, Self::Err>;
}
impl<'d, T> IntoProp<'d> for Vec<T>
where
T: IntoProp<'d>,
{
fn into_prop<E: Extend<Cow<'d, str>>>(self, values: &mut E) {
for val in self {
val.into_prop(values);
}
}
}
impl<'d, T, const N: usize> IntoProp<'d> for [T; N]
where
T: IntoProp<'d>,
{
fn into_prop<E: Extend<Cow<'d, str>>>(self, values: &mut E) {
for val in self {
val.into_prop(values);
}
}
}
impl<'d, T> IntoProp<'d> for &'_ [T]
where
for<'a> &'a T: IntoProp<'d>,
{
fn into_prop<E: Extend<Cow<'d, str>>>(self, values: &mut E) {
for val in self {
val.into_prop(values);
}
}
}
#[derive(thiserror::Error, Debug)]
pub enum ParsePropError<E> {
#[error("no value")]
NoValue,
#[error("too much values")]
TooMuchValues,
#[error("parse: {0}")]
Parse(#[from] E),
}
macro_rules! impl_prop_for_parse {
( $ty:ty ) => {
impl<'d> IntoProp<'d> for $ty {
#[inline]
fn into_prop<E: Extend<Cow<'d, str>>>(self, values: &mut E) {
values.extend(Some(Cow::<str>::Owned(format!("{self}"))));
}
}
impl<'d> IntoProp<'d> for &'_ $ty {
#[inline]
fn into_prop<E: Extend<Cow<'d, str>>>(self, values: &mut E) {
(*self).into_prop(values);
}
}
impl<'d> FromProp<'d> for $ty {
type Err = ParsePropError<<$ty as std::str::FromStr>::Err>;
fn from_prop(values: &[Cow<'d, str>]) -> std::result::Result<Self, Self::Err> {
match values.len() {
0 => Err(ParsePropError::NoValue),
1 => values[0].parse::<$ty>().map_err(ParsePropError::Parse),
2.. => Err(ParsePropError::NoValue),
}
}
}
impl<'d> FromProp<'d> for Vec<$ty> {
type Err = ParsePropError<<$ty as std::str::FromStr>::Err>;
fn from_prop(values: &[Cow<'d, str>]) -> std::result::Result<Self, Self::Err> {
let mut ret = Vec::with_capacity(values.len());
for val in values {
ret.push(val.parse::<$ty>().map_err(ParsePropError::Parse)?);
}
Ok(ret)
}
}
};
}
impl_prop_for_parse!(bool);
impl_prop_for_parse!(u8);
impl_prop_for_parse!(i8);
impl_prop_for_parse!(u16);
impl_prop_for_parse!(i16);
impl_prop_for_parse!(u32);
impl_prop_for_parse!(i32);
impl_prop_for_parse!(u64);
impl_prop_for_parse!(i64);
impl_prop_for_parse!(f32);
impl_prop_for_parse!(f64);
impl<'d> IntoProp<'d> for Cow<'d, str> {
fn into_prop<E: Extend<Cow<'d, str>>>(self, values: &mut E) {
values.extend(Some(self));
}
}
impl<'d> IntoProp<'d> for &'d str {
fn into_prop<E: Extend<Cow<'d, str>>>(self, values: &mut E) {
Cow::<str>::Borrowed(self).into_prop(values);
}
}
impl<'d> IntoProp<'d> for String {
fn into_prop<E: Extend<Cow<'d, str>>>(self, values: &mut E) {
Cow::<str>::Owned(self).into_prop(values);
}
}
impl<'d> IntoProp<'d> for &'d String {
fn into_prop<E: Extend<Cow<'d, str>>>(self, values: &mut E) {
Cow::<str>::Borrowed(self).into_prop(values);
}
}
impl<'d> FromProp<'d> for String {
type Err = Infallible;
fn from_prop(values: &'d [Cow<'d, str>]) -> std::result::Result<Self, Self::Err> {
let mut buf = String::new();
for val in values {
if !buf.is_empty() {
buf.push('\n');
}
buf.push_str(&*val);
}
Ok(buf)
}
}
impl<'d> FromProp<'d> for Vec<String> {
type Err = Infallible;
fn from_prop(values: &'d [Cow<'d, str>]) -> std::result::Result<Self, Self::Err> {
Ok(values.iter().map(|s| s.to_string()).collect::<Vec<_>>())
}
}
impl<'d: 'd_, 'd_> FromProp<'d> for &'d_ [Cow<'d_, str>] {
type Err = Infallible;
fn from_prop(values: &'d [Cow<'d, str>]) -> std::result::Result<Self, Self::Err> {
Ok(values)
}
}