blob: 2db9cd10a9b171048c51ab0cffc8b05b8be8924c [file] [log] [blame] [edit]
use crate::{Enumerable, Listable, Mappable, Structable, Tuplable, Valuable, Visit};
use core::fmt;
macro_rules! value {
(
$(
$(#[$attrs:meta])*
$variant:ident($ty:ty),
)*
) => {
/// Any Rust value
///
/// The `Value` enum is used to pass single values to the
/// [visitor][`Visit`]. Primitive types are enumerated and other types
/// are represented at trait objects.
///
/// Values are converted to `Value` instances using
/// [`Valuable::as_value()`].
///
/// # Examples
///
/// Convert a primitive type
///
/// ```
/// use valuable::{Value, Valuable};
///
/// let num = 123;
/// let val = num.as_value();
///
/// assert!(matches!(val, Value::I32(v) if v == 123));
/// ```
///
/// Converting a struct
///
/// ```
/// use valuable::{Value, Valuable};
///
/// #[derive(Valuable, Debug)]
/// struct HelloWorld {
/// message: String,
/// }
///
/// let hello = HelloWorld {
/// message: "greetings".to_string(),
/// };
///
/// let val = hello.as_value();
///
/// assert!(matches!(val, Value::Structable(_v)));
///
/// // The Value `Debug` output matches the struct's
/// assert_eq!(
/// format!("{:?}", val),
/// format!("{:?}", hello),
/// );
/// ```
///
/// [visitor]: Visit
#[non_exhaustive]
#[derive(Clone, Copy)]
pub enum Value<'a> {
$(
$(#[$attrs])*
$variant($ty),
)*
/// A Rust `()` or `None` value.
///
/// # Examples
///
/// ```
/// use valuable::Value;
///
/// let v = Value::Unit;
/// ```
Unit,
}
$(
$(#[$attrs])*
impl<'a> From<$ty> for Value<'a> {
fn from(src: $ty) -> Value<'a> {
Value::$variant(src)
}
}
)*
impl<'a> From<()> for Value<'a> {
fn from(_: ()) -> Value<'a> {
Value::Tuplable(&())
}
}
impl fmt::Debug for Value<'_> {
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
use Value::*;
// Doc comments are expanded into the branch arms, which results
// in a warning. It isn't a big deal, so silence it.
#[allow(unused_doc_comments)]
match self {
$(
$(#[$attrs])*
$variant(v) => fmt::Debug::fmt(v, fmt),
)*
Unit => ().fmt(fmt),
}
}
}
}
}
value! {
/// A Rust `bool` value
///
/// # Examples
///
/// ```
/// use valuable::Value;
///
/// let v = Value::Bool(true);
/// ```
Bool(bool),
/// A Rust `char` value
///
/// # Examples
///
/// ```
/// use valuable::Value;
///
/// let v = Value::Char('h');
/// ```
Char(char),
/// A Rust `f32` value
///
/// # Examples
///
/// ```
/// use valuable::Value;
///
/// let v = Value::F32(3.1415);
/// ```
F32(f32),
/// A Rust `f64` value
///
/// # Examples
///
/// ```
/// use valuable::Value;
///
/// let v = Value::F64(3.1415);
/// ```
F64(f64),
/// A Rust `i8` value
///
/// # Examples
///
/// ```
/// use valuable::Value;
///
/// let v = Value::I8(42);
/// ```
I8(i8),
/// A Rust `i16` value
///
/// # Examples
///
/// ```
/// use valuable::Value;
///
/// let v = Value::I16(42);
/// ```
I16(i16),
/// A Rust `i32` value
///
/// # Examples
///
/// ```
/// use valuable::Value;
///
/// let v = Value::I32(42);
/// ```
I32(i32),
/// A Rust `i64` value
///
/// # Examples
///
/// ```
/// use valuable::Value;
///
/// let v = Value::I64(42);
/// ```
I64(i64),
/// A Rust `i128` value
///
/// # Examples
///
/// ```
/// use valuable::Value;
///
/// let v = Value::I128(42);
/// ```
I128(i128),
/// A Rust `isize` value
///
/// # Examples
///
/// ```
/// use valuable::Value;
///
/// let v = Value::Isize(42);
/// ```
Isize(isize),
/// A Rust `&str` value
///
/// # Examples
///
/// ```
/// use valuable::Value;
///
/// let v = Value::String("hello");
/// ```
String(&'a str),
/// A Rust `u8` value
///
/// # Examples
///
/// ```
/// use valuable::Value;
///
/// let v = Value::U8(42);
/// ```
U8(u8),
/// A Rust `u16` value
///
/// # Examples
///
/// ```
/// use valuable::Value;
///
/// let v = Value::U16(42);
/// ```
U16(u16),
/// A Rust `u32` value
///
/// # Examples
///
/// ```
/// use valuable::Value;
///
/// let v = Value::U32(42);
/// ```
U32(u32),
/// A Rust `u64` value
///
/// # Examples
///
/// ```
/// use valuable::Value;
///
/// let v = Value::U64(42);
/// ```
U64(u64),
/// A Rust `u128` value
///
/// # Examples
///
/// ```
/// use valuable::Value;
///
/// let v = Value::U128(42);
/// ```
U128(u128),
/// A Rust `usize` value
///
/// # Examples
///
/// ```
/// use valuable::Value;
///
/// let v = Value::Usize(42);
/// ```
Usize(usize),
/// A Rust `&Path` value
///
/// # Examples
///
/// ```
/// use valuable::Value;
/// use std::path::Path;
///
/// let path = Path::new("a.txt");
/// let v = Value::Path(path);
/// ```
#[cfg(feature = "std")]
Path(&'a std::path::Path),
/// A Rust error value
///
/// # Examples
///
/// ```
/// use valuable::Value;
/// use std::io;
///
/// let err: io::Error = io::ErrorKind::Other.into();
/// let v = Value::Error(&err);
/// ```
#[cfg(feature = "std")]
Error(&'a (dyn std::error::Error +'static)),
/// A Rust list value
///
/// # Examples
///
/// ```
/// use valuable::Value;
///
/// let vals = vec![1, 2, 3, 4, 5];
/// let v = Value::Listable(&vals);
/// ```
Listable(&'a dyn Listable),
/// A Rust map value
///
/// # Examples
///
/// ```
/// use valuable::Value;
/// use std::collections::HashMap;
///
/// let mut map = HashMap::new();
/// map.insert("foo", 1);
/// map.insert("bar", 2);
///
/// let v = Value::Mappable(&map);
/// ```
Mappable(&'a dyn Mappable),
/// A Rust struct value
///
/// # Examples
///
/// ```
/// use valuable::{Value, Valuable};
///
/// #[derive(Valuable)]
/// struct MyStruct {
/// field: u32,
/// }
///
/// let my_struct = MyStruct {
/// field: 123,
/// };
///
/// let v = Value::Structable(&my_struct);
/// ```
Structable(&'a dyn Structable),
/// A Rust enum value
///
/// # Examples
///
/// ```
/// use valuable::{Value, Valuable};
///
/// #[derive(Valuable)]
/// enum MyEnum {
/// Foo,
/// Bar,
/// }
///
/// let my_enum = MyEnum::Foo;
/// let v = Value::Enumerable(&my_enum);
/// ```
Enumerable(&'a dyn Enumerable),
/// A tuple value
///
/// # Examples
///
/// ```
/// use valuable::{Value, Valuable};
///
/// let my_tuple = (123, 456);
/// let v = Value::Tuplable(&my_tuple);
/// ```
Tuplable(&'a dyn Tuplable),
}
impl Valuable for Value<'_> {
fn as_value(&self) -> Value<'_> {
*self
}
fn visit(&self, visit: &mut dyn Visit) {
visit.visit_value(*self);
}
}
impl Default for Value<'_> {
fn default() -> Self {
Value::Unit
}
}
macro_rules! convert {
(
$(
$(#[$attrs:meta])*
$ty:ty => $as:ident,
)*
) => {
impl<'a> Value<'a> {
/// Return a `bool` representation of `self`, if possible.
///
/// # Examples
///
/// ```
/// use valuable::Value;
///
/// assert_eq!(Value::Bool(true).as_bool(), Some(true));
/// assert_eq!(Value::Char('c').as_bool(), None);
/// ```
pub fn as_bool(&self) -> Option<bool> {
match *self {
Value::Bool(v) => Some(v),
_ => None,
}
}
/// Return a `char` representation of `self`, if possible.
///
/// # Examples
///
/// ```
/// use valuable::Value;
///
/// assert_eq!(Value::Char('c').as_char(), Some('c'));
/// assert_eq!(Value::Bool(true).as_char(), None);
/// ```
pub fn as_char(&self) -> Option<char> {
match *self {
Value::Char(v) => Some(v),
_ => None,
}
}
/// Return a `f32` representation of `self`, if possible.
///
/// # Examples
///
/// ```
/// use valuable::Value;
///
/// assert_eq!(Value::F32(3.1415).as_f32(), Some(3.1415));
/// assert_eq!(Value::Bool(true).as_f32(), None);
/// ```
pub fn as_f32(&self) -> Option<f32> {
match *self {
Value::F32(v) => Some(v),
_ => None,
}
}
/// Return a `f64` representation of `self`, if possible.
///
/// # Examples
///
/// ```
/// use valuable::Value;
///
/// assert_eq!(Value::F64(3.1415).as_f64(), Some(3.1415));
/// assert_eq!(Value::Bool(true).as_f64(), None);
/// ```
pub fn as_f64(&self) -> Option<f64> {
match *self {
Value::F64(v) => Some(v),
_ => None,
}
}
$(
$(#[$attrs])*
pub fn $as(&self) -> Option<$ty> {
use Value::*;
use core::convert::TryInto;
match *self {
I8(v) => v.try_into().ok(),
I16(v) => v.try_into().ok(),
I32(v) => v.try_into().ok(),
I64(v) => v.try_into().ok(),
I128(v) => v.try_into().ok(),
Isize(v) => v.try_into().ok(),
U8(v) => v.try_into().ok(),
U16(v) => v.try_into().ok(),
U32(v) => v.try_into().ok(),
U64(v) => v.try_into().ok(),
U128(v) => v.try_into().ok(),
Usize(v) => v.try_into().ok(),
_ => None,
}
}
)*
/// Return a `&str` representation of `self`, if possible.
///
/// # Examples
///
/// ```
/// use valuable::Value;
///
/// assert_eq!(Value::String("hello").as_str(), Some("hello"));
/// assert_eq!(Value::Bool(true).as_str(), None);
/// ```
pub fn as_str(&self) -> Option<&str> {
match *self {
Value::String(v) => Some(v),
_ => None,
}
}
/// Return a `&Path` representation of `self`, if possible.
///
/// # Examples
///
/// ```
/// use valuable::Value;
/// use std::path::Path;
///
/// let path = Path::new("a.txt");
///
/// assert!(Value::Path(path).as_path().is_some());
/// assert!(Value::Bool(true).as_path().is_none());
/// ```
#[cfg(feature = "std")]
pub fn as_path(&self) -> Option<&std::path::Path> {
match *self {
Value::Path(v) => Some(v),
_ => None,
}
}
/// Return a `&dyn Error` representation of `self`, if possible.
///
/// # Examples
///
/// ```
/// use valuable::Value;
/// use std::io;
///
/// let err: io::Error = io::ErrorKind::Other.into();
///
/// assert!(Value::Error(&err).as_error().is_some());
/// assert!(Value::Bool(true).as_error().is_none());
/// ```
#[cfg(feature = "std")]
pub fn as_error(&self) -> Option<&(dyn std::error::Error + 'static)> {
match *self {
Value::Error(v) => Some(v),
_ => None,
}
}
/// Return a `&dyn Listable` representation of `self`, if possible.
///
/// # Examples
///
/// ```
/// use valuable::Value;
///
/// let list = vec![1, 2, 3, 4];
///
/// assert!(Value::Listable(&list).as_listable().is_some());
/// assert!(Value::Bool(true).as_listable().is_none());
/// ```
pub fn as_listable(&self) -> Option<&dyn Listable> {
match *self {
Value::Listable(v) => Some(v),
_ => None,
}
}
/// Return a `&dyn Mappable` representation of `self`, if possible.
///
/// # Examples
///
/// ```
/// use valuable::Value;
/// use std::collections::HashMap;
///
/// let mut map = HashMap::new();
/// map.insert("foo", 123);
/// map.insert("bar", 456);
///
/// assert!(Value::Mappable(&map).as_mappable().is_some());
/// assert!(Value::Bool(true).as_mappable().is_none());
/// ```
pub fn as_mappable(&self) -> Option<&dyn Mappable> {
match *self {
Value::Mappable(v) => Some(v),
_ => None,
}
}
/// Return a `&dyn Structable` representation of `self`, if possible.
///
/// # Examples
///
/// ```
/// use valuable::{Value, Valuable};
///
/// #[derive(Valuable)]
/// struct Hello {
/// message: &'static str,
/// }
///
/// let hello = Hello { message: "Hello world" };
///
/// assert!(Value::Structable(&hello).as_structable().is_some());
/// assert!(Value::Bool(true).as_structable().is_none());
/// ```
pub fn as_structable(&self) -> Option<&dyn Structable> {
match *self {
Value::Structable(v) => Some(v),
_ => None,
}
}
/// Return a `&dyn Enumerable` representation of `self`, if possible.
///
/// # Examples
///
/// ```
/// use valuable::{Value, Valuable};
///
/// #[derive(Valuable)]
/// enum Greet {
/// Hello,
/// World,
/// }
///
/// let greet = Greet::Hello;
///
/// assert!(Value::Enumerable(&greet).as_enumerable().is_some());
/// assert!(Value::Bool(true).as_enumerable().is_none());
/// ```
pub fn as_enumerable(&self) -> Option<&dyn Enumerable> {
match *self {
Value::Enumerable(v) => Some(v),
_ => None,
}
}
/// Return a `&dyn Tuplable` representation of `self`, if possible.
///
/// # Examples
///
/// ```
/// use valuable::Value;
///
/// let my_tuple = (123, 456);
///
/// assert!(Value::Tuplable(&my_tuple).as_tuplable().is_some());
/// assert!(Value::Bool(true).as_tuplable().is_none());
/// ```
pub fn as_tuplable(&self) -> Option<&dyn Tuplable> {
match *self {
Value::Tuplable(v) => Some(v),
_ => None,
}
}
}
}
}
convert! {
/// Return a `i8` representation of `self`, if possible.
///
/// # Examples
///
/// ```
/// use valuable::Value;
///
/// assert_eq!(Value::I8(42).as_i8(), Some(42));
/// assert_eq!(Value::I32(42).as_i8(), Some(42));
///
/// assert_eq!(Value::I64(i64::MAX).as_i8(), None);
/// assert_eq!(Value::Bool(true).as_i8(), None);
/// ```
i8 => as_i8,
/// Return a `i16` representation of `self`, if possible.
///
/// # Examples
///
/// ```
/// use valuable::Value;
///
/// assert_eq!(Value::I16(42).as_i16(), Some(42));
/// assert_eq!(Value::I32(42).as_i16(), Some(42));
///
/// assert_eq!(Value::I64(i64::MAX).as_i16(), None);
/// assert_eq!(Value::Bool(true).as_i16(), None);
/// ```
i16 => as_i16,
/// Return a `i32` representation of `self`, if possible.
///
/// # Examples
///
/// ```
/// use valuable::Value;
///
/// assert_eq!(Value::I32(42).as_i32(), Some(42));
/// assert_eq!(Value::I64(42).as_i32(), Some(42));
///
/// assert_eq!(Value::I64(i64::MAX).as_i32(), None);
/// assert_eq!(Value::Bool(true).as_i32(), None);
/// ```
i32 => as_i32,
/// Return a `i64` representation of `self`, if possible.
///
/// # Examples
///
/// ```
/// use valuable::Value;
///
/// assert_eq!(Value::I64(42).as_i64(), Some(42));
/// assert_eq!(Value::I128(42).as_i64(), Some(42));
///
/// assert_eq!(Value::I128(i128::MAX).as_i64(), None);
/// assert_eq!(Value::Bool(true).as_i64(), None);
/// ```
i64 => as_i64,
/// Return a `i128` representation of `self`, if possible.
///
/// # Examples
///
/// ```
/// use valuable::Value;
///
/// assert_eq!(Value::I128(42).as_i128(), Some(42));
/// assert_eq!(Value::U128(42).as_i128(), Some(42));
///
/// assert_eq!(Value::U128(u128::MAX).as_i128(), None);
/// assert_eq!(Value::Bool(true).as_i128(), None);
/// ```
i128 => as_i128,
/// Return a `isize` representation of `self`, if possible.
///
/// # Examples
///
/// ```
/// use valuable::Value;
///
/// assert_eq!(Value::Isize(42).as_isize(), Some(42));
/// assert_eq!(Value::Usize(42).as_isize(), Some(42));
///
/// assert_eq!(Value::Usize(usize::MAX).as_isize(), None);
/// assert_eq!(Value::Bool(true).as_isize(), None);
/// ```
isize => as_isize,
/// Return a `u8` representation of `self`, if possible.
///
/// # Examples
///
/// ```
/// use valuable::Value;
///
/// assert_eq!(Value::U8(42).as_u8(), Some(42));
/// assert_eq!(Value::U32(42).as_u8(), Some(42));
///
/// assert_eq!(Value::U32(u32::MAX).as_u8(), None);
/// assert_eq!(Value::Bool(true).as_u8(), None);
/// ```
u8 => as_u8,
/// Return a `u16` representation of `self`, if possible.
///
/// # Examples
///
/// ```
/// use valuable::Value;
///
/// assert_eq!(Value::U16(42).as_u16(), Some(42));
/// assert_eq!(Value::U32(42).as_u16(), Some(42));
///
/// assert_eq!(Value::U32(u32::MAX).as_u16(), None);
/// assert_eq!(Value::Bool(true).as_u16(), None);
/// ```
u16 => as_u16,
/// Return a `u32` representation of `self`, if possible.
///
/// # Examples
///
/// ```
/// use valuable::Value;
///
/// assert_eq!(Value::U32(42).as_u32(), Some(42));
/// assert_eq!(Value::U64(42).as_u32(), Some(42));
///
/// assert_eq!(Value::U64(u64::MAX).as_u32(), None);
/// assert_eq!(Value::Bool(true).as_u32(), None);
/// ```
u32 => as_u32,
/// Return a `u64` representation of `self`, if possible.
///
/// # Examples
///
/// ```
/// use valuable::Value;
///
/// assert_eq!(Value::U64(42).as_u64(), Some(42));
/// assert_eq!(Value::U128(42).as_u64(), Some(42));
///
/// assert_eq!(Value::U128(u128::MAX).as_u64(), None);
/// assert_eq!(Value::Bool(true).as_u64(), None);
/// ```
u64 => as_u64,
/// Return a `u128` representation of `self`, if possible.
///
/// # Examples
///
/// ```
/// use valuable::Value;
///
/// assert_eq!(Value::U128(42).as_u128(), Some(42));
/// assert_eq!(Value::I32(42).as_u128(), Some(42));
///
/// assert_eq!(Value::I32(-5).as_u128(), None);
/// assert_eq!(Value::Bool(true).as_u128(), None);
/// ```
u128 => as_u128,
/// Return a `usize` representation of `self`, if possible.
///
/// # Examples
///
/// ```
/// use valuable::Value;
///
/// assert_eq!(Value::Usize(42).as_usize(), Some(42));
/// assert_eq!(Value::I8(42).as_usize(), Some(42));
///
/// assert_eq!(Value::I8(-5).as_usize(), None);
/// assert_eq!(Value::Bool(true).as_usize(), None);
/// ```
usize => as_usize,
}