use num_traits::AsPrimitive;
use std::fmt::Write as _;
use std::sync::Arc;
use indexmap::IndexMap;
use parking_lot::Mutex;
use super::bytecode::Const;
use super::native::Native;
use super::numeric::IntWidth;
pub use super::rs_str::RsStr;
pub type List = Arc<Mutex<Vec<Value>>>;
pub type Map = Arc<Mutex<IndexMap<MapKey, Value>>>;
#[derive(Clone, Copy, PartialEq, Eq)]
pub enum MapKind {
Map,
Set,
}
#[derive(Clone, Copy, PartialEq, Eq)]
pub enum CellKind {
Rc,
Arc,
RefCell,
Cell,
Mutex,
TokioMutex,
}
impl CellKind {
pub fn is_shared_pointer(self) -> bool {
matches!(self, CellKind::Rc | CellKind::Arc)
}
}
pub enum ValueRef {
VecElement {
values: List,
index: usize,
},
MapEntry {
map: Map,
key: MapKey,
},
StructField {
data: Arc<StructData>,
slot: usize,
},
CellSlot {
slot: Arc<Mutex<Value>>,
},
Borrowed {
value: Value,
},
}
impl ValueRef {
pub fn vec_element(values: List, index: usize) -> Self {
Self::VecElement { values, index }
}
pub fn map_entry(map: Map, key: MapKey) -> Self {
Self::MapEntry { map, key }
}
pub fn struct_field(data: Arc<StructData>, slot: usize) -> Self {
Self::StructField { data, slot }
}
pub fn cell_slot(slot: Arc<Mutex<Value>>) -> Self {
Self::CellSlot { slot }
}
pub fn borrowed(value: Value) -> Self {
Self::Borrowed { value }
}
pub fn get(&self) -> Option<Value> {
match self {
Self::VecElement { values, index } => values.lock().get(*index).cloned(),
Self::MapEntry { map, key } => map.lock().get(key).cloned(),
Self::StructField { data, slot } => data.values.lock().get(*slot).cloned(),
Self::CellSlot { slot } => Some(slot.lock().clone()),
Self::Borrowed { value } => Some(value.clone()),
}
}
pub fn get_unique(&self) -> Option<Value> {
let unique = |slot: Option<&mut Value>| {
slot.map(|v| {
v.make_unique();
v.clone()
})
};
match self {
Self::VecElement { values, index } => unique(values.lock().get_mut(*index)),
Self::MapEntry { map, key } => unique(map.lock().get_mut(key)),
Self::StructField { data, slot } => unique(data.values.lock().get_mut(*slot)),
Self::CellSlot { slot } => unique(Some(&mut *slot.lock())),
Self::Borrowed { value } => Some(value.clone()),
}
}
pub fn set(&self, value: Value) -> bool {
match self {
Self::VecElement { values, index } => {
let mut values = values.lock();
let Some(slot) = values.get_mut(*index) else {
return false;
};
*slot = value;
true
}
Self::MapEntry { map, key } => {
map.lock().insert(key.clone(), value);
true
}
Self::StructField { data, slot } => {
let mut values = data.values.lock();
let Some(target) = values.get_mut(*slot) else {
return false;
};
*target = value;
true
}
Self::CellSlot { slot } => {
*slot.lock() = value;
true
}
Self::Borrowed { .. } => false,
}
}
}
pub use super::bytecode::StructShape;
pub struct StructData {
pub shape: Arc<StructShape>,
pub values: Mutex<Vec<Value>>,
}
impl StructData {
pub fn name(&self) -> &Arc<str> {
&self.shape.name
}
pub fn get(&self, field: &str) -> Option<Value> {
self.shape
.slot(field)
.map(|i| self.values.lock()[i].clone())
}
pub fn set(&self, field: &str, v: Value) -> bool {
match self.shape.slot(field) {
Some(i) => {
self.values.lock()[i] = v;
true
}
None => false,
}
}
}
#[derive(Clone)]
pub enum Upvalue {
Value(Value),
Mutable(Arc<Mutex<Value>>),
}
impl Upvalue {
pub fn get(&self) -> Value {
match self {
Self::Value(value) => value.clone(),
Self::Mutable(value) => value.lock().clone(),
}
}
pub fn set(&self, value: Value) -> bool {
let Self::Mutable(cell) = self else {
return false;
};
*cell.lock() = value;
true
}
}
pub struct ClosureData {
pub chunk: Arc<super::bytecode::Chunk>,
pub captured: Vec<Upvalue>,
}
#[derive(Clone, Default)]
pub enum Value {
#[default]
Unit,
Bool(bool),
Int(i64),
IntW(i64, IntWidth),
Big(i128, IntWidth),
Float(f64),
F32(f32),
Char(char),
Str(RsStr),
Vec(List),
Map(Map, MapKind),
Tuple(List),
Struct(Arc<StructData>),
Enum {
enum_name: Arc<str>,
variant: Arc<str>,
data: List,
},
Range {
start: i64,
end: i64,
inclusive: bool,
},
Closure(Arc<ClosureData>),
Ref(Arc<ValueRef>),
Cell(CellKind, Arc<Mutex<Value>>),
Native(Arc<Mutex<Native>>),
}
#[derive(Clone, PartialEq, Eq, Hash)]
pub enum MapKey {
Bool(bool),
Int(i64),
Char(char),
Str(RsStr),
}
impl Value {
pub fn str(s: impl Into<RsStr>) -> Value {
Value::Str(s.into())
}
pub fn vec(items: Vec<Value>) -> Value {
Value::Vec(Arc::new(Mutex::new(items)))
}
pub fn tuple(items: Vec<Value>) -> Value {
Value::Tuple(Arc::new(Mutex::new(items)))
}
pub fn map() -> Value {
Value::Map(Arc::new(Mutex::new(IndexMap::default())), MapKind::Map)
}
pub fn map_of(map: IndexMap<MapKey, Value>) -> Value {
Value::Map(Arc::new(Mutex::new(map)), MapKind::Map)
}
pub fn set() -> Value {
Value::Map(Arc::new(Mutex::new(IndexMap::default())), MapKind::Set)
}
pub fn set_of(map: IndexMap<MapKey, Value>) -> Value {
Value::Map(Arc::new(Mutex::new(map)), MapKind::Set)
}
pub fn structure(shape: Arc<StructShape>, values: Vec<Value>) -> Value {
Value::Struct(Arc::new(StructData {
shape,
values: Mutex::new(values),
}))
}
pub fn struct_of(
name: impl Into<Arc<str>>,
pairs: impl IntoIterator<Item = (Arc<str>, Value)>,
) -> Value {
let (fields, values): (Vec<_>, Vec<_>) = pairs.into_iter().unzip();
Value::structure(StructShape::new(name, fields), values)
}
pub fn some(v: Value) -> Value {
Value::enum_of("Option", "Some", vec![v])
}
pub fn enum_of(
enum_name: impl Into<Arc<str>>,
variant: impl Into<Arc<str>>,
data: Vec<Value>,
) -> Value {
Value::Enum {
enum_name: enum_name.into(),
variant: variant.into(),
data: Arc::new(Mutex::new(data)),
}
}
pub fn none() -> Value {
Value::enum_of("Option", "None", Vec::new())
}
pub fn is_none_value(&self) -> bool {
matches!(self, Value::Enum { enum_name, variant, .. }
if &**enum_name == "Option" && &**variant == "None")
}
pub fn ok(v: Value) -> Value {
Value::enum_of("Result", "Ok", vec![v])
}
pub fn err(v: Value) -> Value {
Value::enum_of("Result", "Err", vec![v])
}
pub fn is_truthy(&self) -> bool {
matches!(self, Value::Bool(true))
}
pub(super) fn default_like(&self) -> Value {
match self {
Value::Bool(_) => Value::Bool(false),
Value::Int(_) => Value::Int(0),
Value::IntW(_, w) => Value::IntW(0, *w),
Value::Big(_, w) => Value::Big(0, *w),
Value::Float(_) => Value::Float(0.0),
Value::F32(_) => Value::F32(0.0),
Value::Char(_) => Value::Char('\0'),
Value::Str(_) => Value::str(""),
Value::Vec(_) => Value::vec(Vec::new()),
Value::Map(_, MapKind::Map) => Value::map(),
Value::Map(_, MapKind::Set) => Value::set(),
Value::Enum { enum_name, .. } if &**enum_name == "Option" => Value::none(),
_ => Value::Unit,
}
}
pub(super) fn make_unique(&mut self) {
match self {
Value::Vec(list) | Value::Tuple(list) => {
if Arc::strong_count(list) > 1 {
let copy = list.lock().clone();
*list = Arc::new(Mutex::new(copy));
}
}
Value::Map(map, _) => {
if Arc::strong_count(map) > 1 {
let copy = map.lock().clone();
*map = Arc::new(Mutex::new(copy));
}
}
Value::Struct(data) => {
if Arc::strong_count(data) > 1 {
let values = data.values.lock().clone();
*data = Arc::new(StructData {
shape: data.shape.clone(),
values: Mutex::new(values),
});
}
}
Value::Enum { data, .. } if Arc::strong_count(data) > 1 => {
let copy = data.lock().clone();
*data = Arc::new(Mutex::new(copy));
}
_ => {}
}
}
pub fn from_const(c: &Const) -> Value {
match c {
Const::Big(v, w) => Value::Big(*v, *w),
Const::Float(f) => Value::Float(*f),
Const::F32(f) => Value::F32(*f),
Const::Char(ch) => Value::Char(*ch),
Const::Str(s) => Value::str(&**s),
Const::Bytes(bytes) => {
Value::vec(bytes.iter().map(|&b| Value::Int(i64::from(b))).collect())
}
}
}
pub(super) fn int_parts(&self) -> Option<(i128, IntWidth)> {
match self {
Value::Int(i) => Some((i128::from(*i), IntWidth::I64)),
Value::IntW(v, w) => Some((w.decode(*v), *w)),
Value::Big(v, IntWidth::I128) => Some((*v, IntWidth::I128)),
Value::Big(v, IntWidth::U128) if *v >= 0 => Some((*v, IntWidth::U128)),
_ => None,
}
}
pub(super) fn int_of_width(value: i128, width: IntWidth) -> Value {
match width {
IntWidth::I64 => Value::Int(i64::try_from(value).expect("truncated to width")),
IntWidth::I128 | IntWidth::U128 => Value::Big(value, width),
other => Value::IntW(other.encode(value), other),
}
}
pub(super) fn untag_int(&self) -> Option<i64> {
match self {
Value::IntW(v, w) => i64::try_from(w.decode(*v)).ok(),
_ => None,
}
}
pub(super) fn bridge_image(&self) -> Option<Value> {
match self {
Value::IntW(v, w) => {
let value = w.decode(*v);
Some(Value::Int(i64::try_from(value).unwrap_or(i64::MAX)))
}
Value::F32(f) => Some(Value::Float(f64::from(*f))),
_ => None,
}
}
pub fn type_name(&self) -> &'static str {
match self {
Value::Unit => "()",
Value::Bool(_) => "bool",
Value::Int(_) | Value::IntW(..) | Value::Big(..) => "integer",
Value::Float(_) | Value::F32(_) => "float",
Value::Char(_) => "char",
Value::Str(_) => "String",
Value::Vec(_) => "Vec",
Value::Map(_, MapKind::Map) => "HashMap",
Value::Map(_, MapKind::Set) => "HashSet",
Value::Tuple(_) => "tuple",
Value::Struct(_) => "struct",
Value::Enum { .. } => "enum",
Value::Range { .. } => "range",
Value::Closure(_) => "closure",
Value::Ref(reference) => reference
.get()
.map_or("reference", |value| value.type_name()),
Value::Cell(kind, _) => match kind {
CellKind::Rc => "Rc",
CellKind::Arc => "Arc",
CellKind::RefCell => "RefCell",
CellKind::Cell => "Cell",
CellKind::Mutex | CellKind::TokioMutex => "Mutex",
},
Value::Native(_) => "native",
}
}
pub fn as_key(&self) -> Option<MapKey> {
Some(match self {
Value::Bool(b) => MapKey::Bool(*b),
Value::Int(i) => MapKey::Int(*i),
Value::IntW(v, _) => MapKey::Int(*v),
Value::Char(c) => MapKey::Char(*c),
Value::Str(s) => MapKey::Str(s.clone()),
_ => return None,
})
}
pub fn into_key(self) -> Option<MapKey> {
Some(match self {
Value::Bool(b) => MapKey::Bool(b),
Value::Int(i) => MapKey::Int(i),
Value::IntW(v, _) => MapKey::Int(v),
Value::Char(c) => MapKey::Char(c),
Value::Str(s) => MapKey::Str(s),
_ => return None,
})
}
pub fn eq_value(&self, other: &Value) -> bool {
if let Value::Ref(reference) = self {
return reference.get().is_some_and(|value| value.eq_value(other));
}
if let Value::Ref(reference) = other {
return reference.get().is_some_and(|value| self.eq_value(&value));
}
if let Value::Cell(_, slot) = self {
let inner = slot.lock().clone();
return inner.eq_value(other);
}
if let Value::Cell(_, slot) = other {
let inner = slot.lock().clone();
return self.eq_value(&inner);
}
match (self, other) {
(Value::Unit, Value::Unit) => true,
(Value::Bool(a), Value::Bool(b)) => a == b,
(Value::Int(a), Value::Int(b)) => a == b,
(Value::IntW(..), Value::Int(_) | Value::IntW(..))
| (Value::Int(_), Value::IntW(..)) => {
self.int_parts().map(|(a, _)| a) == other.int_parts().map(|(b, _)| b)
}
(Value::Big(a, wa), Value::Big(b, wb)) => a == b && wa == wb,
(Value::Big(..), Value::Int(_)) | (Value::Int(_), Value::Big(..)) => {
match (self.int_parts(), other.int_parts()) {
(Some((a, _)), Some((b, _))) => a == b,
_ => false,
}
}
(Value::Float(a), Value::Float(b)) => a == b,
(Value::F32(a), Value::F32(b)) => a == b,
(Value::F32(a), Value::Float(b)) | (Value::Float(b), Value::F32(a)) => {
*a == AsPrimitive::<f32>::as_(*b)
}
(Value::Int(a), Value::Float(b)) | (Value::Float(b), Value::Int(a)) => {
AsPrimitive::<f64>::as_(*a) == *b
}
(Value::Char(a), Value::Char(b)) => a == b,
(Value::Str(a), Value::Str(b)) => a == b,
(Value::Vec(a), Value::Vec(b)) | (Value::Tuple(a), Value::Tuple(b)) => {
let a = a.lock().clone();
let b = b.lock().clone();
a.len() == b.len() && a.iter().zip(b.iter()).all(|(x, y)| x.eq_value(y))
}
(
Value::Enum {
enum_name: ea,
variant: va,
data: da,
},
Value::Enum {
enum_name: eb,
variant: vb,
data: db,
},
) => {
let da = da.lock().clone();
let db = db.lock().clone();
ea == eb
&& va == vb
&& da.len() == db.len()
&& da.iter().zip(db.iter()).all(|(x, y)| x.eq_value(y))
}
(Value::Struct(a), Value::Struct(b)) => {
a.name() == b.name() && {
let va = a.values.lock().clone();
let vb = b.values.lock().clone();
va.len() == vb.len()
&& a.shape
.fields
.iter()
.zip(va.iter())
.all(|(k, v)| b.shape.slot(k).is_some_and(|i| v.eq_value(&vb[i])))
}
}
(Value::Native(a), Value::Native(b)) => Arc::ptr_eq(a, b),
_ => false,
}
}
pub fn display(&self) -> String {
match self {
Value::Unit => "()".into(),
Value::Bool(b) => b.to_string(),
Value::Int(i) => i.to_string(),
Value::IntW(v, w) => w.decode(*v).to_string(),
Value::Big(v, w) => big_text(*v, *w),
Value::Float(f) => format_float(*f),
Value::F32(f) => f.to_string(),
Value::Char(c) => c.to_string(),
Value::Str(s) => s.to_string(),
Value::Cell(kind, slot) if kind.is_shared_pointer() => {
let inner = slot.lock().clone();
inner.display()
}
Value::Ref(reference) => match reference.get() {
Some(value) => value.display(),
None => "<dangling reference>".to_string(),
},
Value::Native(n) => match &*n.lock() {
Native::IoErr { display, .. } | Native::JoinErr { display, .. } => display.clone(),
other => format!("<{}>", other.type_name()),
},
Value::Enum {
enum_name,
variant,
data,
} if &**enum_name == "VarError" => {
if &**variant == "NotUnicode" {
let payload = data.lock().first().map(Value::display).unwrap_or_default();
format!("environment variable was not valid unicode: {payload:?}")
} else {
"environment variable not found".to_string()
}
}
other => other.debug(),
}
}
pub fn debug(&self) -> String {
let mut out = String::new();
self.write_debug(&mut out);
out
}
fn write_debug(&self, out: &mut String) {
match self {
Value::Unit => out.push_str("()"),
Value::Bool(b) => write!(out, "{b}").unwrap(),
Value::Int(i) => write!(out, "{i}").unwrap(),
Value::IntW(v, w) => write!(out, "{}", w.decode(*v)).unwrap(),
Value::Big(v, w) => out.push_str(&big_text(*v, *w)),
Value::Float(f) => out.push_str(&format_float_debug(*f)),
Value::F32(f) => write!(out, "{f:?}").unwrap(),
Value::Char(c) => write!(out, "{c:?}").unwrap(),
Value::Str(s) => write!(out, "{:?}", &**s).unwrap(),
Value::Range {
start,
end,
inclusive,
} => {
let sep = if *inclusive { "..=" } else { ".." };
write!(out, "{start}{sep}{end}").unwrap();
}
Value::Vec(items) => {
out.push('[');
for (i, v) in items.lock().iter().enumerate() {
if i > 0 {
out.push_str(", ");
}
v.write_debug(out);
}
out.push(']');
}
Value::Tuple(items) => {
out.push('(');
let items = items.lock();
for (i, v) in items.iter().enumerate() {
if i > 0 {
out.push_str(", ");
}
v.write_debug(out);
}
if items.len() == 1 {
out.push(',');
}
out.push(')');
}
Value::Map(map, kind) => {
out.push('{');
for (i, (k, v)) in map.lock().iter().enumerate() {
if i > 0 {
out.push_str(", ");
}
k.write_debug(out);
if *kind == MapKind::Map {
out.push_str(": ");
v.write_debug(out);
}
}
out.push('}');
}
Value::Struct(s) => write_struct_debug(s, out),
Value::Closure(_) => out.push_str("<closure>"),
Value::Ref(reference) => match reference.get() {
Some(value) => value.write_debug(out),
None => out.push_str("<dangling reference>"),
},
Value::Cell(kind, slot) => write_cell_debug(*kind, slot, out),
Value::Native(n) => {
if let Native::IoErr { debug, .. } | Native::JoinErr { debug, .. } = &*n.lock() {
out.push_str(debug);
} else {
write!(out, "<{}>", n.lock().type_name()).unwrap();
}
}
Value::Enum { variant, data, .. } => {
write!(out, "{variant}").unwrap();
let data = data.lock().clone();
if !data.is_empty() {
out.push('(');
for (i, v) in data.iter().enumerate() {
if i > 0 {
out.push_str(", ");
}
v.write_debug(out);
}
out.push(')');
}
}
}
}
}
fn write_cell_debug(kind: CellKind, slot: &Arc<Mutex<Value>>, out: &mut String) {
let inner = slot.lock().clone();
match kind {
CellKind::Rc | CellKind::Arc => inner.write_debug(out),
CellKind::RefCell => {
out.push_str("RefCell { value: ");
inner.write_debug(out);
out.push_str(" }");
}
CellKind::Cell => {
out.push_str("Cell { value: ");
inner.write_debug(out);
out.push_str(" }");
}
CellKind::Mutex => {
out.push_str("Mutex { data: ");
inner.write_debug(out);
out.push_str(", poisoned: false, .. }");
}
CellKind::TokioMutex => {
out.push_str("Mutex { data: ");
inner.write_debug(out);
out.push_str(" }");
}
}
}
fn big_text(v: i128, w: IntWidth) -> String {
if w == IntWidth::U128 {
v.cast_unsigned().to_string()
} else {
v.to_string()
}
}
fn write_struct_debug(s: &StructData, out: &mut String) {
write!(out, "{}", super::resolver::bare(s.name())).unwrap();
let values = s.values.lock();
if values.is_empty() {
return;
}
if s.shape
.fields
.iter()
.enumerate()
.all(|(i, f)| **f == i.to_string())
{
out.push('(');
for (i, v) in values.iter().enumerate() {
if i > 0 {
out.push_str(", ");
}
v.write_debug(out);
}
out.push(')');
return;
}
out.push_str(" { ");
for (i, (k, v)) in s.shape.fields.iter().zip(values.iter()).enumerate() {
if i > 0 {
out.push_str(", ");
}
write!(out, "{k}: ").unwrap();
v.write_debug(out);
}
out.push_str(" }");
}
impl MapKey {
fn write_debug(&self, out: &mut String) {
match self {
MapKey::Bool(b) => write!(out, "{b}").unwrap(),
MapKey::Int(i) => write!(out, "{i}").unwrap(),
MapKey::Char(c) => write!(out, "{c:?}").unwrap(),
MapKey::Str(s) => write!(out, "{:?}", &**s).unwrap(),
}
}
pub fn to_value(&self) -> Value {
match self {
MapKey::Bool(b) => Value::Bool(*b),
MapKey::Int(i) => Value::Int(*i),
MapKey::Char(c) => Value::Char(*c),
MapKey::Str(s) => Value::Str(s.clone()),
}
}
}
fn format_float(f: f64) -> String {
f.to_string()
}
fn format_float_debug(f: f64) -> String {
format!("{f:?}")
}