mod number;
mod primitive;
mod r#type;
pub use number::{Number, NumberLike, NumberSign, NumberType};
pub use primitive::{Primitive, PrimitiveLike, PrimitiveType};
pub use r#type::ValueType;
use std::{
cmp::Ordering,
collections::{BTreeMap, BTreeSet, BinaryHeap, HashMap, HashSet, LinkedList, VecDeque},
convert::TryFrom,
ffi::{OsStr, OsString},
hash::{Hash, Hasher},
path::{Path, PathBuf},
};
#[derive(Clone, Debug)]
#[cfg_attr(feature = "serde-1", derive(serde::Serialize, serde::Deserialize))]
pub enum Value {
List(Vec<Value>),
Map(HashMap<String, Value>),
Optional(Option<Box<Value>>),
Primitive(Primitive),
Text(String),
}
impl Value {
#[inline]
pub fn is_type(&self, r#type: ValueType) -> bool {
self.to_type() == r#type
}
#[inline]
pub fn to_type(&self) -> ValueType {
ValueType::from(self)
}
#[inline]
pub fn has_same_type(&self, other: &Value) -> bool {
self.to_type() == other.to_type()
}
#[inline]
pub fn is_complex(&self) -> bool {
!self.is_primitive()
}
#[inline]
pub fn is_primitive(&self) -> bool {
matches!(self, Self::Primitive(_))
}
#[inline]
pub fn to_primitive(&self) -> Option<Primitive> {
match self {
Self::Primitive(x) => Some(*x),
_ => None,
}
}
#[inline]
pub fn to_primitive_type(&self) -> Option<PrimitiveType> {
self.to_primitive().map(PrimitiveType::from)
}
}
impl Hash for Value {
fn hash<H: Hasher>(&self, state: &mut H) {
match self {
Self::List(x) => x.hash(state),
Self::Map(x) => {
let mut keys = x.keys().collect::<Vec<&String>>();
keys.sort_unstable();
keys.hash(state);
let mut values = x.values().collect::<Vec<&Value>>();
values.sort_unstable_by(|a, b| a.partial_cmp(b).unwrap_or(Ordering::Less));
values.hash(state);
}
Self::Optional(x) => x.hash(state),
Self::Primitive(x) => x.hash(state),
Self::Text(x) => x.hash(state),
}
}
}
impl Eq for Value {}
impl PartialEq for Value {
fn eq(&self, other: &Self) -> bool {
match (self, other) {
(Self::List(a), Self::List(b)) => a == b,
(Self::Map(a), Self::Map(b)) => a == b,
(Self::Optional(a), Self::Optional(b)) => a == b,
(Self::Optional(Some(a)), b) => a.as_ref() == b,
(a, Self::Optional(Some(b))) => a == b.as_ref(),
(Self::Primitive(a), Self::Primitive(b)) => a == b,
(Self::Text(a), Self::Text(b)) => a == b,
_ => false,
}
}
}
impl PartialOrd for Value {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
match (self, other) {
(Self::List(a), Self::List(b)) => a.partial_cmp(b),
(Self::Optional(a), Self::Optional(b)) => match (a, b) {
(Some(a), Some(b)) => a.partial_cmp(b),
_ => None,
},
(Self::Optional(Some(a)), b) => a.as_ref().partial_cmp(b),
(a, Self::Optional(Some(b))) => a.partial_cmp(b.as_ref()),
(Self::Primitive(a), Self::Primitive(b)) => a.partial_cmp(b),
(Self::Text(a), Self::Text(b)) => a.partial_cmp(b),
(Self::Text(a), Self::Primitive(Primitive::Char(b))) => a.partial_cmp(&b.to_string()),
(Self::Primitive(Primitive::Char(a)), Self::Text(b)) => a.to_string().partial_cmp(b),
_ => None,
}
}
}
pub trait ValueLike: Sized {
fn into_value(self) -> Value;
fn try_from_value(value: Value) -> Result<Self, Value>;
}
impl ValueLike for Value {
fn into_value(self) -> Value {
self
}
fn try_from_value(value: Value) -> Result<Self, Value> {
Ok(value)
}
}
impl<T: PrimitiveLike> ValueLike for T {
fn into_value(self) -> Value {
Value::Primitive(self.into_primitive())
}
fn try_from_value(value: Value) -> Result<Self, Value> {
match value {
Value::Primitive(x) => T::try_from_primitive(x).map_err(Value::Primitive),
x => Err(x),
}
}
}
impl From<Primitive> for Value {
fn from(x: Primitive) -> Self {
Self::Primitive(x)
}
}
impl TryFrom<Value> for Primitive {
type Error = Value;
fn try_from(x: Value) -> Result<Self, Self::Error> {
match x {
Value::Primitive(x) => Ok(x),
x => Err(x),
}
}
}
impl<T: ValueLike> ValueLike for Option<T> {
fn into_value(self) -> Value {
Value::Optional(self.map(|x| Box::new(x.into_value())))
}
fn try_from_value(value: Value) -> Result<Self, Value> {
match value {
Value::Optional(Some(x)) => Ok(Some(
T::try_from_value(*x).map_err(|x| Value::Optional(Some(Box::new(x))))?,
)),
Value::Optional(None) => Ok(None),
x => Err(x),
}
}
}
impl<T: ValueLike> From<Option<T>> for Value {
fn from(x: Option<T>) -> Self {
<Option<T> as ValueLike>::into_value(x)
}
}
impl ValueLike for PathBuf {
fn into_value(self) -> Value {
Value::Text(self.to_string_lossy().to_string())
}
fn try_from_value(value: Value) -> Result<Self, Value> {
match value {
Value::Text(x) => Ok(PathBuf::from(x)),
x => Err(x),
}
}
}
impl ValueLike for OsString {
fn into_value(self) -> Value {
Value::Text(self.to_string_lossy().to_string())
}
fn try_from_value(value: Value) -> Result<Self, Value> {
match value {
Value::Text(x) => Ok(OsString::from(x)),
x => Err(x),
}
}
}
impl ValueLike for String {
fn into_value(self) -> Value {
Value::Text(self)
}
fn try_from_value(value: Value) -> Result<Self, Value> {
match value {
Value::Text(x) => Ok(x),
x => Err(x),
}
}
}
impl<'a> From<&'a Path> for Value {
fn from(p: &'a Path) -> Self {
p.to_path_buf().into_value()
}
}
impl<'a> From<&'a OsStr> for Value {
fn from(s: &'a OsStr) -> Self {
s.to_os_string().into_value()
}
}
impl<'a> From<&'a str> for Value {
fn from(s: &'a str) -> Self {
s.to_string().into_value()
}
}
macro_rules! impl_conv {
($($type:ty)+) => {$(
impl From<$type> for Value {
fn from(x: $type) -> Self {
<$type as ValueLike>::into_value(x)
}
}
impl TryFrom<Value> for $type {
type Error = Value;
fn try_from(x: Value) -> Result<Self, Self::Error> {
<$type as ValueLike>::try_from_value(x)
}
}
)+};
}
impl_conv!(
String OsString PathBuf
bool char f32 f64 i128 i16 i32 i64 i8 isize u128 u16 u32 u64 u8 usize
);
macro_rules! impl_list {
($outer:ident $($type:tt)*) => {
impl<T: ValueLike $(+ $type)*> ValueLike for $outer<T> {
fn into_value(self) -> Value {
Value::List(self.into_iter().map(ValueLike::into_value).collect())
}
fn try_from_value(value: Value) -> Result<Self, Value> {
match value {
Value::List(x) => {
let mut tmp = Vec::new();
let mut has_failure = false;
for v in x {
let result = T::try_from_value(v);
if result.is_err() {
has_failure = true;
}
tmp.push(result);
}
if has_failure {
Err(Value::List(
tmp.into_iter()
.map(|v| match v {
Ok(x) => x.into_value(),
Err(x) => x,
})
.collect(),
))
} else {
Ok(tmp.into_iter().map(|v| v.unwrap()).collect())
}
}
x => Err(x),
}
}
}
impl<T: ValueLike $(+ $type)*> From<$outer<T>> for Value {
fn from(x: $outer<T>) -> Self {
<$outer<T> as ValueLike>::into_value(x)
}
}
impl<T: ValueLike $(+ $type)*> TryFrom<Value> for $outer<T> {
type Error = Value;
fn try_from(x: Value) -> Result<Self, Self::Error> {
<$outer<T> as ValueLike>::try_from_value(x)
}
}
};
}
impl_list!(Vec);
impl_list!(VecDeque);
impl_list!(LinkedList);
impl_list!(BinaryHeap Ord);
impl_list!(HashSet Hash Eq);
impl_list!(BTreeSet Ord);
macro_rules! impl_map {
($outer:ident) => {
impl<T: ValueLike> ValueLike for $outer<String, T> {
fn into_value(self) -> Value {
Value::Map(self.into_iter().map(|(k, v)| (k, v.into_value())).collect())
}
fn try_from_value(value: Value) -> Result<Self, Value> {
match value {
Value::Map(x) => {
let mut tmp = Vec::new();
let mut has_failure = false;
for (k, v) in x {
let result = match T::try_from_value(v) {
Ok(v) => Ok((k, v)),
Err(v) => Err((k, v)),
};
if result.is_err() {
has_failure = true;
}
tmp.push(result);
}
if has_failure {
Err(Value::Map(
tmp.into_iter()
.map(|x| match x {
Ok((k, v)) => (k, v.into_value()),
Err((k, v)) => (k, v),
})
.collect(),
))
} else {
Ok(tmp.into_iter().map(|v| v.unwrap()).collect())
}
}
x => Err(x),
}
}
}
impl<T: ValueLike> From<$outer<String, T>> for Value {
fn from(x: $outer<String, T>) -> Self {
<$outer<String, T> as ValueLike>::into_value(x)
}
}
impl<T: ValueLike> TryFrom<Value> for $outer<String, T> {
type Error = Value;
fn try_from(x: Value) -> Result<Self, Self::Error> {
<$outer<String, T> as ValueLike>::try_from_value(x)
}
}
};
}
impl_map!(HashMap);
impl_map!(BTreeMap);
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn bool_can_convert_to_value() {
assert!(matches!(
true.into_value(),
Value::Primitive(Primitive::Bool(true)),
));
}
#[test]
fn value_can_convert_to_bool() {
assert!(matches!(
bool::try_from_value(Value::Primitive(Primitive::Bool(true))),
Ok(true),
));
assert!(matches!(
bool::try_from_value(Value::Primitive(Primitive::Char('c'))),
Err(Value::Primitive(Primitive::Char('c'))),
));
}
#[test]
fn char_can_convert_to_value() {
assert!(matches!(
'c'.into_value(),
Value::Primitive(Primitive::Char('c')),
));
}
#[test]
fn value_can_convert_to_char() {
assert!(matches!(
char::try_from_value(Value::Primitive(Primitive::Char('c'))),
Ok('c'),
));
assert!(matches!(
char::try_from_value(Value::Primitive(Primitive::Bool(true))),
Err(Value::Primitive(Primitive::Bool(true))),
));
}
#[test]
fn f32_can_convert_to_value() {
assert!(matches!(
123f32.into_value(),
Value::Primitive(Primitive::Number(Number::F32(_))),
));
}
#[test]
fn value_can_convert_to_f32() {
assert!(matches!(
f32::try_from_value(Value::Primitive(Primitive::Number(Number::F32(123.0)))),
Ok(_),
));
assert!(matches!(
f32::try_from_value(Value::Primitive(Primitive::Bool(true))),
Err(Value::Primitive(Primitive::Bool(true))),
));
}
#[test]
fn f64_can_convert_to_value() {
assert!(matches!(
123f64.into_value(),
Value::Primitive(Primitive::Number(Number::F64(_))),
));
}
#[test]
fn value_can_convert_to_f64() {
assert!(matches!(
f64::try_from_value(Value::Primitive(Primitive::Number(Number::F64(123.0)))),
Ok(_),
));
assert!(matches!(
f64::try_from_value(Value::Primitive(Primitive::Bool(true))),
Err(Value::Primitive(Primitive::Bool(true))),
));
}
#[test]
fn isize_can_convert_to_value() {
assert!(matches!(
123isize.into_value(),
Value::Primitive(Primitive::Number(Number::Isize(123))),
));
}
#[test]
fn value_can_convert_to_isize() {
assert!(matches!(
isize::try_from_value(Value::Primitive(Primitive::Number(Number::Isize(123)))),
Ok(123),
));
assert!(matches!(
isize::try_from_value(Value::Primitive(Primitive::Bool(true))),
Err(Value::Primitive(Primitive::Bool(true))),
));
}
#[test]
fn i8_can_convert_to_value() {
assert!(matches!(
123i8.into_value(),
Value::Primitive(Primitive::Number(Number::I8(123))),
));
}
#[test]
fn value_can_convert_to_i8() {
assert!(matches!(
i8::try_from_value(Value::Primitive(Primitive::Number(Number::I8(123)))),
Ok(123),
));
assert!(matches!(
i8::try_from_value(Value::Primitive(Primitive::Bool(true))),
Err(Value::Primitive(Primitive::Bool(true))),
));
}
#[test]
fn i16_can_convert_to_value() {
assert!(matches!(
123i16.into_value(),
Value::Primitive(Primitive::Number(Number::I16(123))),
));
}
#[test]
fn value_can_convert_to_i16() {
assert!(matches!(
i16::try_from_value(Value::Primitive(Primitive::Number(Number::I16(123)))),
Ok(123),
));
assert!(matches!(
i16::try_from_value(Value::Primitive(Primitive::Bool(true))),
Err(Value::Primitive(Primitive::Bool(true))),
));
}
#[test]
fn i32_can_convert_to_value() {
assert!(matches!(
123i32.into_value(),
Value::Primitive(Primitive::Number(Number::I32(123))),
));
}
#[test]
fn value_can_convert_to_i32() {
assert!(matches!(
i32::try_from_value(Value::Primitive(Primitive::Number(Number::I32(123)))),
Ok(123),
));
assert!(matches!(
i32::try_from_value(Value::Primitive(Primitive::Bool(true))),
Err(Value::Primitive(Primitive::Bool(true))),
));
}
#[test]
fn i64_can_convert_to_value() {
assert!(matches!(
123i64.into_value(),
Value::Primitive(Primitive::Number(Number::I64(123))),
));
}
#[test]
fn value_can_convert_to_i64() {
assert!(matches!(
i64::try_from_value(Value::Primitive(Primitive::Number(Number::I64(123)))),
Ok(123),
));
assert!(matches!(
i64::try_from_value(Value::Primitive(Primitive::Bool(true))),
Err(Value::Primitive(Primitive::Bool(true))),
));
}
#[test]
fn i128_can_convert_to_value() {
assert!(matches!(
123i128.into_value(),
Value::Primitive(Primitive::Number(Number::I128(123))),
));
}
#[test]
fn value_can_convert_to_i128() {
assert!(matches!(
i128::try_from_value(Value::Primitive(Primitive::Number(Number::I128(123)))),
Ok(123),
));
assert!(matches!(
i128::try_from_value(Value::Primitive(Primitive::Bool(true))),
Err(Value::Primitive(Primitive::Bool(true))),
));
}
#[test]
fn usize_can_convert_to_value() {
assert!(matches!(
123usize.into_value(),
Value::Primitive(Primitive::Number(Number::Usize(123))),
));
}
#[test]
fn value_can_convert_to_usize() {
assert!(matches!(
usize::try_from_value(Value::Primitive(Primitive::Number(Number::Usize(123)))),
Ok(123),
));
assert!(matches!(
usize::try_from_value(Value::Primitive(Primitive::Bool(true))),
Err(Value::Primitive(Primitive::Bool(true))),
));
}
#[test]
fn u8_can_convert_to_value() {
assert!(matches!(
123u8.into_value(),
Value::Primitive(Primitive::Number(Number::U8(123))),
));
}
#[test]
fn value_can_convert_to_u8() {
assert!(matches!(
u8::try_from_value(Value::Primitive(Primitive::Number(Number::U8(123)))),
Ok(123),
));
assert!(matches!(
u8::try_from_value(Value::Primitive(Primitive::Bool(true))),
Err(Value::Primitive(Primitive::Bool(true))),
));
}
#[test]
fn u16_can_convert_to_value() {
assert!(matches!(
123u16.into_value(),
Value::Primitive(Primitive::Number(Number::U16(123))),
));
}
#[test]
fn value_can_convert_to_u16() {
assert!(matches!(
u16::try_from_value(Value::Primitive(Primitive::Number(Number::U16(123)))),
Ok(123),
));
assert!(matches!(
u16::try_from_value(Value::Primitive(Primitive::Bool(true))),
Err(Value::Primitive(Primitive::Bool(true))),
));
}
#[test]
fn u32_can_convert_to_value() {
assert!(matches!(
123u32.into_value(),
Value::Primitive(Primitive::Number(Number::U32(123))),
));
}
#[test]
fn value_can_convert_to_u32() {
assert!(matches!(
u32::try_from_value(Value::Primitive(Primitive::Number(Number::U32(123)))),
Ok(123),
));
assert!(matches!(
u32::try_from_value(Value::Primitive(Primitive::Bool(true))),
Err(Value::Primitive(Primitive::Bool(true))),
));
}
#[test]
fn u64_can_convert_to_value() {
assert!(matches!(
123u64.into_value(),
Value::Primitive(Primitive::Number(Number::U64(123))),
));
}
#[test]
fn value_can_convert_to_u64() {
assert!(matches!(
u64::try_from_value(Value::Primitive(Primitive::Number(Number::U64(123)))),
Ok(123),
));
assert!(matches!(
u64::try_from_value(Value::Primitive(Primitive::Bool(true))),
Err(Value::Primitive(Primitive::Bool(true))),
));
}
#[test]
fn u128_can_convert_to_value() {
assert!(matches!(
123u128.into_value(),
Value::Primitive(Primitive::Number(Number::U128(123))),
));
}
#[test]
fn value_can_convert_to_u128() {
assert!(matches!(
u128::try_from_value(Value::Primitive(Primitive::Number(Number::U128(123)))),
Ok(123),
));
assert!(matches!(
u128::try_from_value(Value::Primitive(Primitive::Bool(true))),
Err(Value::Primitive(Primitive::Bool(true))),
));
}
#[test]
fn option_can_convert_to_value() {
match Some('c').into_value() {
Value::Optional(Some(x)) => {
assert!(matches!(*x, Value::Primitive(Primitive::Char('c'))))
}
x => panic!("Unexpected value: {:?}", x),
}
assert!(matches!(None::<char>.into_value(), Value::Optional(None)));
}
#[test]
fn value_can_convert_to_option() {
assert!(matches!(
Option::<char>::try_from_value(Value::Optional(Some(Box::new(Value::Primitive(
Primitive::Char('c')
))))),
Ok(Some('c')),
));
assert!(matches!(
Option::<char>::try_from_value(Value::Primitive(Primitive::Bool(true))),
Err(Value::Primitive(Primitive::Bool(true))),
));
assert!(matches!(
Option::<char>::try_from_value(Value::Optional(Some(Box::new(Value::Primitive(
Primitive::Bool(true)
))))),
Err(Value::Optional(Some(_))),
));
}
#[test]
fn string_can_convert_to_value() {
match String::from("test").into_value() {
Value::Text(x) => assert_eq!(x, "test"),
x => panic!("Unexpected value: {:?}", x),
}
}
#[test]
fn value_can_convert_to_string() {
match String::try_from_value(Value::Text(String::from("test"))) {
Ok(x) => assert_eq!(x, "test"),
x => panic!("{:?}", x),
}
assert!(matches!(
String::try_from_value(Value::Primitive(Primitive::Bool(true))),
Err(Value::Primitive(Primitive::Bool(true))),
));
}
#[test]
fn pathbuf_can_convert_to_value() {
match PathBuf::from("test").into_value() {
Value::Text(x) => assert_eq!(x, "test"),
x => panic!("Unexpected value: {:?}", x),
}
}
#[test]
fn value_can_convert_to_pathbuf() {
match PathBuf::try_from_value(Value::Text(String::from("test"))) {
Ok(x) => assert_eq!(x.as_os_str(), "test"),
x => panic!("{:?}", x),
}
assert!(matches!(
PathBuf::try_from_value(Value::Primitive(Primitive::Bool(true))),
Err(Value::Primitive(Primitive::Bool(true))),
));
}
#[test]
fn osstring_can_convert_to_value() {
match OsString::from("test").into_value() {
Value::Text(x) => assert_eq!(x, "test"),
x => panic!("Unexpected value: {:?}", x),
}
}
#[test]
fn value_can_convert_to_osstring() {
match OsString::try_from_value(Value::Text(String::from("test"))) {
Ok(x) => assert_eq!(x, "test"),
x => panic!("{:?}", x),
}
assert!(matches!(
OsString::try_from_value(Value::Primitive(Primitive::Bool(true))),
Err(Value::Primitive(Primitive::Bool(true))),
));
}
#[test]
fn vec_can_convert_to_value() {
match vec![1, 2, 3].into_value() {
Value::List(x) => assert_eq!(x, vec![1.into_value(), 2.into_value(), 3.into_value()]),
x => panic!("Unexpected value: {:?}", x),
}
}
#[test]
fn value_can_convert_to_vec() {
match Vec::<u8>::try_from_value(vec![1, 2, 3].into_value()) {
Ok(x) => assert_eq!(x, vec![1, 2, 3]),
x => panic!("{:?}", x),
}
assert!(matches!(
Vec::<u8>::try_from_value(Value::Primitive(Primitive::Bool(true))),
Err(Value::Primitive(Primitive::Bool(true))),
));
}
#[test]
fn vecdeque_can_convert_to_value() {
let list: VecDeque<u8> = vec![1, 2, 3].into_iter().collect();
match list.into_value() {
Value::List(x) => assert_eq!(x, vec![1.into_value(), 2.into_value(), 3.into_value()]),
x => panic!("Unexpected value: {:?}", x),
}
}
#[test]
fn value_can_convert_to_vecdeque() {
match VecDeque::<u8>::try_from_value(vec![1, 2, 3].into_value()) {
Ok(x) => assert_eq!(x, vec![1, 2, 3]),
x => panic!("{:?}", x),
}
assert!(matches!(
VecDeque::<u8>::try_from_value(Value::Primitive(Primitive::Bool(true))),
Err(Value::Primitive(Primitive::Bool(true))),
));
}
#[test]
fn linkedlist_can_convert_to_value() {
let list: LinkedList<u8> = vec![1, 2, 3].into_iter().collect();
match list.into_value() {
Value::List(x) => assert_eq!(x, vec![1.into_value(), 2.into_value(), 3.into_value()]),
x => panic!("Unexpected value: {:?}", x),
}
}
#[test]
fn value_can_convert_to_linkedlist() {
match LinkedList::<u8>::try_from_value(vec![1, 2, 3].into_value()) {
Ok(x) => assert_eq!(x, vec![1, 2, 3].into_iter().collect::<LinkedList<u8>>()),
x => panic!("{:?}", x),
}
assert!(matches!(
LinkedList::<u8>::try_from_value(Value::Primitive(Primitive::Bool(true))),
Err(Value::Primitive(Primitive::Bool(true))),
));
}
#[test]
fn binaryheap_can_convert_to_value() {
let list: BinaryHeap<u8> = vec![1, 2, 3].into_iter().collect();
match list.into_value() {
Value::List(x) => assert_eq!(x, vec![3.into_value(), 2.into_value(), 1.into_value()]),
x => panic!("Unexpected value: {:?}", x),
}
}
#[test]
fn value_can_convert_to_binaryheap() {
match BinaryHeap::<u8>::try_from_value(vec![1, 2, 3].into_value()) {
Ok(mut x) => {
assert_eq!(x.pop(), Some(3));
assert_eq!(x.pop(), Some(2));
assert_eq!(x.pop(), Some(1));
assert_eq!(x.pop(), None);
}
x => panic!("{:?}", x),
}
assert!(matches!(
BinaryHeap::<u8>::try_from_value(Value::Primitive(Primitive::Bool(true))),
Err(Value::Primitive(Primitive::Bool(true))),
));
}
#[test]
fn hashset_can_convert_to_value() {
let list: HashSet<u8> = vec![1, 2, 3].into_iter().collect();
match list.into_value() {
Value::List(mut x) => {
x.sort_unstable_by(|a, b| a.partial_cmp(b).unwrap());
assert_eq!(x, vec![1.into_value(), 2.into_value(), 3.into_value()]);
}
x => panic!("Unexpected value: {:?}", x),
}
}
#[test]
fn value_can_convert_to_hashset() {
match HashSet::<u8>::try_from_value(vec![1, 2, 3].into_value()) {
Ok(x) => assert_eq!(x, vec![1, 2, 3].into_iter().collect::<HashSet<u8>>()),
x => panic!("{:?}", x),
}
assert!(matches!(
HashSet::<u8>::try_from_value(Value::Primitive(Primitive::Bool(true))),
Err(Value::Primitive(Primitive::Bool(true))),
));
}
#[test]
fn btreeset_can_convert_to_value() {
let list: BTreeSet<u8> = vec![1, 2, 3].into_iter().collect();
match list.into_value() {
Value::List(mut x) => {
x.sort_unstable_by(|a, b| a.partial_cmp(b).unwrap());
assert_eq!(x, vec![1.into_value(), 2.into_value(), 3.into_value()]);
}
x => panic!("Unexpected value: {:?}", x),
}
}
#[test]
fn value_can_convert_to_btreeset() {
match BTreeSet::<u8>::try_from_value(vec![1, 2, 3].into_value()) {
Ok(x) => assert_eq!(x, vec![1, 2, 3].into_iter().collect::<BTreeSet<u8>>()),
x => panic!("{:?}", x),
}
assert!(matches!(
BTreeSet::<u8>::try_from_value(Value::Primitive(Primitive::Bool(true))),
Err(Value::Primitive(Primitive::Bool(true))),
));
}
#[test]
fn hashmap_can_convert_to_value() {
let map: HashMap<String, u8> = vec![
(String::from("one"), 1),
(String::from("two"), 2),
(String::from("three"), 3),
]
.into_iter()
.collect();
match map.into_value() {
Value::Map(mut x) => {
assert_eq!(x.len(), 3);
assert_eq!(x.remove("one"), Some(1.into_value()));
assert_eq!(x.remove("two"), Some(2.into_value()));
assert_eq!(x.remove("three"), Some(3.into_value()));
}
x => panic!("Unexpected value: {:?}", x),
}
}
#[test]
fn value_can_convert_to_hashmap() {
match HashMap::<String, u8>::try_from_value(
vec![
(String::from("one"), 1),
(String::from("two"), 2),
(String::from("three"), 3),
]
.into_iter()
.collect::<HashMap<String, u8>>()
.into_value(),
) {
Ok(mut x) => {
assert_eq!(x.len(), 3);
assert_eq!(x.remove("one"), Some(1));
assert_eq!(x.remove("two"), Some(2));
assert_eq!(x.remove("three"), Some(3));
}
x => panic!("{:?}", x),
}
assert!(matches!(
HashMap::<String, u8>::try_from_value(Value::Primitive(Primitive::Bool(true))),
Err(Value::Primitive(Primitive::Bool(true))),
));
}
#[test]
fn btreemap_can_convert_to_value() {
let map: BTreeMap<String, u8> = vec![
(String::from("one"), 1),
(String::from("two"), 2),
(String::from("three"), 3),
]
.into_iter()
.collect();
match map.into_value() {
Value::Map(mut x) => {
assert_eq!(x.len(), 3);
assert_eq!(x.remove("one"), Some(1.into_value()));
assert_eq!(x.remove("two"), Some(2.into_value()));
assert_eq!(x.remove("three"), Some(3.into_value()));
}
x => panic!("Unexpected value: {:?}", x),
}
}
#[test]
fn value_can_convert_to_btreemap() {
match BTreeMap::<String, u8>::try_from_value(
vec![
(String::from("one"), 1),
(String::from("two"), 2),
(String::from("three"), 3),
]
.into_iter()
.collect::<HashMap<String, u8>>()
.into_value(),
) {
Ok(mut x) => {
assert_eq!(x.len(), 3);
assert_eq!(x.remove("one"), Some(1));
assert_eq!(x.remove("two"), Some(2));
assert_eq!(x.remove("three"), Some(3));
}
x => panic!("{:?}", x),
}
assert!(matches!(
BTreeMap::<String, u8>::try_from_value(Value::Primitive(Primitive::Bool(true))),
Err(Value::Primitive(Primitive::Bool(true))),
));
}
}