use alloc::boxed::Box;
use alloc::collections::{BTreeMap, BTreeSet};
use alloc::string::String;
use alloc::vec::Vec;
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum ValueType {
Bool,
U8,
U16,
U32,
U64,
S8,
S16,
S32,
S64,
F32,
F64,
Char,
String,
List(Box<ValueType>),
Option(Box<ValueType>),
Result {
ok: Box<ValueType>,
err: Box<ValueType>,
},
Record(String), Variant(String), Tuple(Vec<ValueType>),
Flags,
}
impl core::fmt::Display for ValueType {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
match self {
ValueType::Bool => write!(f, "bool"),
ValueType::U8 => write!(f, "u8"),
ValueType::U16 => write!(f, "u16"),
ValueType::U32 => write!(f, "u32"),
ValueType::U64 => write!(f, "u64"),
ValueType::S8 => write!(f, "s8"),
ValueType::S16 => write!(f, "s16"),
ValueType::S32 => write!(f, "s32"),
ValueType::S64 => write!(f, "s64"),
ValueType::F32 => write!(f, "f32"),
ValueType::F64 => write!(f, "f64"),
ValueType::Char => write!(f, "char"),
ValueType::String => write!(f, "string"),
ValueType::List(inner) => write!(f, "list<{}>", inner),
ValueType::Option(inner) => write!(f, "option<{}>", inner),
ValueType::Result { ok, err } => write!(f, "result<{}, {}>", ok, err),
ValueType::Record(name) => write!(f, "{}", name),
ValueType::Variant(name) => write!(f, "{}", name),
ValueType::Tuple(types) => {
write!(f, "tuple<")?;
for (i, t) in types.iter().enumerate() {
if i > 0 {
write!(f, ", ")?;
}
write!(f, "{}", t)?;
}
write!(f, ">")
}
ValueType::Flags => write!(f, "flags"),
}
}
}
#[derive(Debug, Clone, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum Value {
Bool(bool),
U8(u8),
U16(u16),
U32(u32),
U64(u64),
S8(i8),
S16(i16),
S32(i32),
S64(i64),
F32(f32),
F64(f64),
Char(char),
String(String),
List {
elem_type: ValueType,
items: Vec<Value>,
},
Option {
inner_type: ValueType,
value: Option<Box<Value>>,
},
Result {
ok_type: ValueType,
err_type: ValueType,
value: core::result::Result<Box<Value>, Box<Value>>,
},
Record {
type_name: String,
fields: Vec<(String, Value)>,
},
Variant {
type_name: String,
case_name: String,
tag: usize,
payload: Vec<Value>,
},
Tuple(Vec<Value>),
Flags(u64),
}
impl Value {
pub fn sym(s: impl Into<String>) -> Self {
Value::Variant {
type_name: String::from("expr"),
case_name: String::from("sym"),
tag: 0,
payload: alloc::vec![Value::String(s.into())],
}
}
pub fn num(n: i64) -> Self {
Value::Variant {
type_name: String::from("expr"),
case_name: String::from("num"),
tag: 1,
payload: alloc::vec![Value::S64(n)],
}
}
pub fn lst(items: Vec<Value>) -> Self {
Value::Variant {
type_name: String::from("expr"),
case_name: String::from("lst"),
tag: 4,
payload: alloc::vec![Value::List {
elem_type: ValueType::Variant(String::from("expr")),
items,
}],
}
}
pub fn infer_type(&self) -> ValueType {
match self {
Value::Bool(_) => ValueType::Bool,
Value::U8(_) => ValueType::U8,
Value::U16(_) => ValueType::U16,
Value::U32(_) => ValueType::U32,
Value::U64(_) => ValueType::U64,
Value::S8(_) => ValueType::S8,
Value::S16(_) => ValueType::S16,
Value::S32(_) => ValueType::S32,
Value::S64(_) => ValueType::S64,
Value::F32(_) => ValueType::F32,
Value::F64(_) => ValueType::F64,
Value::Char(_) => ValueType::Char,
Value::String(_) => ValueType::String,
Value::List { elem_type, .. } => ValueType::List(Box::new(elem_type.clone())),
Value::Option { inner_type, .. } => ValueType::Option(Box::new(inner_type.clone())),
Value::Result {
ok_type, err_type, ..
} => ValueType::Result {
ok: Box::new(ok_type.clone()),
err: Box::new(err_type.clone()),
},
Value::Record { type_name, .. } => ValueType::Record(type_name.clone()),
Value::Variant { type_name, .. } => ValueType::Variant(type_name.clone()),
Value::Tuple(items) => ValueType::Tuple(items.iter().map(|v| v.infer_type()).collect()),
Value::Flags(_) => ValueType::Flags,
}
}
}
impl core::fmt::Display for Value {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
match self {
Value::Bool(v) => write!(f, "{}", v),
Value::U8(v) => write!(f, "{}", v),
Value::U16(v) => write!(f, "{}", v),
Value::U32(v) => write!(f, "{}", v),
Value::U64(v) => write!(f, "{}", v),
Value::S8(v) => write!(f, "{}", v),
Value::S16(v) => write!(f, "{}", v),
Value::S32(v) => write!(f, "{}", v),
Value::S64(v) => write!(f, "{}", v),
Value::F32(v) => write!(f, "{}", v),
Value::F64(v) => write!(f, "{}", v),
Value::Char(v) => write!(f, "'{}'", v),
Value::String(v) => write!(f, "\"{}\"", v),
Value::Tuple(items) => {
write!(f, "(")?;
for (i, item) in items.iter().enumerate() {
if i > 0 {
write!(f, ", ")?;
}
write!(f, "{}", item)?;
}
write!(f, ")")
}
Value::List { items, .. } => {
write!(f, "[")?;
for (i, item) in items.iter().enumerate() {
if i > 0 {
write!(f, ", ")?;
}
if i >= 10 {
write!(f, "... ({} more)", items.len() - 10)?;
break;
}
write!(f, "{}", item)?;
}
write!(f, "]")
}
Value::Option { value, .. } => match value {
Some(v) => write!(f, "some({})", v),
None => write!(f, "none"),
},
Value::Result { value, .. } => match value {
Ok(v) => write!(f, "ok({})", v),
Err(v) => write!(f, "err({})", v),
},
Value::Record { type_name, fields } => {
if type_name.is_empty() {
write!(f, "{{")?;
} else {
write!(f, "{}{{", type_name)?;
}
for (i, (name, value)) in fields.iter().enumerate() {
if i > 0 {
write!(f, ", ")?;
}
write!(f, "{}: {}", name, value)?;
}
write!(f, "}}")
}
Value::Variant {
type_name,
case_name,
payload,
..
} => {
if !type_name.is_empty() {
write!(f, "{}::", type_name)?;
}
write!(f, "{}", case_name)?;
if !payload.is_empty() {
write!(f, "(")?;
for (i, v) in payload.iter().enumerate() {
if i > 0 {
write!(f, ", ")?;
}
write!(f, "{}", v)?;
}
write!(f, ")")?;
}
Ok(())
}
Value::Flags(v) => write!(f, "flags(0x{:x})", v),
}
}
}
impl From<bool> for Value {
fn from(v: bool) -> Self {
Value::Bool(v)
}
}
impl From<u8> for Value {
fn from(v: u8) -> Self {
Value::U8(v)
}
}
impl From<u16> for Value {
fn from(v: u16) -> Self {
Value::U16(v)
}
}
impl From<u32> for Value {
fn from(v: u32) -> Self {
Value::U32(v)
}
}
impl From<u64> for Value {
fn from(v: u64) -> Self {
Value::U64(v)
}
}
impl From<i8> for Value {
fn from(v: i8) -> Self {
Value::S8(v)
}
}
impl From<i16> for Value {
fn from(v: i16) -> Self {
Value::S16(v)
}
}
impl From<i32> for Value {
fn from(v: i32) -> Self {
Value::S32(v)
}
}
impl From<i64> for Value {
fn from(v: i64) -> Self {
Value::S64(v)
}
}
impl From<f32> for Value {
fn from(v: f32) -> Self {
Value::F32(v)
}
}
impl From<f64> for Value {
fn from(v: f64) -> Self {
Value::F64(v)
}
}
impl From<char> for Value {
fn from(v: char) -> Self {
Value::Char(v)
}
}
impl From<String> for Value {
fn from(v: String) -> Self {
Value::String(v)
}
}
impl From<&str> for Value {
fn from(v: &str) -> Self {
Value::String(String::from(v))
}
}
impl<T: Into<Value>> From<Vec<T>> for Value {
fn from(v: Vec<T>) -> Self {
let items: Vec<Value> = v.into_iter().map(Into::into).collect();
let elem_type = items
.first()
.map(|v| v.infer_type())
.unwrap_or(ValueType::S32);
Value::List { elem_type, items }
}
}
impl<T: Into<Value>, const N: usize> From<[T; N]> for Value {
fn from(v: [T; N]) -> Self {
let items: Vec<Value> = v.into_iter().map(Into::into).collect();
let elem_type = items
.first()
.map(|v| v.infer_type())
.unwrap_or(ValueType::S32);
Value::List { elem_type, items }
}
}
impl<T: TryFrom<Value, Error = ConversionError>, const N: usize> TryFrom<Value> for [T; N] {
type Error = ConversionError;
fn try_from(v: Value) -> Result<Self, Self::Error> {
match v {
Value::List { items, .. } => {
if items.len() != N {
return Err(ConversionError::WrongFieldCount {
expected: N,
got: items.len(),
});
}
let vec: Vec<T> = items
.into_iter()
.enumerate()
.map(|(i, item)| {
T::try_from(item).map_err(|e| ConversionError::IndexError(i, Box::new(e)))
})
.collect::<Result<Vec<T>, _>>()?;
vec.try_into().map_err(|_| {
ConversionError::ExpectedList(String::from("array conversion failed"))
})
}
other => Err(ConversionError::ExpectedList(format!("{:?}", other))),
}
}
}
impl<T: Into<Value>> From<Option<T>> for Value {
fn from(v: Option<T>) -> Self {
let (inner_type, value) = match v {
Some(x) => {
let val: Value = x.into();
let ty = val.infer_type();
(ty, Some(Box::new(val)))
}
None => (ValueType::S32, None), };
Value::Option { inner_type, value }
}
}
impl<T: Into<Value>> From<Box<T>> for Value {
fn from(v: Box<T>) -> Self {
(*v).into()
}
}
use crate::ConversionError;
impl TryFrom<Value> for bool {
type Error = ConversionError;
fn try_from(v: Value) -> Result<Self, Self::Error> {
match v {
Value::Bool(x) => Ok(x),
other => Err(ConversionError::TypeMismatch {
expected: String::from("bool"),
got: format!("{:?}", other),
}),
}
}
}
impl TryFrom<Value> for u8 {
type Error = ConversionError;
fn try_from(v: Value) -> Result<Self, Self::Error> {
match v {
Value::U8(x) => Ok(x),
other => Err(ConversionError::TypeMismatch {
expected: String::from("u8"),
got: format!("{:?}", other),
}),
}
}
}
impl TryFrom<Value> for u16 {
type Error = ConversionError;
fn try_from(v: Value) -> Result<Self, Self::Error> {
match v {
Value::U16(x) => Ok(x),
other => Err(ConversionError::TypeMismatch {
expected: String::from("u16"),
got: format!("{:?}", other),
}),
}
}
}
impl TryFrom<Value> for u32 {
type Error = ConversionError;
fn try_from(v: Value) -> Result<Self, Self::Error> {
match v {
Value::U32(x) => Ok(x),
other => Err(ConversionError::TypeMismatch {
expected: String::from("u32"),
got: format!("{:?}", other),
}),
}
}
}
impl TryFrom<Value> for u64 {
type Error = ConversionError;
fn try_from(v: Value) -> Result<Self, Self::Error> {
match v {
Value::U64(x) => Ok(x),
other => Err(ConversionError::TypeMismatch {
expected: String::from("u64"),
got: format!("{:?}", other),
}),
}
}
}
impl TryFrom<Value> for i8 {
type Error = ConversionError;
fn try_from(v: Value) -> Result<Self, Self::Error> {
match v {
Value::S8(x) => Ok(x),
other => Err(ConversionError::TypeMismatch {
expected: String::from("i8"),
got: format!("{:?}", other),
}),
}
}
}
impl TryFrom<Value> for i16 {
type Error = ConversionError;
fn try_from(v: Value) -> Result<Self, Self::Error> {
match v {
Value::S16(x) => Ok(x),
other => Err(ConversionError::TypeMismatch {
expected: String::from("i16"),
got: format!("{:?}", other),
}),
}
}
}
impl TryFrom<Value> for i32 {
type Error = ConversionError;
fn try_from(v: Value) -> Result<Self, Self::Error> {
match v {
Value::S32(x) => Ok(x),
other => Err(ConversionError::TypeMismatch {
expected: String::from("i32"),
got: format!("{:?}", other),
}),
}
}
}
impl TryFrom<Value> for i64 {
type Error = ConversionError;
fn try_from(v: Value) -> Result<Self, Self::Error> {
match v {
Value::S64(x) => Ok(x),
other => Err(ConversionError::TypeMismatch {
expected: String::from("i64"),
got: format!("{:?}", other),
}),
}
}
}
impl TryFrom<Value> for f32 {
type Error = ConversionError;
fn try_from(v: Value) -> Result<Self, Self::Error> {
match v {
Value::F32(x) => Ok(x),
other => Err(ConversionError::TypeMismatch {
expected: String::from("f32"),
got: format!("{:?}", other),
}),
}
}
}
impl TryFrom<Value> for f64 {
type Error = ConversionError;
fn try_from(v: Value) -> Result<Self, Self::Error> {
match v {
Value::F64(x) => Ok(x),
other => Err(ConversionError::TypeMismatch {
expected: String::from("f64"),
got: format!("{:?}", other),
}),
}
}
}
impl TryFrom<Value> for char {
type Error = ConversionError;
fn try_from(v: Value) -> Result<Self, Self::Error> {
match v {
Value::Char(x) => Ok(x),
other => Err(ConversionError::TypeMismatch {
expected: String::from("char"),
got: format!("{:?}", other),
}),
}
}
}
impl TryFrom<Value> for String {
type Error = ConversionError;
fn try_from(v: Value) -> Result<Self, Self::Error> {
match v {
Value::String(x) => Ok(x),
other => Err(ConversionError::TypeMismatch {
expected: String::from("String"),
got: format!("{:?}", other),
}),
}
}
}
impl<T: TryFrom<Value, Error = ConversionError>> TryFrom<Value> for Vec<T> {
type Error = ConversionError;
fn try_from(v: Value) -> Result<Self, Self::Error> {
match v {
Value::List { items, .. } => items
.into_iter()
.enumerate()
.map(|(i, item)| {
T::try_from(item).map_err(|e| ConversionError::IndexError(i, Box::new(e)))
})
.collect(),
other => Err(ConversionError::ExpectedList(format!("{:?}", other))),
}
}
}
impl<T: Into<Value> + Ord> From<BTreeSet<T>> for Value {
fn from(v: BTreeSet<T>) -> Self {
let items: Vec<Value> = v.into_iter().map(Into::into).collect();
let elem_type = items
.first()
.map(|v| v.infer_type())
.unwrap_or(ValueType::S32);
Value::List { elem_type, items }
}
}
impl<T: TryFrom<Value, Error = ConversionError> + Ord> TryFrom<Value> for BTreeSet<T> {
type Error = ConversionError;
fn try_from(v: Value) -> Result<Self, Self::Error> {
match v {
Value::List { items, .. } => items
.into_iter()
.enumerate()
.map(|(i, item)| {
T::try_from(item).map_err(|e| ConversionError::IndexError(i, Box::new(e)))
})
.collect(),
other => Err(ConversionError::ExpectedList(format!("{:?}", other))),
}
}
}
impl<K: Into<Value> + Ord, V: Into<Value>> From<BTreeMap<K, V>> for Value {
fn from(v: BTreeMap<K, V>) -> Self {
let items: Vec<Value> = v
.into_iter()
.map(|(k, v)| Value::Tuple(Vec::from([k.into(), v.into()])))
.collect();
let elem_type = items
.first()
.map(|v| v.infer_type())
.unwrap_or(ValueType::S32);
Value::List { elem_type, items }
}
}
impl<
K: TryFrom<Value, Error = ConversionError> + Ord,
V: TryFrom<Value, Error = ConversionError>,
> TryFrom<Value> for BTreeMap<K, V>
{
type Error = ConversionError;
fn try_from(v: Value) -> Result<Self, Self::Error> {
match v {
Value::List { items, .. } => items
.into_iter()
.enumerate()
.map(|(i, item)| match item {
Value::Tuple(mut fields) if fields.len() == 2 => {
let v_val = fields.pop().unwrap();
let k_val = fields.pop().unwrap();
let k = K::try_from(k_val)
.map_err(|e| ConversionError::IndexError(i, Box::new(e)))?;
let v = V::try_from(v_val)
.map_err(|e| ConversionError::IndexError(i, Box::new(e)))?;
Ok((k, v))
}
other => Err(ConversionError::ExpectedTuple(format!("{:?}", other))),
})
.collect(),
other => Err(ConversionError::ExpectedList(format!("{:?}", other))),
}
}
}
pub trait FromValue: Sized {
fn from_value(v: Value) -> Result<Self, ConversionError>;
}
impl<T: TryFrom<Value, Error = ConversionError>> FromValue for T {
fn from_value(v: Value) -> Result<Self, ConversionError> {
T::try_from(v)
}
}
impl FromValue for Value {
fn from_value(v: Value) -> Result<Self, ConversionError> {
Ok(v)
}
}
impl<T: FromValue> FromValue for Option<T> {
fn from_value(v: Value) -> Result<Self, ConversionError> {
match v {
Value::Option { value: None, .. } => Ok(None),
Value::Option {
value: Some(inner), ..
} => {
let value = T::from_value(*inner)?;
Ok(Some(value))
}
other => Err(ConversionError::ExpectedOption(format!("{:?}", other))),
}
}
}
impl<T: FromValue, E: FromValue> FromValue for core::result::Result<T, E> {
fn from_value(v: Value) -> Result<Self, ConversionError> {
match v {
Value::Result {
value: Ok(inner), ..
} => {
let value = T::from_value(*inner)
.map_err(|e| ConversionError::PayloadError(Box::new(e)))?;
Ok(Ok(value))
}
Value::Result {
value: Err(inner), ..
} => {
let value = E::from_value(*inner)
.map_err(|e| ConversionError::PayloadError(Box::new(e)))?;
Ok(Err(value))
}
Value::Variant {
tag: 0, payload, ..
} if !payload.is_empty() => {
let value = T::from_value(payload.into_iter().next().unwrap())
.map_err(|e| ConversionError::PayloadError(Box::new(e)))?;
Ok(Ok(value))
}
Value::Variant {
tag: 1, payload, ..
} if !payload.is_empty() => {
let value = E::from_value(payload.into_iter().next().unwrap())
.map_err(|e| ConversionError::PayloadError(Box::new(e)))?;
Ok(Err(value))
}
Value::Variant { tag, .. } => Err(ConversionError::UnknownTag { tag, max: 1 }),
other => Err(ConversionError::ExpectedVariant(format!("{:?}", other))),
}
}
}
impl From<()> for Value {
fn from(_: ()) -> Self {
Value::Tuple(Vec::new())
}
}
impl TryFrom<Value> for () {
type Error = ConversionError;
fn try_from(v: Value) -> Result<Self, Self::Error> {
match v {
Value::Tuple(items) if items.is_empty() => Ok(()),
other => Err(ConversionError::ExpectedTuple(format!("{:?}", other))),
}
}
}
impl<A: Into<Value>> From<(A,)> for Value {
fn from((a,): (A,)) -> Self {
Value::Tuple(alloc::vec![a.into()])
}
}
impl<A: TryFrom<Value, Error = ConversionError>> TryFrom<Value> for (A,) {
type Error = ConversionError;
fn try_from(v: Value) -> Result<Self, Self::Error> {
match v {
Value::Tuple(mut items) if items.len() == 1 => {
let a = A::try_from(items.remove(0))
.map_err(|e| ConversionError::IndexError(0, Box::new(e)))?;
Ok((a,))
}
other => Err(ConversionError::ExpectedTuple(format!("{:?}", other))),
}
}
}
impl<A: Into<Value>, B: Into<Value>> From<(A, B)> for Value {
fn from((a, b): (A, B)) -> Self {
Value::Tuple(alloc::vec![a.into(), b.into()])
}
}
impl<A: TryFrom<Value, Error = ConversionError>, B: TryFrom<Value, Error = ConversionError>>
TryFrom<Value> for (A, B)
{
type Error = ConversionError;
fn try_from(v: Value) -> Result<Self, Self::Error> {
match v {
Value::Tuple(mut items) if items.len() == 2 => {
let b = B::try_from(items.remove(1))
.map_err(|e| ConversionError::IndexError(1, Box::new(e)))?;
let a = A::try_from(items.remove(0))
.map_err(|e| ConversionError::IndexError(0, Box::new(e)))?;
Ok((a, b))
}
other => Err(ConversionError::ExpectedTuple(format!("{:?}", other))),
}
}
}
impl<A: Into<Value>, B: Into<Value>, C: Into<Value>> From<(A, B, C)> for Value {
fn from((a, b, c): (A, B, C)) -> Self {
Value::Tuple(alloc::vec![a.into(), b.into(), c.into()])
}
}
impl<
A: TryFrom<Value, Error = ConversionError>,
B: TryFrom<Value, Error = ConversionError>,
C: TryFrom<Value, Error = ConversionError>,
> TryFrom<Value> for (A, B, C)
{
type Error = ConversionError;
fn try_from(v: Value) -> Result<Self, Self::Error> {
match v {
Value::Tuple(mut items) if items.len() == 3 => {
let c = C::try_from(items.remove(2))
.map_err(|e| ConversionError::IndexError(2, Box::new(e)))?;
let b = B::try_from(items.remove(1))
.map_err(|e| ConversionError::IndexError(1, Box::new(e)))?;
let a = A::try_from(items.remove(0))
.map_err(|e| ConversionError::IndexError(0, Box::new(e)))?;
Ok((a, b, c))
}
other => Err(ConversionError::ExpectedTuple(format!("{:?}", other))),
}
}
}
impl<A: Into<Value>, B: Into<Value>, C: Into<Value>, D: Into<Value>> From<(A, B, C, D)> for Value {
fn from((a, b, c, d): (A, B, C, D)) -> Self {
Value::Tuple(alloc::vec![a.into(), b.into(), c.into(), d.into()])
}
}
impl<
A: TryFrom<Value, Error = ConversionError>,
B: TryFrom<Value, Error = ConversionError>,
C: TryFrom<Value, Error = ConversionError>,
D: TryFrom<Value, Error = ConversionError>,
> TryFrom<Value> for (A, B, C, D)
{
type Error = ConversionError;
fn try_from(v: Value) -> Result<Self, Self::Error> {
match v {
Value::Tuple(mut items) if items.len() == 4 => {
let d = D::try_from(items.remove(3))
.map_err(|e| ConversionError::IndexError(3, Box::new(e)))?;
let c = C::try_from(items.remove(2))
.map_err(|e| ConversionError::IndexError(2, Box::new(e)))?;
let b = B::try_from(items.remove(1))
.map_err(|e| ConversionError::IndexError(1, Box::new(e)))?;
let a = A::try_from(items.remove(0))
.map_err(|e| ConversionError::IndexError(0, Box::new(e)))?;
Ok((a, b, c, d))
}
other => Err(ConversionError::ExpectedTuple(format!("{:?}", other))),
}
}
}
impl<T: Into<Value>, E: Into<Value>> From<core::result::Result<T, E>> for Value {
fn from(r: core::result::Result<T, E>) -> Self {
match r {
Ok(v) => {
let val: Value = v.into();
let ok_type = val.infer_type();
Value::Result {
ok_type,
err_type: ValueType::String, value: Ok(Box::new(val)),
}
}
Err(e) => {
let val: Value = e.into();
let err_type = val.infer_type();
Value::Result {
ok_type: ValueType::S32, err_type,
value: Err(Box::new(val)),
}
}
}
}
}
use alloc::format;