use std::{
borrow::Cow,
fmt::{Display, Write},
marker::PhantomData,
};
use serde::{
de::Visitor,
ser::{SerializeMap, SerializeSeq},
Deserialize, Serialize,
};
use crate::format::{Float, InnerFloat, InnerInteger, Integer};
#[derive(Debug, Clone, PartialEq)]
#[must_use]
pub enum Value<'a> {
None,
Unit,
Bool(bool),
Integer(Integer),
Float(Float),
Bytes(Cow<'a, [u8]>),
String(Cow<'a, str>),
Sequence(Vec<Self>),
Mappings(Vec<(Self, Self)>),
}
impl<'a> Display for Value<'a> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Value::None => f.write_str("None"),
Value::Unit => f.write_str("()"),
Value::Bool(true) => f.write_str("true"),
Value::Bool(false) => f.write_str("false"),
Value::Integer(value) => Display::fmt(value, f),
Value::Float(value) => Display::fmt(value, f),
Value::Bytes(bytes) => {
f.write_str("0x")?;
for (index, byte) in bytes.iter().enumerate() {
if index > 0 && index % 4 == 0 {
f.write_char('_')?;
}
write!(f, "{:02x}", byte)?;
}
Ok(())
}
Value::String(string) => f.write_str(string),
Value::Sequence(sequence) => {
f.write_char('[')?;
for (index, value) in sequence.iter().enumerate() {
if index > 0 {
f.write_str(", ")?;
}
Display::fmt(value, f)?;
}
f.write_char(']')
}
Value::Mappings(mappings) => {
f.write_char('{')?;
for (index, (key, value)) in mappings.iter().enumerate() {
if index > 0 {
f.write_str(", ")?;
}
Display::fmt(key, f)?;
f.write_str(": ")?;
Display::fmt(value, f)?;
}
f.write_char('}')
}
}
}
}
impl<'a> Value<'a> {
pub fn from_sequence<IntoIter: IntoIterator<Item = T>, T: Into<Self>>(
sequence: IntoIter,
) -> Self {
Self::Sequence(sequence.into_iter().map(T::into).collect())
}
pub fn from_mappings<IntoIter: IntoIterator<Item = (K, V)>, K: Into<Self>, V: Into<Self>>(
mappings: IntoIter,
) -> Self {
Self::Mappings(
mappings
.into_iter()
.map(|(k, v)| (k.into(), v.into()))
.collect(),
)
}
#[must_use]
pub fn is_empty(&self) -> bool {
match self {
Value::None => true,
Value::Unit | Value::Bool(_) | Value::Integer(_) | Value::Float(_) => false,
Value::Bytes(value) => value.is_empty(),
Value::String(value) => value.is_empty(),
Value::Sequence(value) => value.is_empty(),
Value::Mappings(value) => value.is_empty(),
}
}
#[must_use]
pub fn as_bool(&self) -> bool {
match self {
Value::None => false,
Value::Unit => true,
Value::Bool(value) => *value,
Value::Integer(value) => !value.is_zero(),
Value::Float(value) => !value.is_zero(),
Value::Bytes(value) => !value.is_empty(),
Value::String(value) => !value.is_empty(),
Value::Sequence(value) => !value.is_empty(),
Value::Mappings(value) => !value.is_empty(),
}
}
#[must_use]
pub fn as_integer(&self) -> Option<Integer> {
match self {
Value::Integer(value) => Some(*value),
Value::Float(value) => value.as_integer().ok(),
_ => None,
}
}
#[must_use]
pub fn as_float(&self) -> Option<Float> {
match self {
Value::Integer(value) => value.as_float().ok(),
Value::Float(value) => Some(*value),
_ => None,
}
}
#[must_use]
pub fn as_str(&self) -> Option<&str> {
match self {
Self::Bytes(bytes) => std::str::from_utf8(bytes).ok(),
Self::String(string) => Some(string),
_ => None,
}
}
#[must_use]
pub fn as_bytes(&self) -> Option<&[u8]> {
match self {
Self::Bytes(bytes) => Some(bytes),
Self::String(string) => Some(string.as_bytes()),
_ => None,
}
}
#[must_use]
pub fn values(&self) -> SequenceIter<'_> {
match self {
Self::Sequence(sequence) => SequenceIter::Sequence(sequence.iter()),
Self::Mappings(mappings) => SequenceIter::Mappings(mappings.iter()),
_ => SequenceIter::Sequence([].iter()),
}
}
#[must_use]
pub fn mappings(&self) -> std::slice::Iter<'_, (Self, Self)> {
match self {
Self::Mappings(mappings) => mappings.iter(),
_ => [].iter(),
}
}
pub fn into_static(self) -> Value<'static> {
match self {
Self::None => Value::None,
Self::Unit => Value::Unit,
Self::Bool(value) => Value::Bool(value),
Self::Integer(value) => Value::Integer(value),
Self::Float(value) => Value::Float(value),
Self::Bytes(Cow::Owned(value)) => Value::Bytes(Cow::Owned(value)),
Self::Bytes(Cow::Borrowed(value)) => Value::Bytes(Cow::Owned(value.to_vec())),
Self::String(Cow::Owned(value)) => Value::String(Cow::Owned(value)),
Self::String(Cow::Borrowed(value)) => Value::String(Cow::Owned(value.to_string())),
Self::Sequence(value) => {
Value::Sequence(value.into_iter().map(Value::into_static).collect())
}
Self::Mappings(value) => Value::Mappings(
value
.into_iter()
.map(|(k, v)| (k.into_static(), v.into_static()))
.collect(),
),
}
}
}
impl<'a> Serialize for Value<'a> {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
match self {
Value::None => serializer.serialize_none(),
Value::Unit => serializer.serialize_unit(),
Value::Bool(value) => serializer.serialize_bool(*value),
Value::Integer(integer) => match integer.0 {
InnerInteger::I8(value) => serializer.serialize_i8(value),
InnerInteger::I16(value) => serializer.serialize_i16(value),
InnerInteger::I32(value) => serializer.serialize_i32(value),
InnerInteger::I64(value) => serializer.serialize_i64(value),
InnerInteger::I128(value) => serializer.serialize_i128(value),
InnerInteger::U8(value) => serializer.serialize_u8(value),
InnerInteger::U16(value) => serializer.serialize_u16(value),
InnerInteger::U32(value) => serializer.serialize_u32(value),
InnerInteger::U64(value) => serializer.serialize_u64(value),
InnerInteger::U128(value) => serializer.serialize_u128(value),
},
Value::Float(value) => match value.0 {
InnerFloat::F64(value) => serializer.serialize_f64(value),
InnerFloat::F32(value) => serializer.serialize_f32(value),
},
Value::Bytes(value) => serializer.serialize_bytes(value),
Value::String(value) => serializer.serialize_str(value),
Value::Sequence(values) => {
let mut seq = serializer.serialize_seq(Some(values.len()))?;
for value in values {
seq.serialize_element(value)?;
}
seq.end()
}
Value::Mappings(keys_and_values) => {
let mut map = serializer.serialize_map(Some(keys_and_values.len()))?;
for (key, value) in keys_and_values {
map.serialize_entry(key, value)?;
}
map.end()
}
}
}
}
impl<'de: 'a, 'a> Deserialize<'de> for Value<'a> {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
deserializer.deserialize_any(ValueVisitor::default())
}
}
#[derive(Default)]
struct ValueVisitor<'a>(PhantomData<&'a ()>);
impl<'de: 'a, 'a> Visitor<'de> for ValueVisitor<'a> {
type Value = Value<'a>;
fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
formatter.write_str("any value")
}
fn visit_none<E>(self) -> Result<Self::Value, E>
where
E: serde::de::Error,
{
Ok(Value::None)
}
fn visit_bool<E>(self, v: bool) -> Result<Self::Value, E>
where
E: serde::de::Error,
{
Ok(Value::Bool(v))
}
fn visit_i8<E>(self, v: i8) -> Result<Self::Value, E>
where
E: serde::de::Error,
{
Ok(Value::Integer(Integer::from(v)))
}
fn visit_i32<E>(self, v: i32) -> Result<Self::Value, E>
where
E: serde::de::Error,
{
Ok(Value::Integer(Integer::from(v)))
}
fn visit_i16<E>(self, v: i16) -> Result<Self::Value, E>
where
E: serde::de::Error,
{
Ok(Value::Integer(Integer::from(v)))
}
fn visit_i64<E>(self, v: i64) -> Result<Self::Value, E>
where
E: serde::de::Error,
{
Ok(Value::Integer(Integer::from(v)))
}
fn visit_i128<E>(self, v: i128) -> Result<Self::Value, E>
where
E: serde::de::Error,
{
Ok(Value::Integer(Integer::from(v)))
}
fn visit_u8<E>(self, v: u8) -> Result<Self::Value, E>
where
E: serde::de::Error,
{
Ok(Value::Integer(Integer::from(v)))
}
fn visit_u16<E>(self, v: u16) -> Result<Self::Value, E>
where
E: serde::de::Error,
{
Ok(Value::Integer(Integer::from(v)))
}
fn visit_u32<E>(self, v: u32) -> Result<Self::Value, E>
where
E: serde::de::Error,
{
Ok(Value::Integer(Integer::from(v)))
}
fn visit_u64<E>(self, v: u64) -> Result<Self::Value, E>
where
E: serde::de::Error,
{
Ok(Value::Integer(Integer::from(v)))
}
fn visit_u128<E>(self, v: u128) -> Result<Self::Value, E>
where
E: serde::de::Error,
{
Ok(Value::Integer(Integer::from(v)))
}
fn visit_f32<E>(self, v: f32) -> Result<Self::Value, E>
where
E: serde::de::Error,
{
Ok(Value::Float(Float::from(v)))
}
fn visit_f64<E>(self, v: f64) -> Result<Self::Value, E>
where
E: serde::de::Error,
{
Ok(Value::Float(Float::from(v)))
}
fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
where
E: serde::de::Error,
{
Ok(Value::String(Cow::Owned(v.to_string())))
}
fn visit_borrowed_str<E>(self, v: &'a str) -> Result<Self::Value, E>
where
E: serde::de::Error,
{
Ok(Value::String(Cow::Borrowed(v)))
}
fn visit_string<E>(self, v: String) -> Result<Self::Value, E>
where
E: serde::de::Error,
{
Ok(Value::String(Cow::Owned(v)))
}
fn visit_bytes<E>(self, v: &[u8]) -> Result<Self::Value, E>
where
E: serde::de::Error,
{
Ok(Value::Bytes(Cow::Owned(v.to_vec())))
}
fn visit_borrowed_bytes<E>(self, v: &'a [u8]) -> Result<Self::Value, E>
where
E: serde::de::Error,
{
Ok(Value::Bytes(Cow::Borrowed(v)))
}
fn visit_byte_buf<E>(self, v: Vec<u8>) -> Result<Self::Value, E>
where
E: serde::de::Error,
{
Ok(Value::Bytes(Cow::Owned(v)))
}
fn visit_some<D>(self, deserializer: D) -> Result<Self::Value, D::Error>
where
D: serde::Deserializer<'de>,
{
deserializer.deserialize_any(Self::default())
}
fn visit_unit<E>(self) -> Result<Self::Value, E>
where
E: serde::de::Error,
{
Ok(Value::Unit)
}
fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
where
A: serde::de::SeqAccess<'de>,
{
let mut values = if let Some(hint) = seq.size_hint() {
Vec::with_capacity(hint)
} else {
Vec::new()
};
while let Some(value) = seq.next_element()? {
values.push(value);
}
Ok(Value::Sequence(values))
}
fn visit_map<A>(self, mut map: A) -> Result<Self::Value, A::Error>
where
A: serde::de::MapAccess<'de>,
{
let mut values = if let Some(hint) = map.size_hint() {
Vec::with_capacity(hint)
} else {
Vec::new()
};
while let Some(value) = map.next_entry()? {
values.push(value);
}
Ok(Value::Mappings(values))
}
}
impl<'a> From<Option<Value<'a>>> for Value<'a> {
fn from(value: Option<Value<'a>>) -> Self {
if let Some(value) = value {
value
} else {
Value::None
}
}
}
impl<'a> From<()> for Value<'a> {
fn from(_: ()) -> Self {
Value::Unit
}
}
impl<'a> From<bool> for Value<'a> {
fn from(value: bool) -> Self {
Value::Bool(value)
}
}
macro_rules! define_value_from_primitive {
($container:ident, $variant:ident, $primitive:ty) => {
impl<'a> From<$primitive> for Value<'a> {
fn from(value: $primitive) -> Self {
Self::$container($container::from(value))
}
}
};
}
define_value_from_primitive!(Integer, U8, u8);
define_value_from_primitive!(Integer, U16, u16);
define_value_from_primitive!(Integer, U32, u32);
define_value_from_primitive!(Integer, U64, u64);
define_value_from_primitive!(Integer, U128, u128);
define_value_from_primitive!(Integer, I8, i8);
define_value_from_primitive!(Integer, I16, i16);
define_value_from_primitive!(Integer, I32, i32);
define_value_from_primitive!(Integer, I64, i64);
define_value_from_primitive!(Integer, I128, i128);
define_value_from_primitive!(Float, F32, f32);
define_value_from_primitive!(Float, F64, f64);
impl<'a> From<&'a [u8]> for Value<'a> {
fn from(bytes: &'a [u8]) -> Self {
Self::Bytes(Cow::Borrowed(bytes))
}
}
impl<'a> From<Vec<u8>> for Value<'a> {
fn from(bytes: Vec<u8>) -> Self {
Self::Bytes(Cow::Owned(bytes))
}
}
impl<'a, const N: usize> From<&'a [u8; N]> for Value<'a> {
fn from(bytes: &'a [u8; N]) -> Self {
Self::Bytes(Cow::Borrowed(bytes))
}
}
impl<'a> From<&'a str> for Value<'a> {
fn from(string: &'a str) -> Self {
Self::String(Cow::Borrowed(string))
}
}
impl<'a> From<String> for Value<'a> {
fn from(string: String) -> Self {
Self::String(Cow::Owned(string))
}
}
impl<'a> From<Vec<Value<'a>>> for Value<'a> {
fn from(value: Vec<Value<'a>>) -> Self {
Self::Sequence(value)
}
}
impl<'a> From<Vec<(Value<'a>, Value<'a>)>> for Value<'a> {
fn from(value: Vec<(Value<'a>, Value<'a>)>) -> Self {
Self::Mappings(value)
}
}
pub enum SequenceIter<'a> {
Sequence(std::slice::Iter<'a, Value<'a>>),
Mappings(std::slice::Iter<'a, (Value<'a>, Value<'a>)>),
}
impl<'a> Iterator for SequenceIter<'a> {
type Item = &'a Value<'a>;
fn next(&mut self) -> Option<Self::Item> {
match self {
SequenceIter::Sequence(sequence) => sequence.next(),
SequenceIter::Mappings(mappings) => mappings.next().map(|(_k, v)| v),
}
}
}
#[test]
#[allow(clippy::cognitive_complexity)]
fn value_display_tests() {
assert_eq!(Value::None.to_string(), "None");
assert_eq!(Value::Unit.to_string(), "()");
assert_eq!(Value::Bool(false).to_string(), "false");
assert_eq!(Value::Bool(true).to_string(), "true");
assert_eq!(Value::from(1_u8).to_string(), "1");
assert_eq!(Value::from(1_u16).to_string(), "1");
assert_eq!(Value::from(1_u32).to_string(), "1");
assert_eq!(Value::from(1_u64).to_string(), "1");
assert_eq!(Value::from(1_u128).to_string(), "1");
assert_eq!(Value::from(1_i8).to_string(), "1");
assert_eq!(Value::from(1_i16).to_string(), "1");
assert_eq!(Value::from(1_i32).to_string(), "1");
assert_eq!(Value::from(1_i64).to_string(), "1");
assert_eq!(Value::from(1_i128).to_string(), "1");
assert_eq!(Value::from(1.1_f32).to_string(), "1.1");
assert_eq!(Value::from(1.1_f64).to_string(), "1.1");
assert_eq!(Value::from(b"\xFE\xED\xD0\xD0").to_string(), "0xfeedd0d0");
assert_eq!(
Value::from(b"\xFE\xED\xD0\xD0\xDE\xAD\xBE\xEF").to_string(),
"0xfeedd0d0_deadbeef"
);
assert_eq!(Value::from("hello world").to_string(), "hello world");
assert_eq!(
Value::from_sequence(Vec::<Value<'_>>::new()).to_string(),
"[]"
);
assert_eq!(
Value::from_sequence(vec![Value::None]).to_string(),
"[None]"
);
assert_eq!(
Value::from_sequence(vec![Value::None, Value::Unit]).to_string(),
"[None, ()]"
);
assert_eq!(
Value::from_mappings(Vec::<(Value<'_>, Value<'_>)>::new()).to_string(),
"{}"
);
assert_eq!(
Value::from_mappings(vec![(Value::from(0_u8), Value::None)]).to_string(),
"{0: None}"
);
assert_eq!(
Value::from_mappings(vec![
(Value::from(0_u8), Value::None),
(Value::from(1_u8), Value::Unit)
])
.to_string(),
"{0: None, 1: ()}"
);
}
#[test]
#[allow(clippy::manual_assert)] fn value_as_float_tests() {
approx::assert_relative_eq!(
Value::from(u8::MAX)
.as_float()
.expect("u8 conversion failed")
.as_f32()
.expect("f32 conversion failed"),
255_f32,
);
approx::assert_relative_eq!(
Value::from(u32::MAX)
.as_float()
.expect("u32 conversion failed")
.as_f64(),
4_294_967_295_f64,
);
assert!(Value::from(u32::MAX)
.as_float()
.expect("u32 conversion failed")
.as_f32()
.is_err());
approx::assert_relative_eq!(Value::from(0_f64).as_float().unwrap().as_f32().unwrap(), 0.);
}
#[test]
fn value_as_integer_tests() {
macro_rules! test_signed {
($primitive:ty, $signed_method:ident, $unsigned:ty, $unsigned_method:ident, $float:ty) => {
assert_eq!(
Value::from(<$float>::from(<$primitive>::MAX))
.as_integer()
.expect("integer conversion failed")
.$signed_method()
.unwrap(),
<$primitive>::MAX,
);
assert_eq!(
Value::from(<$float>::from(<$primitive>::MIN))
.as_integer()
.expect("integer conversion failed")
.$signed_method()
.unwrap(),
<$primitive>::MIN,
);
assert_eq!(
Value::from(<$float>::from(<$primitive>::MAX))
.as_integer()
.expect("integer conversion failed")
.$unsigned_method()
.unwrap(),
<$unsigned>::try_from(<$primitive>::MAX).unwrap(),
);
};
}
test_signed!(i8, as_i8, u8, as_u8, f32);
test_signed!(i16, as_i16, u16, as_u16, f32);
test_signed!(i32, as_i32, u32, as_u32, f64);
macro_rules! test_unsigned {
($primitive:ty, $unsigned_method:ident, $signed:ty, $signed_method:ident, $float:ty) => {
assert_eq!(
Value::from(<$float>::from(<$primitive>::MAX))
.as_integer()
.expect("integer conversion failed")
.$unsigned_method()
.unwrap(),
<$primitive>::MAX,
);
assert!(Value::from(<$float>::from(<$primitive>::MAX))
.as_integer()
.expect("integer conversion failed")
.$signed_method()
.is_err());
};
}
test_unsigned!(u8, as_u8, i8, as_i8, f32);
test_unsigned!(u16, as_u16, i16, as_i16, f32);
test_unsigned!(u32, as_u32, i32, as_i32, f64);
}