use crate::collections::HashMap;
use crate::runtime::{
Bytes, FromValue, Object, Shared, StaticString, ToValue, Tuple, TypeInfo, Value, Vec, VmError,
VmErrorKind,
};
use serde::{Deserialize, Serialize};
use std::sync::Arc;
use std::vec;
#[derive(Debug, Clone, Deserialize, Serialize)]
pub enum ConstValue {
Unit,
Byte(u8),
Char(char),
Bool(bool),
Integer(i64),
Float(f64),
String(String),
StaticString(Arc<StaticString>),
Bytes(Bytes),
Vec(vec::Vec<ConstValue>),
Tuple(Box<[ConstValue]>),
Object(HashMap<String, ConstValue>),
Option(Option<Box<ConstValue>>),
}
impl ConstValue {
pub fn into_value(self) -> Value {
match self {
Self::Unit => Value::Unit,
Self::Byte(b) => Value::Byte(b),
Self::Char(c) => Value::Char(c),
Self::Bool(b) => Value::Bool(b),
Self::Integer(n) => Value::Integer(n),
Self::Float(n) => Value::Float(n),
Self::String(s) => Value::String(Shared::new(s)),
Self::StaticString(s) => Value::StaticString(s),
Self::Bytes(b) => Value::Bytes(Shared::new(b)),
Self::Option(option) => {
Value::Option(Shared::new(option.map(|some| some.into_value())))
}
Self::Vec(vec) => {
let mut v = Vec::with_capacity(vec.len());
for value in vec {
v.push(value.into_value());
}
Value::Vec(Shared::new(v))
}
Self::Tuple(tuple) => {
let mut t = vec::Vec::with_capacity(tuple.len());
for value in vec::Vec::from(tuple) {
t.push(value.into_value());
}
Value::Tuple(Shared::new(Tuple::from(t)))
}
Self::Object(object) => {
let mut o = Object::with_capacity(object.len());
for (key, value) in object {
o.insert(key, value.into_value());
}
Value::Object(Shared::new(o))
}
}
}
pub fn into_bool(self) -> Result<bool, Self> {
match self {
Self::Bool(value) => Ok(value),
value => Err(value),
}
}
pub fn type_info(&self) -> TypeInfo {
match self {
Self::Unit => TypeInfo::StaticType(crate::runtime::UNIT_TYPE),
Self::Byte(..) => TypeInfo::StaticType(crate::runtime::BYTE_TYPE),
Self::Char(..) => TypeInfo::StaticType(crate::runtime::CHAR_TYPE),
Self::Bool(..) => TypeInfo::StaticType(crate::runtime::BOOL_TYPE),
Self::String(..) => TypeInfo::StaticType(crate::runtime::STRING_TYPE),
Self::StaticString(..) => TypeInfo::StaticType(crate::runtime::STRING_TYPE),
Self::Bytes(..) => TypeInfo::StaticType(crate::runtime::BYTES_TYPE),
Self::Integer(..) => TypeInfo::StaticType(crate::runtime::INTEGER_TYPE),
Self::Float(..) => TypeInfo::StaticType(crate::runtime::FLOAT_TYPE),
Self::Vec(..) => TypeInfo::StaticType(crate::runtime::VEC_TYPE),
Self::Tuple(..) => TypeInfo::StaticType(crate::runtime::TUPLE_TYPE),
Self::Object(..) => TypeInfo::StaticType(crate::runtime::OBJECT_TYPE),
Self::Option(..) => TypeInfo::StaticType(crate::runtime::OPTION_TYPE),
}
}
}
impl FromValue for ConstValue {
fn from_value(value: Value) -> Result<Self, VmError> {
Ok(match value {
Value::Unit => Self::Unit,
Value::Byte(b) => Self::Byte(b),
Value::Char(c) => Self::Char(c),
Value::Bool(b) => Self::Bool(b),
Value::Integer(n) => Self::Integer(n),
Value::Float(f) => Self::Float(f),
Value::String(s) => {
let s = s.take()?;
Self::String(s)
}
Value::StaticString(s) => Self::StaticString(s),
Value::Option(option) => Self::Option(match option.take()? {
Some(some) => Some(Box::new(Self::from_value(some)?)),
None => None,
}),
Value::Bytes(b) => {
let b = b.take()?;
Self::Bytes(b)
}
Value::Vec(vec) => {
let vec = vec.take()?;
let mut const_vec = vec::Vec::with_capacity(vec.len());
for value in vec {
const_vec.push(Self::from_value(value)?);
}
Self::Vec(const_vec)
}
Value::Tuple(tuple) => {
let tuple = tuple.take()?;
let mut const_tuple = vec::Vec::with_capacity(tuple.len());
for value in vec::Vec::from(tuple.into_inner()) {
const_tuple.push(Self::from_value(value)?);
}
Self::Tuple(const_tuple.into_boxed_slice())
}
Value::Object(object) => {
let object = object.take()?;
let mut const_object = HashMap::with_capacity(object.len());
for (key, value) in object {
const_object.insert(key, Self::from_value(value)?);
}
Self::Object(const_object)
}
value => {
return Err(VmError::from(VmErrorKind::ConstNotSupported {
actual: value.type_info()?,
}))
}
})
}
}
impl ToValue for ConstValue {
fn to_value(self) -> Result<Value, VmError> {
Ok(ConstValue::into_value(self))
}
}