use alloc::string::String;
use alloc::sync::Arc;
use alloc::vec;
use alloc::vec::Vec;
use serde::{Deserialize, Serialize};
use crate::id::{DefinitionId, NameId};
pub const MAX_DECODE_DEPTH: usize = 128;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord, Serialize, Deserialize)]
pub struct ShapeId(pub u32);
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub enum ValueType {
Int,
Float,
Bool,
String,
List,
DivertTarget,
VariablePointer,
TempPointer,
Null,
FragmentRef,
Array,
Map,
Record,
FnRef,
Closure,
Handle,
Projection,
Option,
Range,
Vec2,
Vec3,
Vec4,
Quat,
Mat2,
Mat3,
Mat4,
Weighted,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum Value {
Int(i32),
Float(f32),
Bool(bool),
String(Arc<str>),
List(Arc<ListValue>),
DivertTarget(DefinitionId),
VariablePointer(DefinitionId),
TempPointer {
slot: u16,
frame_depth: u16,
},
Null,
FragmentRef(u32),
Array(Arc<Vec<Value>>),
Map(Arc<OrderedMap>),
Record {
shape: ShapeId,
fields: Arc<Vec<Value>>,
},
FnRef(DefinitionId),
Closure(Arc<ClosureValue>),
Handle {
kind: NameId,
id: u64,
},
Projection(Arc<ProjectionValue>),
OptionVal(Option<Arc<Value>>),
Range {
start: i32,
end: i32,
inclusive: bool,
},
Vec2(#[serde(with = "tower_serde::vec2")] glam::Vec2),
Vec3(#[serde(with = "tower_serde::vec3")] glam::Vec3),
Vec4(#[serde(with = "tower_serde::vec4")] glam::Vec4),
Quat(#[serde(with = "tower_serde::quat")] glam::Quat),
Mat2(#[serde(with = "tower_serde::mat2")] glam::Mat2),
Mat3(#[serde(with = "tower_serde::mat3")] glam::Mat3),
Mat4(#[serde(with = "tower_serde::mat4")] glam::Mat4),
Weighted(Arc<WeightedValue>),
}
pub mod tower_serde {
macro_rules! lane_codec {
($name:ident, $ty:ty, $lanes:literal, $to:ident, |$a:ident| $from:expr) => {
pub mod $name {
use serde::{Deserialize, Deserializer, Serialize, Serializer};
pub fn serialize<S: Serializer>(v: &$ty, s: S) -> Result<S::Ok, S::Error> {
v.$to().serialize(s)
}
pub fn deserialize<'de, D: Deserializer<'de>>(d: D) -> Result<$ty, D::Error> {
<[f32; $lanes]>::deserialize(d).map(|$a| $from)
}
}
};
}
lane_codec!(vec2, glam::Vec2, 2, to_array, |a| glam::Vec2::from_array(a));
lane_codec!(vec3, glam::Vec3, 3, to_array, |a| glam::Vec3::from_array(a));
lane_codec!(vec4, glam::Vec4, 4, to_array, |a| glam::Vec4::from_array(a));
lane_codec!(quat, glam::Quat, 4, to_array, |a| glam::Quat::from_array(a));
lane_codec!(mat2, glam::Mat2, 4, to_cols_array, |a| {
glam::Mat2::from_cols_array(&a)
});
lane_codec!(mat3, glam::Mat3, 9, to_cols_array, |a| {
glam::Mat3::from_cols_array(&a)
});
lane_codec!(mat4, glam::Mat4, 16, to_cols_array, |a| {
glam::Mat4::from_cols_array(&a)
});
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct ProjectionValue {
pub cell: DefinitionId,
pub segments: Vec<ProjSegment>,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub enum ProjSegment {
Index(i32),
Key(Value),
}
impl ProjSegment {
#[must_use]
pub fn from_value(v: Value) -> Self {
match v {
Value::Int(n) => Self::Index(n),
other => Self::Key(other),
}
}
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct ClosureValue {
pub target: DefinitionId,
pub env: Vec<ClosureEnvEntry>,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct ClosureEnvEntry {
pub name: NameId,
pub is_ref: bool,
pub payload: Value,
}
impl Value {
pub fn value_type(&self) -> ValueType {
match self {
Self::Int(_) => ValueType::Int,
Self::Float(_) => ValueType::Float,
Self::Bool(_) => ValueType::Bool,
Self::String(_) => ValueType::String,
Self::List(_) => ValueType::List,
Self::DivertTarget(_) => ValueType::DivertTarget,
Self::VariablePointer(_) => ValueType::VariablePointer,
Self::TempPointer { .. } => ValueType::TempPointer,
Self::Null => ValueType::Null,
Self::FragmentRef(_) => ValueType::FragmentRef,
Self::Array(_) => ValueType::Array,
Self::Map(_) => ValueType::Map,
Self::Record { .. } => ValueType::Record,
Self::FnRef(_) => ValueType::FnRef,
Self::Closure(_) => ValueType::Closure,
Self::Handle { .. } => ValueType::Handle,
Self::Projection(_) => ValueType::Projection,
Self::OptionVal(_) => ValueType::Option,
Self::Range { .. } => ValueType::Range,
Self::Vec2(_) => ValueType::Vec2,
Self::Vec3(_) => ValueType::Vec3,
Self::Vec4(_) => ValueType::Vec4,
Self::Quat(_) => ValueType::Quat,
Self::Mat2(_) => ValueType::Mat2,
Self::Mat3(_) => ValueType::Mat3,
Self::Mat4(_) => ValueType::Mat4,
Self::Weighted(_) => ValueType::Weighted,
}
}
pub fn range(start: i32, end: i32, inclusive: bool) -> Self {
Self::Range {
start,
end,
inclusive,
}
}
pub fn as_range(&self) -> Option<(i32, i32, bool)> {
match self {
Self::Range {
start,
end,
inclusive,
} => Some((*start, *end, *inclusive)),
_ => None,
}
}
pub fn range_end_exclusive(&self) -> Option<i64> {
match self {
Self::Range { end, inclusive, .. } => {
Some(i64::from(*end) + i64::from(u8::from(*inclusive)))
}
_ => None,
}
}
pub fn range_len(&self) -> Option<i64> {
match self {
Self::Range { start, .. } => {
let end_ex = self.range_end_exclusive()?;
Some((end_ex - i64::from(*start)).max(0))
}
_ => None,
}
}
#[must_use]
pub fn weighted(entries: Vec<(i32, Value)>) -> Self {
Self::Weighted(Arc::new(WeightedValue { entries }))
}
pub fn some(inner: Value) -> Self {
Self::OptionVal(Some(Arc::new(inner)))
}
pub fn none() -> Self {
Self::OptionVal(None)
}
pub fn as_option(&self) -> Option<Option<&Value>> {
match self {
Self::OptionVal(inner) => Some(inner.as_deref()),
_ => None,
}
}
pub fn as_int(&self) -> Option<i32> {
match self {
Self::Int(i) => Some(*i),
_ => None,
}
}
pub fn as_float(&self) -> Option<f32> {
match self {
Self::Float(f) => Some(*f),
#[expect(
clippy::cast_precision_loss,
reason = "int->float promotion matches ink coercion semantics"
)]
Self::Int(i) => Some(*i as f32),
_ => None,
}
}
pub fn as_bool(&self) -> Option<bool> {
match self {
Self::Bool(b) => Some(*b),
_ => None,
}
}
pub fn as_str(&self) -> Option<&str> {
match self {
Self::String(s) => Some(s),
_ => None,
}
}
pub fn array(items: Vec<Value>) -> Self {
Self::Array(Arc::new(items))
}
pub fn map(map: OrderedMap) -> Self {
Self::Map(Arc::new(map))
}
pub fn record(shape: ShapeId, fields: Vec<Value>) -> Self {
Self::Record {
shape,
fields: Arc::new(fields),
}
}
pub fn as_record(&self) -> Option<(ShapeId, &Arc<Vec<Value>>)> {
match self {
Self::Record { shape, fields } => Some((*shape, fields)),
_ => None,
}
}
pub fn closure(target: DefinitionId, env: Vec<ClosureEnvEntry>) -> Self {
Self::Closure(Arc::new(ClosureValue { target, env }))
}
pub fn fn_target(&self) -> Option<DefinitionId> {
match self {
Self::FnRef(target) => Some(*target),
Self::Closure(c) => Some(c.target),
_ => None,
}
}
pub fn as_closure(&self) -> Option<&Arc<ClosureValue>> {
match self {
Self::Closure(c) => Some(c),
_ => None,
}
}
pub fn as_weighted(&self) -> Option<&Arc<WeightedValue>> {
match self {
Self::Weighted(w) => Some(w),
_ => None,
}
}
pub fn handle(kind: NameId, id: u64) -> Self {
Self::Handle { kind, id }
}
pub fn as_handle(&self) -> Option<(NameId, u64)> {
match self {
Self::Handle { kind, id } => Some((*kind, *id)),
_ => None,
}
}
pub fn projection(cell: DefinitionId, segments: Vec<ProjSegment>) -> Self {
Self::Projection(Arc::new(ProjectionValue { cell, segments }))
}
pub fn as_projection(&self) -> Option<&Arc<ProjectionValue>> {
match self {
Self::Projection(p) => Some(p),
_ => None,
}
}
pub fn as_vec2(&self) -> Option<glam::Vec2> {
match self {
Self::Vec2(v) => Some(*v),
_ => None,
}
}
pub fn as_vec3(&self) -> Option<glam::Vec3> {
match self {
Self::Vec3(v) => Some(*v),
_ => None,
}
}
pub fn as_vec4(&self) -> Option<glam::Vec4> {
match self {
Self::Vec4(v) => Some(*v),
_ => None,
}
}
pub fn as_quat(&self) -> Option<glam::Quat> {
match self {
Self::Quat(q) => Some(*q),
_ => None,
}
}
pub fn as_mat2(&self) -> Option<glam::Mat2> {
match self {
Self::Mat2(m) => Some(*m),
_ => None,
}
}
pub fn as_mat3(&self) -> Option<glam::Mat3> {
match self {
Self::Mat3(m) => Some(*m),
_ => None,
}
}
pub fn as_mat4(&self) -> Option<glam::Mat4> {
match self {
Self::Mat4(m) => Some(*m),
_ => None,
}
}
pub fn as_array(&self) -> Option<&Arc<Vec<Value>>> {
match self {
Self::Array(items) => Some(items),
_ => None,
}
}
pub fn as_map(&self) -> Option<&Arc<OrderedMap>> {
match self {
Self::Map(map) => Some(map),
_ => None,
}
}
pub fn array_make_mut(&mut self) -> Option<&mut Vec<Value>> {
match self {
Self::Array(items) => Some(Arc::make_mut(items)),
_ => None,
}
}
pub fn map_make_mut(&mut self) -> Option<&mut OrderedMap> {
match self {
Self::Map(map) => Some(Arc::make_mut(map)),
_ => None,
}
}
pub fn record_make_mut(&mut self) -> Option<&mut Vec<Value>> {
match self {
Self::Record { fields, .. } => Some(Arc::make_mut(fields)),
_ => None,
}
}
}
impl PartialEq for Value {
#[expect(
clippy::match_same_arms,
reason = "each scalar variant is spelled out so the mapping to the \
derive it replaces is auditable; merging identical `a == b` \
bodies would obscure which variants are covered"
)]
fn eq(&self, other: &Self) -> bool {
match (self, other) {
(Self::Int(a), Self::Int(b)) => a == b,
(Self::Float(a), Self::Float(b)) => a == b,
(Self::Bool(a), Self::Bool(b)) => a == b,
(Self::String(a), Self::String(b)) => a == b,
(Self::List(a), Self::List(b)) => a == b,
(Self::DivertTarget(a), Self::DivertTarget(b)) => a == b,
(Self::VariablePointer(a), Self::VariablePointer(b)) => a == b,
(
Self::TempPointer {
slot: a_slot,
frame_depth: a_depth,
},
Self::TempPointer {
slot: b_slot,
frame_depth: b_depth,
},
) => a_slot == b_slot && a_depth == b_depth,
(Self::Null, Self::Null) => true,
(Self::FragmentRef(a), Self::FragmentRef(b)) => a == b,
(Self::Array(a), Self::Array(b)) => Arc::ptr_eq(a, b) || a == b,
(Self::Map(a), Self::Map(b)) => Arc::ptr_eq(a, b) || a == b,
(
Self::Record {
shape: sa,
fields: a,
},
Self::Record {
shape: sb,
fields: b,
},
) => sa == sb && (Arc::ptr_eq(a, b) || a == b),
(Self::FnRef(a), Self::FnRef(b)) => a == b,
(Self::Closure(a), Self::Closure(b)) => Arc::ptr_eq(a, b) || a == b,
(Self::Handle { kind: ka, id: ida }, Self::Handle { kind: kb, id: idb }) => {
ka == kb && ida == idb
}
(Self::Projection(a), Self::Projection(b)) => Arc::ptr_eq(a, b) || a == b,
(Self::Weighted(a), Self::Weighted(b)) => Arc::ptr_eq(a, b) || a == b,
(Self::OptionVal(a), Self::OptionVal(b)) => match (a, b) {
(None, None) => true,
(Some(x), Some(y)) => Arc::ptr_eq(x, y) || x == y,
_ => false,
},
(a @ Self::Range { start: sa, .. }, b @ Self::Range { start: sb, .. }) => {
let (la, lb) = (a.range_len(), b.range_len());
match (la, lb) {
(Some(0), Some(0)) => true,
(Some(x), Some(y)) => x == y && sa == sb,
_ => false,
}
}
(Self::Vec2(a), Self::Vec2(b)) => a == b,
(Self::Vec3(a), Self::Vec3(b)) => a == b,
(Self::Vec4(a), Self::Vec4(b)) => a == b,
(Self::Quat(a), Self::Quat(b)) => a == b,
(Self::Mat2(a), Self::Mat2(b)) => a == b,
(Self::Mat3(a), Self::Mat3(b)) => a == b,
(Self::Mat4(a), Self::Mat4(b)) => a == b,
_ => false,
}
}
}
impl From<i32> for Value {
fn from(v: i32) -> Self {
Self::Int(v)
}
}
impl From<f32> for Value {
fn from(v: f32) -> Self {
Self::Float(v)
}
}
impl From<bool> for Value {
fn from(v: bool) -> Self {
Self::Bool(v)
}
}
impl From<&str> for Value {
fn from(v: &str) -> Self {
Self::String(Arc::from(v))
}
}
impl From<String> for Value {
fn from(v: String) -> Self {
Self::String(Arc::from(v))
}
}
impl From<Arc<str>> for Value {
fn from(v: Arc<str>) -> Self {
Self::String(v)
}
}
impl From<()> for Value {
fn from((): ()) -> Self {
Self::Null
}
}
impl From<glam::Vec2> for Value {
fn from(v: glam::Vec2) -> Self {
Self::Vec2(v)
}
}
impl From<glam::Vec3> for Value {
fn from(v: glam::Vec3) -> Self {
Self::Vec3(v)
}
}
impl From<glam::Vec4> for Value {
fn from(v: glam::Vec4) -> Self {
Self::Vec4(v)
}
}
impl From<glam::Quat> for Value {
fn from(v: glam::Quat) -> Self {
Self::Quat(v)
}
}
impl From<glam::Mat2> for Value {
fn from(v: glam::Mat2) -> Self {
Self::Mat2(v)
}
}
impl From<glam::Mat3> for Value {
fn from(v: glam::Mat3) -> Self {
Self::Mat3(v)
}
}
impl From<glam::Mat4> for Value {
fn from(v: glam::Mat4) -> Self {
Self::Mat4(v)
}
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct ListValue {
pub items: Vec<DefinitionId>,
pub origins: Vec<DefinitionId>,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub enum MapKey {
Int(i32),
Str(Arc<str>),
Bool(bool),
}
impl MapKey {
pub fn from_value(value: &Value) -> Option<Self> {
match value {
Value::Int(n) => Some(Self::Int(*n)),
Value::String(s) => Some(Self::Str(Arc::clone(s))),
Value::Bool(b) => Some(Self::Bool(*b)),
_ => None,
}
}
}
impl From<i32> for MapKey {
fn from(v: i32) -> Self {
Self::Int(v)
}
}
impl From<bool> for MapKey {
fn from(v: bool) -> Self {
Self::Bool(v)
}
}
impl From<&str> for MapKey {
fn from(v: &str) -> Self {
Self::Str(Arc::from(v))
}
}
impl From<String> for MapKey {
fn from(v: String) -> Self {
Self::Str(Arc::from(v))
}
}
impl From<Arc<str>> for MapKey {
fn from(v: Arc<str>) -> Self {
Self::Str(v)
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct WeightedValue {
pub entries: Vec<(i32, Value)>,
}
impl WeightedValue {
#[must_use]
pub fn total_weight(&self) -> i64 {
self.entries.iter().map(|(w, _)| i64::from(*w)).sum()
}
}
impl PartialEq for WeightedValue {
fn eq(&self, other: &Self) -> bool {
if self.entries.len() != other.entries.len() {
return false;
}
let mut used = vec![false; other.entries.len()];
'outer: for (w, v) in &self.entries {
for (i, (ow, ov)) in other.entries.iter().enumerate() {
if !used[i] && w == ow && v == ov {
used[i] = true;
continue 'outer;
}
}
return false;
}
true
}
}
#[derive(Debug, Clone, Default, Serialize)]
pub struct OrderedMap {
entries: Vec<(MapKey, Value)>,
}
impl<'de> Deserialize<'de> for OrderedMap {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
#[derive(Deserialize)]
struct Shadow {
entries: Vec<(MapKey, Value)>,
}
let shadow = Shadow::deserialize(deserializer)?;
let mut map = Self::with_capacity(shadow.entries.len());
for (key, value) in shadow.entries {
if map.contains_key(&key) {
return Err(serde::de::Error::custom("duplicate key in map value"));
}
map.insert(key, value);
}
Ok(map)
}
}
impl PartialEq for OrderedMap {
fn eq(&self, other: &Self) -> bool {
self.entries.len() == other.entries.len()
&& self.entries.iter().all(|(key, value)| {
other
.get(key)
.is_some_and(|other_value| other_value == value)
})
}
}
impl OrderedMap {
pub fn new() -> Self {
Self {
entries: Vec::new(),
}
}
pub fn with_capacity(n: usize) -> Self {
Self {
entries: Vec::with_capacity(n),
}
}
pub fn len(&self) -> usize {
self.entries.len()
}
pub fn is_empty(&self) -> bool {
self.entries.is_empty()
}
pub fn get(&self, key: &MapKey) -> Option<&Value> {
self.entries.iter().find(|(k, _)| k == key).map(|(_, v)| v)
}
pub fn contains_key(&self, key: &MapKey) -> bool {
self.entries.iter().any(|(k, _)| k == key)
}
pub fn get_mut(&mut self, key: &MapKey) -> Option<&mut Value> {
self.entries
.iter_mut()
.find(|(k, _)| k == key)
.map(|(_, v)| v)
}
pub fn insert(&mut self, key: MapKey, value: Value) -> Option<Value> {
if let Some((_, slot)) = self.entries.iter_mut().find(|(k, _)| *k == key) {
Some(core::mem::replace(slot, value))
} else {
self.entries.push((key, value));
None
}
}
pub fn remove(&mut self, key: &MapKey) -> Option<Value> {
let idx = self.entries.iter().position(|(k, _)| k == key)?;
Some(self.entries.remove(idx).1)
}
pub fn iter(&self) -> impl Iterator<Item = (&MapKey, &Value)> {
self.entries.iter().map(|(k, v)| (k, v))
}
pub fn keys(&self) -> impl Iterator<Item = &MapKey> {
self.entries.iter().map(|(k, _)| k)
}
pub fn values(&self) -> impl Iterator<Item = &Value> {
self.entries.iter().map(|(_, v)| v)
}
}
impl FromIterator<(MapKey, Value)> for OrderedMap {
fn from_iter<I: IntoIterator<Item = (MapKey, Value)>>(iter: I) -> Self {
let mut map = Self::new();
for (k, v) in iter {
map.insert(k, v);
}
map
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::id::DefinitionTag;
#[test]
fn value_type_discriminant() {
assert_eq!(Value::Int(0).value_type(), ValueType::Int);
assert_eq!(Value::Float(0.0).value_type(), ValueType::Float);
assert_eq!(Value::Bool(true).value_type(), ValueType::Bool);
assert_eq!(Value::String("".into()).value_type(), ValueType::String);
assert_eq!(Value::Null.value_type(), ValueType::Null);
let list = ListValue {
items: vec![],
origins: vec![],
};
assert_eq!(Value::List(list.into()).value_type(), ValueType::List);
let target = DefinitionId::new(DefinitionTag::Address, 1);
assert_eq!(
Value::DivertTarget(target).value_type(),
ValueType::DivertTarget
);
}
#[test]
fn from_impls_roundtrip() {
assert_eq!(Value::from(7_i32), Value::Int(7));
assert_eq!(Value::from(1.5_f32), Value::Float(1.5));
assert_eq!(Value::from(true), Value::Bool(true));
assert_eq!(Value::from("hi"), Value::String("hi".into()));
assert_eq!(Value::from(String::from("hi")), Value::String("hi".into()));
assert_eq!(Value::from(()), Value::Null);
}
#[test]
fn accessors_are_strict_except_int_to_float() {
assert_eq!(Value::Int(3).as_int(), Some(3));
assert_eq!(Value::Float(3.0).as_int(), None);
assert_eq!(Value::Bool(true).as_int(), None);
assert_eq!(Value::Int(3).as_float(), Some(3.0));
assert_eq!(Value::Float(2.5).as_float(), Some(2.5));
assert_eq!(Value::Bool(true).as_bool(), Some(true));
assert_eq!(Value::Int(1).as_bool(), None);
assert_eq!(Value::String("x".into()).as_str(), Some("x"));
assert_eq!(Value::Int(1).as_str(), None);
}
#[test]
fn collection_value_types() {
assert_eq!(
Value::array(vec![Value::Int(1)]).value_type(),
ValueType::Array
);
assert_eq!(Value::map(OrderedMap::new()).value_type(), ValueType::Map);
}
#[test]
fn array_accessors() {
let v = Value::array(vec![Value::Int(1), Value::Int(2)]);
let items = v.as_array().expect("is array");
assert_eq!(items.len(), 2);
assert!(Value::Int(0).as_array().is_none());
assert!(v.as_map().is_none());
}
#[test]
fn map_key_from_value_permitted_domain() {
assert_eq!(MapKey::from_value(&Value::Int(3)), Some(MapKey::Int(3)));
assert_eq!(
MapKey::from_value(&Value::String("k".into())),
Some(MapKey::Str("k".into()))
);
assert_eq!(
MapKey::from_value(&Value::Bool(true)),
Some(MapKey::Bool(true))
);
assert_eq!(MapKey::from_value(&Value::Float(1.0)), None);
assert_eq!(MapKey::from_value(&Value::Null), None);
assert_eq!(MapKey::from_value(&Value::array(vec![])), None);
}
#[test]
fn map_key_variants_are_distinct() {
assert_ne!(MapKey::Int(1), MapKey::Bool(true));
assert_ne!(MapKey::from(1), MapKey::from("1"));
assert_ne!(MapKey::from(true), MapKey::from(false));
assert_eq!(MapKey::from(1), MapKey::Int(1));
assert_eq!(MapKey::from("a"), MapKey::Str("a".into()));
}
#[test]
fn ordered_map_preserves_insertion_order() {
let mut m = OrderedMap::new();
assert!(m.is_empty());
m.insert(MapKey::from("b"), Value::Int(2));
m.insert(MapKey::from("a"), Value::Int(1));
m.insert(MapKey::from("c"), Value::Int(3));
let keys: Vec<&MapKey> = m.keys().collect();
assert_eq!(
keys,
vec![&MapKey::from("b"), &MapKey::from("a"), &MapKey::from("c")]
);
assert_eq!(m.len(), 3);
assert_eq!(m.get(&MapKey::from("a")), Some(&Value::Int(1)));
assert!(m.contains_key(&MapKey::from("c")));
assert!(!m.contains_key(&MapKey::from("z")));
}
#[test]
fn ordered_map_reinsert_keeps_position_and_returns_old() {
let mut m = OrderedMap::new();
m.insert(MapKey::from("x"), Value::Int(1));
m.insert(MapKey::from("y"), Value::Int(2));
let old = m.insert(MapKey::from("x"), Value::Int(9));
assert_eq!(old, Some(Value::Int(1)));
let keys: Vec<&MapKey> = m.keys().collect();
assert_eq!(keys, vec![&MapKey::from("x"), &MapKey::from("y")]);
assert_eq!(m.get(&MapKey::from("x")), Some(&Value::Int(9)));
}
#[test]
fn ordered_map_remove_shifts_survivors() {
let mut m = OrderedMap::new();
m.insert(MapKey::from("a"), Value::Int(1));
m.insert(MapKey::from("b"), Value::Int(2));
m.insert(MapKey::from("c"), Value::Int(3));
assert_eq!(m.remove(&MapKey::from("b")), Some(Value::Int(2)));
assert_eq!(m.remove(&MapKey::from("b")), None);
let keys: Vec<&MapKey> = m.keys().collect();
assert_eq!(keys, vec![&MapKey::from("a"), &MapKey::from("c")]);
}
#[test]
fn ordered_map_from_iter_last_wins_first_position() {
let m: OrderedMap = [
(MapKey::from("a"), Value::Int(1)),
(MapKey::from("b"), Value::Int(2)),
(MapKey::from("a"), Value::Int(10)),
]
.into_iter()
.collect();
assert_eq!(m.len(), 2);
let keys: Vec<&MapKey> = m.keys().collect();
assert_eq!(keys, vec![&MapKey::from("a"), &MapKey::from("b")]);
assert_eq!(m.get(&MapKey::from("a")), Some(&Value::Int(10)));
}
#[test]
fn ordered_map_deserialize_rejects_duplicate_key() {
let json = r#"{"entries":[[{"Str":"a"},{"Int":1}],[{"Str":"a"},{"Int":2}]]}"#;
let err = serde_json::from_str::<OrderedMap>(json)
.expect_err("duplicate key must not deserialize");
assert!(
err.to_string().contains("duplicate key"),
"unexpected error: {err}"
);
}
#[test]
fn ordered_map_deserialize_accepts_distinct_keys() {
let json = r#"{"entries":[[{"Str":"a"},{"Int":1}],[{"Str":"b"},{"Int":2}]]}"#;
let m: OrderedMap = serde_json::from_str(json).expect("distinct keys must deserialize");
assert_eq!(m.len(), 2);
assert_eq!(m.get(&MapKey::from("a")), Some(&Value::Int(1)));
assert_eq!(m.get(&MapKey::from("b")), Some(&Value::Int(2)));
}
#[test]
fn ordered_map_serde_json_round_trip_without_duplicates() {
let mut m = OrderedMap::new();
m.insert(MapKey::from("hp"), Value::Int(10));
m.insert(MapKey::from(true), Value::String("flag".into()));
m.insert(MapKey::from(7), Value::Float(1.5));
let json = serde_json::to_string(&m).expect("serialize");
let back: OrderedMap = serde_json::from_str(&json).expect("deserialize");
assert_eq!(back, m);
}
#[test]
fn tower_equality_is_componentwise_ieee() {
let a = Value::Vec2(glam::Vec2::new(1.0, 2.0));
assert_eq!(a, Value::Vec2(glam::Vec2::new(1.0, 2.0)));
assert_eq!(
Value::Vec2(glam::Vec2::new(-0.0, 1.0)),
Value::Vec2(glam::Vec2::new(0.0, 1.0))
);
let nan = Value::Vec3(glam::Vec3::new(f32::NAN, 0.0, 0.0));
assert_ne!(nan.clone(), nan);
assert_ne!(a, Value::Vec3(glam::Vec3::new(1.0, 2.0, 0.0)));
}
#[test]
fn tower_serde_is_flat_lane_arrays() {
let v = Value::Vec3(glam::Vec3::new(1.0, 2.5, -3.0));
let json = serde_json::to_string(&v).expect("serialize");
assert_eq!(json, r#"{"Vec3":[1.0,2.5,-3.0]}"#);
let back: Value = serde_json::from_str(&json).expect("deserialize");
assert_eq!(back, v);
let m = Value::Mat2(glam::Mat2::from_cols_array(&[1.0, 2.0, 3.0, 4.0]));
let json = serde_json::to_string(&m).expect("serialize");
assert_eq!(json, r#"{"Mat2":[1.0,2.0,3.0,4.0]}"#);
let back: Value = serde_json::from_str(&json).expect("deserialize");
assert_eq!(back, m);
let q = Value::Quat(glam::Quat::from_xyzw(0.1, 0.2, 0.3, 0.4));
let back: Value = serde_json::from_str(&serde_json::to_string(&q).expect("serialize"))
.expect("deserialize");
assert_eq!(back, q);
}
#[test]
fn tower_accessors_and_from_impls_are_identity() {
let v = glam::Vec3::new(1.0, 2.0, 3.0);
assert_eq!(Value::from(v).as_vec3(), Some(v));
assert_eq!(Value::from(v).as_vec2(), None);
let m = glam::Mat4::IDENTITY;
assert_eq!(Value::from(m).as_mat4(), Some(m));
assert_eq!(Value::Int(1).as_quat(), None);
}
#[test]
fn value_map_deserialize_rejects_duplicate_key() {
let json = r#"{"Map":{"entries":[[{"Str":"a"},{"Int":1}],[{"Str":"a"},{"Int":2}]]}}"#;
let err =
serde_json::from_str::<Value>(json).expect_err("duplicate key must not deserialize");
assert!(
err.to_string().contains("duplicate key"),
"unexpected error: {err}"
);
}
#[test]
fn clone_is_arc_bump_not_deep_copy() {
let v = Value::array(vec![Value::Int(1)]);
let arc = Arc::clone(v.as_array().expect("array"));
assert_eq!(Arc::strong_count(&arc), 2); let v2 = v.clone();
assert_eq!(Arc::strong_count(&arc), 3); drop(v2);
assert_eq!(Arc::strong_count(&arc), 2);
}
#[test]
fn array_make_mut_in_place_when_unique() {
let mut v = Value::array(vec![Value::Int(1)]);
let arc_before = Arc::as_ptr(v.as_array().expect("array"));
v.array_make_mut().expect("array").push(Value::Int(2));
let arc_after = Arc::as_ptr(v.as_array().expect("array"));
assert_eq!(arc_before, arc_after, "unique Arc mutates in place");
assert_eq!(v.as_array().expect("array").len(), 2);
}
#[test]
fn array_make_mut_copies_when_shared() {
let original = Value::array(vec![Value::Int(1)]);
let mut copy = original.clone(); copy.array_make_mut().expect("array").push(Value::Int(2));
assert_eq!(
original.as_array().expect("array").as_slice(),
&[Value::Int(1)]
);
assert_eq!(copy.as_array().expect("array").len(), 2);
assert_eq!(Arc::strong_count(original.as_array().expect("array")), 1);
}
#[test]
fn map_make_mut_copies_when_shared() {
let mut base = OrderedMap::new();
base.insert(MapKey::from("a"), Value::Int(1));
let original = Value::map(base);
let mut copy = original.clone();
copy.map_make_mut()
.expect("map")
.insert(MapKey::from("b"), Value::Int(2));
assert_eq!(original.as_map().expect("map").len(), 1);
assert_eq!(copy.as_map().expect("map").len(), 2);
}
#[test]
fn make_mut_returns_none_for_non_collection() {
assert!(Value::Int(1).array_make_mut().is_none());
assert!(Value::Int(1).map_make_mut().is_none());
}
#[test]
fn record_make_mut_copies_when_shared() {
let shape = ShapeId(0);
let original = Value::record(shape, vec![Value::Int(1), Value::Int(2)]);
let mut copy = original.clone(); copy.record_make_mut().expect("record")[0] = Value::Int(99);
assert_eq!(
original.as_record().expect("record").1.as_slice(),
&[Value::Int(1), Value::Int(2)],
"mutating the copy must never be observable through the original"
);
assert_eq!(
copy.as_record().expect("record").1.as_slice(),
&[Value::Int(99), Value::Int(2)]
);
assert_eq!(
Arc::strong_count(original.as_record().expect("record").1),
1
);
}
#[test]
fn nested_array_inside_record_field_is_isolated_after_copy() {
let shape = ShapeId(0);
let inner = Value::array(vec![Value::Int(1), Value::Int(2)]);
let original = Value::record(shape, vec![Value::String("bag".into()), inner]);
let mut copy = original.clone();
let fields = copy.record_make_mut().expect("record");
let mut inner_copy = fields[1].clone();
inner_copy
.array_make_mut()
.expect("array")
.push(Value::Int(3));
fields[1] = inner_copy;
let original_inner = original
.as_record()
.expect("record")
.1
.get(1)
.expect("field 1")
.as_array()
.expect("array");
assert_eq!(
original_inner.as_slice(),
&[Value::Int(1), Value::Int(2)],
"mutating the copy's nested array must never be observable through the original record"
);
let copy_inner = copy
.as_record()
.expect("record")
.1
.get(1)
.expect("field 1")
.as_array()
.expect("array");
assert_eq!(
copy_inner.as_slice(),
&[Value::Int(1), Value::Int(2), Value::Int(3)]
);
}
#[test]
fn closure_val_capture_is_isolated_from_later_mutation_of_the_source() {
let mut original = Value::array(vec![Value::Int(1)]);
let entry = ClosureEnvEntry {
name: NameId(0),
is_ref: false,
payload: original.clone(), };
let closure = Value::closure(DefinitionId::new(DefinitionTag::Address, 0), vec![entry]);
original
.array_make_mut()
.expect("array")
.push(Value::Int(2));
assert_eq!(
original.as_array().expect("array").as_slice(),
&[Value::Int(1), Value::Int(2)]
);
let captured = &closure.as_closure().expect("closure").env[0].payload;
assert_eq!(
captured.as_array().expect("array").as_slice(),
&[Value::Int(1)],
"mutating the source after MakeClosure must never be observable through the val-captured snapshot"
);
}
#[test]
fn option_some_wrap_is_isolated_from_later_mutation_of_the_source() {
let mut original = Value::array(vec![Value::Int(1)]);
let wrapped = Value::some(original.clone());
original
.array_make_mut()
.expect("array")
.push(Value::Int(2));
assert_eq!(
original.as_array().expect("array").as_slice(),
&[Value::Int(1), Value::Int(2)]
);
let inner = wrapped
.as_option()
.expect("option")
.expect("some")
.as_array()
.expect("array");
assert_eq!(
inner.as_slice(),
&[Value::Int(1)],
"mutating the source after `some(..)` wrapped it must never be observable through the wrapped copy"
);
}
#[test]
fn weighted_entry_capture_is_isolated_from_later_mutation_of_the_source() {
let mut original = Value::array(vec![Value::Int(1)]);
let table = Value::weighted(vec![(1, original.clone())]);
original
.array_make_mut()
.expect("array")
.push(Value::Int(2));
assert_eq!(
original.as_array().expect("array").as_slice(),
&[Value::Int(1), Value::Int(2)]
);
let weighted = table.as_weighted().expect("weighted");
let entry = weighted.entries[0].1.as_array().expect("array");
assert_eq!(
entry.as_slice(),
&[Value::Int(1)],
"mutating the source after the table captured it must never be observable through the weighted entry"
);
}
#[test]
fn array_equality_is_structural_across_distinct_arcs() {
let a = Value::array(vec![Value::Int(1), Value::Int(2)]);
let b = Value::array(vec![Value::Int(1), Value::Int(2)]);
assert!(!Arc::ptr_eq(a.as_array().unwrap(), b.as_array().unwrap()));
assert_eq!(a, b);
let c = Value::array(vec![Value::Int(1), Value::Int(3)]);
assert_ne!(a, c);
}
#[test]
fn nested_collection_equality() {
let inner = Value::array(vec![Value::Int(1)]);
let a = Value::array(vec![inner.clone(), Value::map(OrderedMap::new())]);
let b = Value::array(vec![
Value::array(vec![Value::Int(1)]),
Value::map(OrderedMap::new()),
]);
assert_eq!(a, b);
}
#[test]
fn shared_snapshot_is_equal_via_ptr_eq() {
let a = Value::array(vec![Value::Int(1)]);
let snapshot = a.clone(); assert!(Arc::ptr_eq(
a.as_array().unwrap(),
snapshot.as_array().unwrap()
));
assert_eq!(a, snapshot);
}
#[test]
fn distinct_nan_arrays_never_equal_but_same_snapshot_is() {
let a = Value::array(vec![Value::Float(f32::NAN)]);
let b = Value::array(vec![Value::Float(f32::NAN)]);
assert_ne!(a, b);
let snapshot = a.clone();
assert_eq!(a, snapshot);
}
#[test]
fn map_equality_is_content_based_insertion_order_insensitive() {
let m1: OrderedMap = [
(MapKey::from("a"), Value::Int(1)),
(MapKey::from("b"), Value::Int(2)),
]
.into_iter()
.collect();
let m2: OrderedMap = [
(MapKey::from("b"), Value::Int(2)),
(MapKey::from("a"), Value::Int(1)),
]
.into_iter()
.collect();
assert_eq!(Value::map(m1.clone()), Value::map(m2.clone()));
assert_eq!(Value::map(m2.clone()), Value::map(m1.clone()));
assert_eq!(Value::map(m1.clone()), Value::map(m1.clone()));
assert_eq!(
m1.keys().cloned().collect::<Vec<_>>(),
vec![MapKey::from("a"), MapKey::from("b")]
);
assert_eq!(
m2.keys().cloned().collect::<Vec<_>>(),
vec![MapKey::from("b"), MapKey::from("a")]
);
}
#[test]
fn map_equality_still_rejects_different_content() {
let a: OrderedMap = [(MapKey::from("a"), Value::Int(1))].into_iter().collect();
let b: OrderedMap = [(MapKey::from("a"), Value::Int(2))].into_iter().collect();
assert_ne!(Value::map(a.clone()), Value::map(b));
let c: OrderedMap = [
(MapKey::from("a"), Value::Int(1)),
(MapKey::from("b"), Value::Int(2)),
]
.into_iter()
.collect();
assert_ne!(Value::map(a), Value::map(c));
}
#[test]
fn nested_map_equality_is_order_insensitive_at_every_level() {
let inner1: OrderedMap = [
(MapKey::from("x"), Value::Int(1)),
(MapKey::from("y"), Value::Int(2)),
]
.into_iter()
.collect();
let inner2: OrderedMap = [
(MapKey::from("y"), Value::Int(2)),
(MapKey::from("x"), Value::Int(1)),
]
.into_iter()
.collect();
let outer1: OrderedMap = [
(MapKey::from("inner"), Value::map(inner1)),
(MapKey::from("other"), Value::Int(9)),
]
.into_iter()
.collect();
let outer2: OrderedMap = [
(MapKey::from("other"), Value::Int(9)),
(MapKey::from("inner"), Value::map(inner2)),
]
.into_iter()
.collect();
assert_eq!(Value::map(outer1), Value::map(outer2));
}
#[test]
fn record_equality_is_unaffected_by_map_ordering_ruling() {
let shape = ShapeId(0);
let r1 = Value::record(shape, vec![Value::Int(1), Value::Int(2)]);
let r2 = Value::record(shape, vec![Value::Int(1), Value::Int(2)]);
let r3 = Value::record(shape, vec![Value::Int(2), Value::Int(1)]);
assert_eq!(r1, r2);
assert_ne!(r1, r3);
}
#[test]
fn cross_type_inequality_unaffected() {
assert_ne!(Value::Int(1), Value::Bool(true));
assert_ne!(Value::array(vec![]), Value::Null);
assert_ne!(Value::array(vec![]), Value::map(OrderedMap::new()));
assert_eq!(Value::Null, Value::Null);
}
fn json_round_trip(v: &Value) -> Value {
let json = serde_json::to_string(v).expect("serialize");
serde_json::from_str(&json).expect("deserialize")
}
#[test]
fn scalar_serde_round_trip_unchanged() {
for v in [
Value::Int(-7),
Value::Float(1.5),
Value::Bool(true),
Value::String("hi".into()),
Value::Null,
] {
assert_eq!(json_round_trip(&v), v);
}
}
#[test]
fn array_serde_round_trip_is_structural() {
let v = Value::array(vec![
Value::Int(1),
Value::String("two".into()),
Value::Bool(false),
]);
let back = json_round_trip(&v);
assert_eq!(back, v);
assert_eq!(back.value_type(), ValueType::Array);
}
#[test]
fn map_serde_round_trip_preserves_order_and_key_types() {
let m: OrderedMap = [
(MapKey::from("z"), Value::Int(1)),
(MapKey::from(10), Value::Int(2)),
(MapKey::from(true), Value::Int(3)),
(MapKey::from("a"), Value::Int(4)),
]
.into_iter()
.collect();
let v = Value::map(m);
let back = json_round_trip(&v);
assert_eq!(back, v);
let back_map = back.as_map().expect("map");
let keys: Vec<&MapKey> = back_map.keys().collect();
assert_eq!(
keys,
vec![
&MapKey::from("z"),
&MapKey::from(10),
&MapKey::from(true),
&MapKey::from("a"),
]
);
}
#[test]
fn nested_collection_serde_round_trip() {
let inner_map: OrderedMap = [
(
MapKey::from("items"),
Value::array(vec![Value::Int(1), Value::Int(2)]),
),
(MapKey::from("name"), Value::String("goblin".into())),
]
.into_iter()
.collect();
let v = Value::array(vec![
Value::map(inner_map),
Value::array(vec![Value::map(OrderedMap::new())]),
Value::Null,
]);
assert_eq!(json_round_trip(&v), v);
}
#[test]
fn handle_value_type_and_constructor() {
let h = Value::handle(NameId(3), 42);
assert_eq!(h.value_type(), ValueType::Handle);
assert_eq!(h.as_handle(), Some((NameId(3), 42)));
assert!(Value::Int(0).as_handle().is_none());
}
#[test]
fn handle_equality_is_token_equality() {
assert_eq!(Value::handle(NameId(1), 42), Value::handle(NameId(1), 42));
assert_ne!(Value::handle(NameId(1), 42), Value::handle(NameId(2), 42));
assert_ne!(Value::handle(NameId(1), 1), Value::handle(NameId(1), 2));
assert_ne!(
Value::handle(NameId(1), 42),
Value::DivertTarget(DefinitionId::new(DefinitionTag::Address, 42))
);
}
#[test]
fn handle_is_not_a_legal_map_key() {
assert_eq!(MapKey::from_value(&Value::handle(NameId(1), 42)), None);
}
#[test]
fn handle_serde_round_trip_is_structural() {
let v = Value::handle(NameId(7), u64::MAX);
let back = json_round_trip(&v);
assert_eq!(back, v);
assert_eq!(back.value_type(), ValueType::Handle);
assert_eq!(back.as_handle(), Some((NameId(7), u64::MAX)));
}
#[test]
fn handle_nested_in_collection_serde_round_trip() {
let v = Value::array(vec![
Value::handle(NameId(1), 1),
Value::handle(NameId(2), 2),
Value::Null,
]);
assert_eq!(json_round_trip(&v), v);
}
#[test]
fn option_value_type_and_constructors() {
assert_eq!(Value::none().value_type(), ValueType::Option);
assert_eq!(Value::some(Value::Int(3)).value_type(), ValueType::Option);
assert_eq!(Value::none().as_option(), Some(None));
assert_eq!(
Value::some(Value::Int(3)).as_option(),
Some(Some(&Value::Int(3)))
);
assert_eq!(Value::Int(3).as_option(), None);
}
#[test]
fn option_equality_is_structural() {
assert_eq!(Value::none(), Value::none());
assert_eq!(Value::some(Value::Int(1)), Value::some(Value::Int(1)));
assert_ne!(Value::some(Value::Int(1)), Value::some(Value::Int(2)));
assert_ne!(Value::some(Value::Int(1)), Value::none());
assert_ne!(Value::some(Value::Int(1)), Value::Int(1));
assert_ne!(Value::none(), Value::Null);
}
#[test]
fn option_nesting_is_preserved() {
let some_none = Value::some(Value::none());
assert_ne!(some_none, Value::none());
assert_eq!(some_none, Value::some(Value::none()));
}
#[test]
fn option_clone_is_arc_bump() {
let v = Value::some(Value::array(vec![Value::Int(1)]));
let v2 = v.clone();
let (Value::OptionVal(Some(a)), Value::OptionVal(Some(b))) = (&v, &v2) else {
unreachable!("both are freshly built some values");
};
assert!(Arc::ptr_eq(a, b), "clone shares the payload Arc");
}
#[test]
fn option_serde_round_trip_is_structural() {
for v in [
Value::none(),
Value::some(Value::Int(7)),
Value::some(Value::none()),
Value::array(vec![Value::none(), Value::some(Value::from("x"))]),
] {
assert_eq!(json_round_trip(&v), v);
}
}
#[test]
fn range_value_type_and_accessors() {
let r = Value::range(1, 6, true);
assert_eq!(r.value_type(), ValueType::Range);
assert_eq!(r.as_range(), Some((1, 6, true)));
assert_eq!(Value::Int(1).as_range(), None);
assert_eq!(r.range_end_exclusive(), Some(7));
assert_eq!(Value::range(1, 7, false).range_end_exclusive(), Some(7));
assert_eq!(r.range_len(), Some(6));
assert_eq!(Value::range(0, 0, false).range_len(), Some(0));
assert_eq!(Value::range(5, 2, false).range_len(), Some(0));
assert_eq!(
Value::range(1, i32::MAX, true).range_end_exclusive(),
Some(i64::from(i32::MAX) + 1)
);
assert_eq!(
Value::range(i32::MIN, i32::MAX, true).range_len(),
Some(1i64 << 32)
);
}
#[test]
fn range_equality_is_content_equality() {
assert_eq!(Value::range(1, 6, true), Value::range(1, 7, false));
assert_eq!(Value::range(1, 7, false), Value::range(1, 6, true));
assert_eq!(Value::range(0, 3, false), Value::range(0, 3, false));
assert_ne!(Value::range(0, 3, false), Value::range(1, 3, false));
assert_ne!(Value::range(0, 3, false), Value::range(0, 4, false));
assert_eq!(Value::range(0, 0, false), Value::range(5, 5, false));
assert_eq!(Value::range(9, 2, false), Value::range(0, 0, false));
assert_ne!(Value::range(0, 0, false), Value::range(0, 1, false));
assert_ne!(Value::range(0, 2, false), Value::array(vec![]));
assert_ne!(Value::range(0, 2, false), Value::Int(0));
}
#[test]
fn range_serde_round_trip_preserves_the_written_form() {
for v in [
Value::range(1, 6, true),
Value::range(0, 10, false),
Value::range(-3, 3, false),
Value::range(0, 0, false),
Value::array(vec![Value::range(1, 2, true), Value::Int(9)]),
] {
let back = json_round_trip(&v);
assert_eq!(back, v);
if let Value::Range { .. } = &v {
assert_eq!(back.as_range(), v.as_range());
}
}
}
}