1use std::any::Any;
2use std::cmp::Ordering;
3use std::fmt;
4use std::ops::Deref;
5use std::rc::Rc;
6
7use num_bigint::BigInt;
8
9use crate::descriptor::TypeId;
10use crate::error::{PanicKind, SoilError};
11
12pub struct Ref<T: ?Sized>(Rc<T>);
23
24#[cfg(debug_assertions)]
25mod live {
26 use std::cell::Cell;
27
28 thread_local! {
29 static LIVE: Cell<usize> = const { Cell::new(0) };
30 }
31
32 pub fn inc() {
33 LIVE.with(|c| c.set(c.get() + 1));
34 }
35
36 pub fn dec() {
37 LIVE.with(|c| c.set(c.get() - 1));
38 }
39
40 pub fn count() -> usize {
41 LIVE.with(|c| c.get())
42 }
43}
44
45pub fn debug_live_values() -> usize {
50 #[cfg(debug_assertions)]
51 {
52 live::count()
53 }
54 #[cfg(not(debug_assertions))]
55 {
56 0
57 }
58}
59
60impl<T> Ref<T> {
61 pub fn new(value: T) -> Self {
62 #[cfg(debug_assertions)]
63 live::inc();
64 Ref(Rc::new(value))
65 }
66}
67
68impl<T: ?Sized> Ref<T> {
69 pub fn addr(&self) -> usize {
72 Rc::as_ptr(&self.0) as *const () as usize
73 }
74
75 pub fn ptr_eq(a: &Self, b: &Self) -> bool {
76 Rc::ptr_eq(&a.0, &b.0)
77 }
78}
79
80impl From<&str> for Ref<str> {
81 fn from(s: &str) -> Self {
82 #[cfg(debug_assertions)]
83 live::inc();
84 Ref(Rc::from(s))
85 }
86}
87
88impl From<String> for Ref<str> {
89 fn from(s: String) -> Self {
90 #[cfg(debug_assertions)]
91 live::inc();
92 Ref(Rc::from(s.into_boxed_str()))
93 }
94}
95
96impl From<&[u8]> for Ref<[u8]> {
97 fn from(b: &[u8]) -> Self {
98 #[cfg(debug_assertions)]
99 live::inc();
100 Ref(Rc::from(b))
101 }
102}
103
104impl From<Vec<u8>> for Ref<[u8]> {
105 fn from(b: Vec<u8>) -> Self {
106 #[cfg(debug_assertions)]
107 live::inc();
108 Ref(Rc::from(b.into_boxed_slice()))
109 }
110}
111
112impl<T: ?Sized> Clone for Ref<T> {
113 fn clone(&self) -> Self {
114 Ref(self.0.clone())
115 }
116}
117
118impl<T: ?Sized> Drop for Ref<T> {
119 fn drop(&mut self) {
120 #[cfg(debug_assertions)]
121 if Rc::strong_count(&self.0) == 1 {
122 live::dec();
123 }
124 }
125}
126
127impl<T: ?Sized> Deref for Ref<T> {
128 type Target = T;
129
130 fn deref(&self) -> &T {
131 &self.0
132 }
133}
134
135impl<T: ?Sized + fmt::Debug> fmt::Debug for Ref<T> {
136 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
137 self.0.fmt(f)
138 }
139}
140
141#[derive(Clone, Debug)]
148pub enum Value {
149 I64(i64),
150 U64(u64),
151 I32(i32),
152 U32(u32),
153 I16(i16),
154 U16(u16),
155 I8(i8),
156 U8(u8),
157 F64(f64),
158 BigInt(Ref<BigInt>),
159 Utf8(Ref<str>),
160 Bytes(Ref<[u8]>),
161 Unit,
162 Record(Ref<Record>),
163 Sum(Ref<SumVal>),
164 List(Ref<Vec<Value>>),
165 Map(Ref<MapVal>),
166 Closure(Ref<Closure>),
167 Opaque(Ref<OpaqueVal>),
168}
169
170#[derive(Debug)]
173pub struct Record {
174 pub type_id: TypeId,
175 pub fields: Box<[Value]>,
176}
177
178#[derive(Debug)]
181pub struct SumVal {
182 pub type_id: TypeId,
183 pub variant: u32,
184 pub payload: Option<Value>,
185}
186
187pub struct OpaqueVal {
192 pub type_id: TypeId,
193 pub payload: Box<dyn Any>,
194}
195
196impl fmt::Debug for OpaqueVal {
197 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
198 write!(f, "<handle:{:?}>", self.type_id)
199 }
200}
201
202pub type ClosureFn = Box<dyn Fn(&[Value]) -> Result<Value, SoilError>>;
207
208pub struct Closure {
209 f: ClosureFn,
210}
211
212impl Closure {
213 pub fn native(f: impl Fn(&[Value]) -> Result<Value, SoilError> + 'static) -> Self {
214 Closure { f: Box::new(f) }
215 }
216
217 pub fn call(&self, args: &[Value]) -> Result<Value, SoilError> {
218 (self.f)(args)
219 }
220}
221
222impl fmt::Debug for Closure {
223 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
224 write!(f, "<closure>")
225 }
226}
227
228#[derive(Debug)]
236pub enum MapOrder {
237 Structural,
238 Custom(Ref<Closure>),
239}
240
241#[derive(Debug)]
253pub struct MapVal {
254 order: MapOrder,
255 entries: Vec<(Value, Value)>,
256}
257
258impl MapVal {
259 pub fn new(order: MapOrder) -> Self {
260 MapVal {
261 order,
262 entries: Vec::new(),
263 }
264 }
265
266 pub fn order(&self) -> &MapOrder {
267 &self.order
268 }
269
270 pub fn entries(&self) -> &[(Value, Value)] {
272 &self.entries
273 }
274
275 pub fn len(&self) -> usize {
276 self.entries.len()
277 }
278
279 pub fn is_empty(&self) -> bool {
280 self.entries.is_empty()
281 }
282
283 fn compare_keys(
284 &self,
285 runtime: &crate::Runtime,
286 a: &Value,
287 b: &Value,
288 ) -> Result<Ordering, SoilError> {
289 match &self.order {
290 MapOrder::Structural => crate::ops::compare(runtime, a, b),
291 MapOrder::Custom(comparator) => {
292 let result = comparator.call(&[a.clone(), b.clone()])?;
293 match result {
294 Value::I64(n) => Ok(n.cmp(&0)),
295 other => Err(SoilError::new(
296 PanicKind::TypeError,
297 format!("map comparator returned {other:?}, expected I64"),
298 )),
299 }
300 }
301 }
302 }
303
304 fn search(
307 &self,
308 runtime: &crate::Runtime,
309 key: &Value,
310 ) -> Result<Result<usize, usize>, SoilError> {
311 let mut lo = 0usize;
312 let mut hi = self.entries.len();
313 while lo < hi {
314 let mid = lo + (hi - lo) / 2;
315 match self.compare_keys(runtime, &self.entries[mid].0, key)? {
316 Ordering::Less => lo = mid + 1,
317 Ordering::Greater => hi = mid,
318 Ordering::Equal => return Ok(Ok(mid)),
319 }
320 }
321 Ok(Err(lo))
322 }
323
324 pub fn get(&self, runtime: &crate::Runtime, key: &Value) -> Result<Option<&Value>, SoilError> {
325 Ok(self.search(runtime, key)?.ok().map(|i| &self.entries[i].1))
326 }
327
328 pub fn insert(
332 &mut self,
333 runtime: &crate::Runtime,
334 key: Value,
335 value: Value,
336 ) -> Result<(), SoilError> {
337 match self.search(runtime, &key)? {
338 Ok(i) => self.entries[i].1 = value,
339 Err(i) => self.entries.insert(i, (key, value)),
340 }
341 Ok(())
342 }
343
344 pub fn remove(
345 &mut self,
346 runtime: &crate::Runtime,
347 key: &Value,
348 ) -> Result<Option<Value>, SoilError> {
349 match self.search(runtime, key)? {
350 Ok(i) => Ok(Some(self.entries.remove(i).1)),
351 Err(_) => Ok(None),
352 }
353 }
354}
355
356#[cfg(test)]
357mod tests {
358 use super::*;
359
360 fn i64_comparator() -> Ref<Closure> {
361 Ref::new(Closure::native(|args| match (&args[0], &args[1]) {
362 (Value::I64(a), Value::I64(b)) => Ok(Value::I64(match a.cmp(b) {
363 Ordering::Less => -1,
364 Ordering::Equal => 0,
365 Ordering::Greater => 1,
366 })),
367 _ => Err(SoilError::new(PanicKind::TypeError, "expected I64 keys")),
368 }))
369 }
370
371 #[test]
372 fn value_is_at_most_three_words() {
373 assert!(std::mem::size_of::<Value>() <= 24);
374 }
375
376 #[test]
377 fn refcounting_returns_to_zero() {
378 let before = debug_live_values();
379 {
380 let a = Ref::new(vec![Value::I64(1), Value::Unit]);
381 let b = a.clone();
382 assert!(Ref::ptr_eq(&a, &b));
383 assert_eq!(debug_live_values(), before + 1);
384 let s: Ref<str> = Ref::from("hello");
385 assert_eq!(&*s, "hello");
386 assert_eq!(debug_live_values(), before + 2);
387 }
388 assert_eq!(debug_live_values(), before);
389 }
390
391 #[test]
392 fn nested_values_release_on_drop() {
393 let before = debug_live_values();
394 {
395 let inner: Ref<str> = Ref::from("payload");
396 let list = Value::List(Ref::new(vec![Value::Utf8(inner)]));
397 let copy = list.clone();
398 drop(list);
399 assert_eq!(debug_live_values(), before + 2);
400 drop(copy);
401 }
402 assert_eq!(debug_live_values(), before);
403 }
404
405 #[test]
406 fn closure_invocation() {
407 let double = Closure::native(|args| match args {
408 [Value::I64(n)] => Ok(Value::I64(n * 2)),
409 _ => Err(SoilError::new(PanicKind::TypeError, "expected one I64")),
410 });
411 match double.call(&[Value::I64(21)]) {
412 Ok(Value::I64(42)) => {}
413 other => panic!("unexpected result: {other:?}"),
414 }
415 assert!(double.call(&[Value::Unit]).is_err());
416 }
417
418 #[test]
419 fn map_insert_get_remove_in_comparator_order() {
420 let rt = crate::Runtime::new();
421 let mut map = MapVal::new(MapOrder::Custom(i64_comparator()));
422 for k in [30i64, 10, 20, 10] {
423 map.insert(&rt, Value::I64(k), Value::I64(k * 100)).unwrap();
424 }
425 assert_eq!(map.len(), 3);
426 let keys: Vec<i64> = map
427 .entries()
428 .iter()
429 .map(|(k, _)| match k {
430 Value::I64(n) => *n,
431 _ => unreachable!(),
432 })
433 .collect();
434 assert_eq!(keys, vec![10, 20, 30]);
435
436 match map.get(&rt, &Value::I64(20)).unwrap() {
437 Some(Value::I64(2000)) => {}
438 other => panic!("unexpected: {other:?}"),
439 }
440 assert!(map.get(&rt, &Value::I64(99)).unwrap().is_none());
441
442 match map.remove(&rt, &Value::I64(10)).unwrap() {
443 Some(Value::I64(1000)) => {}
444 other => panic!("unexpected: {other:?}"),
445 }
446 assert_eq!(map.len(), 2);
447 assert!(map.remove(&rt, &Value::I64(10)).unwrap().is_none());
448 }
449
450 #[test]
451 fn map_structural_order_uses_derived_compare() {
452 let rt = crate::Runtime::new();
453 let mut map = MapVal::new(MapOrder::Structural);
454 for k in [30i64, 10, 20] {
455 map.insert(&rt, Value::I64(k), Value::Unit).unwrap();
456 }
457 let keys: Vec<i64> = map
458 .entries()
459 .iter()
460 .map(|(k, _)| match k {
461 Value::I64(n) => *n,
462 _ => unreachable!(),
463 })
464 .collect();
465 assert_eq!(keys, vec![10, 20, 30]);
466 }
467
468 #[test]
469 fn map_comparator_errors_propagate() {
470 let rt = crate::Runtime::new();
471 let mut map = MapVal::new(MapOrder::Custom(Ref::new(Closure::native(|_| {
472 Err(SoilError::new(PanicKind::TypeError, "always fails"))
473 }))));
474 assert!(map.insert(&rt, Value::I64(1), Value::Unit).is_ok());
475 assert!(map.insert(&rt, Value::I64(2), Value::Unit).is_err());
476 }
477
478 #[test]
479 fn opaque_identity_is_address() {
480 let a = Ref::new(OpaqueVal {
481 type_id: TypeId(0),
482 payload: Box::new(7u8),
483 });
484 let b = a.clone();
485 let c = Ref::new(OpaqueVal {
486 type_id: TypeId(0),
487 payload: Box::new(7u8),
488 });
489 assert_eq!(a.addr(), b.addr());
490 assert_ne!(a.addr(), c.addr());
491 }
492}