Skip to main content

oxilean_runtime/object/
functions.rs

1//! Auto-generated module
2//!
3//! 🤖 Generated with [SplitRS](https://github.com/cool-japan/splitrs)
4
5use super::rtobject_type::RtObject;
6use super::types::{
7    ArrayOps, BigIntData, FieldAccess, HeapObject, ObjectFlags, ObjectHeader, ObjectTable, RtArith,
8    RtObjectCmp, RtObjectPool, StringOps, TypeRegistry, TypeTag,
9};
10
11/// Tag for heap-allocated objects.
12pub(super) const TAG_HEAP: u8 = 0x00;
13/// Tag for small natural numbers.
14pub(super) const TAG_SMALL_NAT: u8 = 0x01;
15/// Tag for boolean values.
16pub(super) const TAG_BOOL: u8 = 0x02;
17/// Tag for the unit value.
18pub(super) const TAG_UNIT: u8 = 0x03;
19/// Tag for character values.
20pub(super) const TAG_CHAR: u8 = 0x04;
21/// Tag for small constructor indices.
22pub(super) const TAG_CTOR: u8 = 0x05;
23/// Tag for signed integers.
24pub(super) const TAG_INT: u8 = 0x06;
25/// Tag for float bit patterns (reduced precision).
26pub(super) const TAG_FLOAT_BITS: u8 = 0x07;
27/// Tag for closure references.
28pub(super) const TAG_CLOSURE: u8 = 0x08;
29/// Tag for array references.
30pub(super) const TAG_ARRAY: u8 = 0x09;
31/// Tag for string references.
32pub(super) const TAG_STRING: u8 = 0x0A;
33/// Tag for thunk references.
34pub(super) const TAG_THUNK: u8 = 0x0B;
35/// Tag for IO action references.
36pub(super) const TAG_IO_ACTION: u8 = 0x0C;
37/// Tag for task references.
38pub(super) const TAG_TASK: u8 = 0x0D;
39/// Tag for external/opaque references.
40pub(super) const TAG_EXTERNAL: u8 = 0x0E;
41/// Reserved tag.
42pub(super) const _TAG_RESERVED: u8 = 0x0F;
43/// Mask for extracting the 56-bit payload from a tagged u64.
44pub(super) const PAYLOAD_MASK: u64 = 0x00FF_FFFF_FFFF_FFFF;
45/// Maximum value for a small natural number.
46pub(super) const MAX_SMALL_NAT: u64 = PAYLOAD_MASK;
47/// Maximum value for an inline signed integer (55-bit magnitude + sign).
48pub(super) const MAX_SMALL_INT: i64 = (1_i64 << 55) - 1;
49/// Minimum value for an inline signed integer.
50pub(super) const MIN_SMALL_INT: i64 = -(1_i64 << 55);
51/// Type-safe boxing of Rust primitives into `RtObject`.
52pub trait BoxInto {
53    /// Box this value into an `RtObject`.
54    fn box_into(self) -> RtObject;
55}
56/// Type-safe unboxing of `RtObject` into Rust primitives.
57pub trait UnboxFrom: Sized {
58    /// Try to unbox an `RtObject` into this type.
59    fn unbox_from(obj: &RtObject) -> Option<Self>;
60}
61impl BoxInto for bool {
62    fn box_into(self) -> RtObject {
63        RtObject::bool_val(self)
64    }
65}
66impl UnboxFrom for bool {
67    fn unbox_from(obj: &RtObject) -> Option<Self> {
68        obj.as_bool()
69    }
70}
71impl BoxInto for u64 {
72    fn box_into(self) -> RtObject {
73        RtObject::nat(self)
74    }
75}
76impl UnboxFrom for u64 {
77    fn unbox_from(obj: &RtObject) -> Option<Self> {
78        obj.as_small_nat()
79    }
80}
81impl BoxInto for i64 {
82    fn box_into(self) -> RtObject {
83        RtObject::small_int(self).unwrap_or_else(|| {
84            let negative = self < 0;
85            let magnitude = if negative {
86                (self as i128).unsigned_abs() as u64
87            } else {
88                self as u64
89            };
90            let heap = HeapObject::BigInt(BigIntData {
91                header: ObjectHeader::new(TypeTag::BigInt, 2),
92                negative,
93                digits: vec![magnitude],
94            });
95            RtObject::from_heap(heap)
96        })
97    }
98}
99impl UnboxFrom for i64 {
100    fn unbox_from(obj: &RtObject) -> Option<Self> {
101        obj.as_small_int()
102    }
103}
104impl BoxInto for char {
105    fn box_into(self) -> RtObject {
106        RtObject::char_val(self)
107    }
108}
109impl UnboxFrom for char {
110    fn unbox_from(obj: &RtObject) -> Option<Self> {
111        obj.as_char()
112    }
113}
114impl BoxInto for f64 {
115    fn box_into(self) -> RtObject {
116        RtObject::boxed_float(self)
117    }
118}
119impl BoxInto for String {
120    fn box_into(self) -> RtObject {
121        RtObject::string(self)
122    }
123}
124impl BoxInto for &str {
125    fn box_into(self) -> RtObject {
126        RtObject::string(self.to_string())
127    }
128}
129impl BoxInto for () {
130    fn box_into(self) -> RtObject {
131        RtObject::unit()
132    }
133}
134impl UnboxFrom for () {
135    fn unbox_from(obj: &RtObject) -> Option<Self> {
136        if obj.is_unit() {
137            Some(())
138        } else {
139            None
140        }
141    }
142}
143#[cfg(test)]
144mod tests {
145    use super::*;
146    #[test]
147    fn test_small_nat() {
148        let n = RtObject::nat(42);
149        assert!(n.is_nat());
150        assert_eq!(n.as_small_nat(), Some(42));
151    }
152    #[test]
153    fn test_bool() {
154        let t = RtObject::bool_val(true);
155        let f = RtObject::bool_val(false);
156        assert_eq!(t.as_bool(), Some(true));
157        assert_eq!(f.as_bool(), Some(false));
158    }
159    #[test]
160    fn test_unit() {
161        let u = RtObject::unit();
162        assert!(u.is_unit());
163    }
164    #[test]
165    fn test_char() {
166        let c = RtObject::char_val('A');
167        assert_eq!(c.as_char(), Some('A'));
168    }
169    #[test]
170    fn test_small_int() {
171        let positive = RtObject::small_int(42).expect("test operation should succeed");
172        assert_eq!(positive.as_small_int(), Some(42));
173        let negative = RtObject::small_int(-7).expect("test operation should succeed");
174        assert_eq!(negative.as_small_int(), Some(-7));
175    }
176    #[test]
177    fn test_object_header_encode_decode() {
178        let header = ObjectHeader::new(TypeTag::Closure, 5);
179        let encoded = header.encode();
180        let decoded = ObjectHeader::decode(encoded).expect("test operation should succeed");
181        assert_eq!(decoded.type_tag, TypeTag::Closure);
182        assert_eq!(decoded.size_words, 5);
183        assert_eq!(decoded.rc_count, 1);
184    }
185    #[test]
186    fn test_object_flags() {
187        let mut flags = ObjectFlags::empty();
188        assert!(!flags.has(ObjectFlags::pinned()));
189        flags.set(ObjectFlags::pinned());
190        assert!(flags.has(ObjectFlags::pinned()));
191        flags.clear(ObjectFlags::pinned());
192        assert!(!flags.has(ObjectFlags::pinned()));
193    }
194    #[test]
195    fn test_nat_arithmetic() {
196        let a = RtObject::nat(10);
197        let b = RtObject::nat(3);
198        assert_eq!(
199            RtArith::nat_add(&a, &b)
200                .expect("type conversion should succeed")
201                .as_small_nat(),
202            Some(13)
203        );
204        assert_eq!(
205            RtArith::nat_sub(&a, &b)
206                .expect("type conversion should succeed")
207                .as_small_nat(),
208            Some(7)
209        );
210        assert_eq!(
211            RtArith::nat_mul(&a, &b)
212                .expect("type conversion should succeed")
213                .as_small_nat(),
214            Some(30)
215        );
216        assert_eq!(
217            RtArith::nat_div(&a, &b)
218                .expect("type conversion should succeed")
219                .as_small_nat(),
220            Some(3)
221        );
222        assert_eq!(
223            RtArith::nat_mod(&a, &b)
224                .expect("type conversion should succeed")
225                .as_small_nat(),
226            Some(1)
227        );
228    }
229    #[test]
230    fn test_object_table() {
231        let mut table = ObjectTable::new();
232        table.insert("x".to_string(), RtObject::nat(42));
233        table.insert("y".to_string(), RtObject::bool_val(true));
234        assert_eq!(table.len(), 2);
235        assert_eq!(
236            table
237                .get("x")
238                .expect("key should exist in map")
239                .as_small_nat(),
240            Some(42)
241        );
242        assert!(table.contains("y"));
243    }
244    #[test]
245    fn test_type_registry_builtins() {
246        let mut registry = TypeRegistry::new();
247        registry.register_builtins();
248        assert!(registry.lookup("Nat").is_some());
249        assert!(registry.lookup("Bool").is_some());
250        assert!(registry.lookup("Unit").is_some());
251        assert!(registry.lookup("List").is_some());
252    }
253    #[test]
254    fn test_boxing() {
255        let b: RtObject = true.box_into();
256        assert_eq!(bool::unbox_from(&b), Some(true));
257        let n: RtObject = 42u64.box_into();
258        assert_eq!(u64::unbox_from(&n), Some(42));
259        let u: RtObject = ().box_into();
260        assert_eq!(<()>::unbox_from(&u), Some(()));
261    }
262    #[test]
263    fn test_string_object() {
264        let s = RtObject::string("hello".to_string());
265        assert!(s.is_string_ref());
266        assert_eq!(StringOps::as_str(&s), Some("hello".to_string()));
267        assert_eq!(StringOps::byte_len(&s), Some(5));
268    }
269    #[test]
270    fn test_array_object() {
271        let arr = RtObject::array(vec![RtObject::nat(1), RtObject::nat(2), RtObject::nat(3)]);
272        assert_eq!(ArrayOps::len(&arr), Some(3));
273        assert_eq!(
274            ArrayOps::get(&arr, 1)
275                .expect("type conversion should succeed")
276                .as_small_nat(),
277            Some(2)
278        );
279    }
280    #[test]
281    fn test_constructor_fields() {
282        let pair = RtObject::constructor(0, vec![RtObject::nat(1), RtObject::nat(2)]);
283        assert_eq!(FieldAccess::get_ctor_index(&pair), Some(0));
284        assert_eq!(FieldAccess::num_fields(&pair), Some(2));
285        assert_eq!(
286            FieldAccess::proj_fst(&pair)
287                .expect("type conversion should succeed")
288                .as_small_nat(),
289            Some(1)
290        );
291        assert_eq!(
292            FieldAccess::proj_snd(&pair)
293                .expect("type conversion should succeed")
294                .as_small_nat(),
295            Some(2)
296        );
297    }
298    #[test]
299    fn test_bool_ops() {
300        let t = RtObject::bool_val(true);
301        let f = RtObject::bool_val(false);
302        assert_eq!(
303            RtArith::bool_and(&t, &f)
304                .expect("type conversion should succeed")
305                .as_bool(),
306            Some(false)
307        );
308        assert_eq!(
309            RtArith::bool_or(&t, &f)
310                .expect("type conversion should succeed")
311                .as_bool(),
312            Some(true)
313        );
314        assert_eq!(
315            RtArith::bool_not(&t)
316                .expect("type conversion should succeed")
317                .as_bool(),
318            Some(false)
319        );
320    }
321}
322#[cfg(test)]
323mod extra_object_tests {
324    use super::*;
325    #[test]
326    fn test_numeric_eq_int() {
327        let a = RtObject::small_int(10).expect("test operation should succeed");
328        let b = RtObject::small_int(10).expect("test operation should succeed");
329        let c = RtObject::small_int(11).expect("test operation should succeed");
330        assert!(RtObjectCmp::numeric_eq(&a, &b));
331        assert!(!RtObjectCmp::numeric_eq(&a, &c));
332    }
333    #[test]
334    fn test_int_lt() {
335        let a = RtObject::small_int(3).expect("test operation should succeed");
336        let b = RtObject::small_int(5).expect("test operation should succeed");
337        assert_eq!(RtObjectCmp::int_lt(&a, &b), Some(true));
338        assert_eq!(RtObjectCmp::int_lt(&b, &a), Some(false));
339    }
340    #[test]
341    fn test_object_pool() {
342        let mut pool = RtObjectPool::new();
343        let obj = pool.acquire_unit();
344        pool.release(obj);
345        assert_eq!(pool.free_count(), 1);
346        let _ = pool.acquire_unit();
347        assert_eq!(pool.free_count(), 0);
348    }
349}