#[doc(hidden)]
#[macro_export]
macro_rules! impl_token_value {
($($ty:ty),+ $(,)?) => {$(
impl ::std::convert::From<$ty> for $crate::sdf::Value {
fn from(value: $ty) -> Self {
$crate::sdf::Value::Token($crate::tf::Token::new(value.as_token()))
}
}
impl ::std::convert::TryFrom<$crate::sdf::Value> for $ty {
type Error = $crate::sdf::CastError;
fn try_from(
value: $crate::sdf::Value,
) -> ::std::result::Result<Self, $crate::sdf::CastError> {
match &value {
$crate::sdf::Value::Token(token) => <$ty>::from_token(token.as_str()),
_ => ::std::option::Option::None,
}
.ok_or_else(|| $crate::sdf::CastError::TypeMismatch {
target: ::std::stringify!($ty),
actual: ::std::convert::Into::into(&value),
})
}
}
impl $crate::sdf::FromValue for $ty {
fn accepts_kind(kind: $crate::sdf::ValueKind) -> bool {
kind == $crate::sdf::ValueKind::Token
}
}
)+};
}
#[cfg(test)]
mod tests {
use crate::sdf;
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
enum Outcome {
Ok,
Error,
}
impl Outcome {
const fn as_token(self) -> &'static str {
match self {
Self::Ok => "ok",
Self::Error => "error",
}
}
fn from_token(token: impl AsRef<str>) -> Option<Self> {
match token.as_ref() {
"ok" => Some(Self::Ok),
"error" => Some(Self::Error),
_ => None,
}
}
}
sdf::impl_token_value!(Outcome);
#[test]
fn error_variant_admitted() -> Result<(), sdf::CastError> {
assert_eq!(Outcome::try_from(sdf::Value::token("error"))?, Outcome::Error);
Ok(())
}
#[test]
fn authors_a_token() {
assert_eq!(sdf::Value::from(Outcome::Ok), sdf::Value::token("ok"));
}
#[test]
fn unknown_value_reports_the_enum() {
for value in [sdf::Value::token("maybe"), sdf::Value::Bool(true)] {
let error = Outcome::try_from(value).expect_err("not an Outcome");
assert!(error.to_string().contains("Outcome"), "{error}");
}
}
}