#[ allow( clippy ::std_instead_of_alloc, clippy ::std_instead_of_core ) ]
mod private
{
use std ::fmt ::
{
Display,
Formatter
};
use iter_tools ::Itertools;
#[ derive( Debug, Clone, PartialEq, Eq ) ]
pub enum Type
{
String,
Number,
Path,
Bool,
List( Box< Type >, char ),
}
pub trait TryCast< T >
{
fn try_cast( &self, value: String ) -> error_tools ::untyped ::Result< T >;
}
#[ derive( Debug, Clone, PartialEq ) ]
pub enum Value
{
String( String ),
Number( f64 ),
Path( std ::path ::PathBuf ),
Bool( bool ),
List( Vec< Value > ),
}
impl Display for Value
{
fn fmt( &self, f: &mut Formatter< '_ > ) -> std ::fmt ::Result
{
match self
{
Value ::String( s ) =>
{
write!( f , "{s}" )?;
}
Value ::Number( n ) =>
{
write!( f, "{n}" )?;
}
Value ::Path( p ) =>
{
write!( f, "{}", p.display() )?;
}
Value ::Bool( b ) =>
{
write!( f, "{b}" )?;
}
Value ::List( list ) =>
{
let list = list.iter().map( std ::string ::ToString ::to_string ).join( "," );
write!( f, "{list}" )?;
}
}
Ok( () )
}
}
macro_rules! value_into_impl
{
( $( $value_kind: path => $( $kind: ty => $cast: expr ), + ); + ) =>
{
$( $(
impl From< Value > for $kind
{
fn from( value: Value ) -> Self
{
match value
{
#[ allow( clippy ::redundant_closure_call, clippy ::cast_possible_truncation, clippy ::cast_sign_loss ) ] $value_kind( value ) => ( $cast )( value ),
_ => panic!( "Unknown cast variant. Got `{value:?}` and try to cast to `{}`", stringify!( $kind ) )
}
}
}
)+ )+
};
}
value_into_impl!
{
Value ::Number =>
u32 => | value | value as u32,
u64 => | value | value as u64,
i32 => | value | value as i32,
i64 => | value | value as i64,
f32 => | value | value as f32,
f64 => | value | value;
Value ::Bool =>
bool => | value | value;
Value ::String =>
String => String ::from,
&'static str => | value: String | Box ::leak( value.into_boxed_str() );
Value ::Path =>
std ::path ::PathBuf => | value | value
}
impl< T: From< Value > > From< Value > for Vec< T >
{
fn from( value: Value ) -> Self
{
match value
{
Value ::List( value ) => value.into_iter().map( std ::convert ::Into ::into ).collect(),
_ => panic!( "Unknown cast variant. Got `{value:?}` and try to cast to `Vec< {} >`", core ::any ::type_name :: < T >() )
}
}
}
impl TryCast< Value > for Type
{
fn try_cast( &self, value: String ) -> error_tools ::error ::untyped ::Result< Value >
{
match self
{
Self ::String => Ok( Value ::String( value ) ),
Self ::Number => value.parse().map_err( | _ |
{
error_tools ::untyped ::format_err!( "Can not parse number from `{value}`" )
}).map( Value ::Number ),
Self ::Path => Ok( Value ::Path( value.into() ) ),
Self ::Bool => Ok( Value ::Bool( match value.as_str()
{
"1" | "true" => true, "0" | "false" => false, _ =>
{
return Err( error_tools ::untyped ::format_err!( "Can not parse bool from `{value}`" ) )
}
})),
Self ::List( kind, delimeter ) =>
{
let values: error_tools ::error ::untyped ::Result< Vec< Value > > = value
.split( *delimeter )
.map( | val | kind.try_cast( val.into() ) )
.collect();
let values = values?;
Ok( Value ::List( values ) )
},
}
}
}
}
crate ::mod_interface!
{
exposed use Type;
exposed use Value;
exposed use TryCast;
}