oxilean_runtime/object/
functions.rs1use super::rtobject_type::RtObject;
6use super::types::{
7 ArrayOps, BigIntData, FieldAccess, HeapObject, ObjectFlags, ObjectHeader, ObjectTable, RtArith,
8 RtObjectCmp, RtObjectPool, StringOps, TypeRegistry, TypeTag,
9};
10
11pub(super) const TAG_HEAP: u8 = 0x00;
13pub(super) const TAG_SMALL_NAT: u8 = 0x01;
15pub(super) const TAG_BOOL: u8 = 0x02;
17pub(super) const TAG_UNIT: u8 = 0x03;
19pub(super) const TAG_CHAR: u8 = 0x04;
21pub(super) const TAG_CTOR: u8 = 0x05;
23pub(super) const TAG_INT: u8 = 0x06;
25pub(super) const TAG_FLOAT_BITS: u8 = 0x07;
27pub(super) const TAG_CLOSURE: u8 = 0x08;
29pub(super) const TAG_ARRAY: u8 = 0x09;
31pub(super) const TAG_STRING: u8 = 0x0A;
33pub(super) const TAG_THUNK: u8 = 0x0B;
35pub(super) const TAG_IO_ACTION: u8 = 0x0C;
37pub(super) const TAG_TASK: u8 = 0x0D;
39pub(super) const TAG_EXTERNAL: u8 = 0x0E;
41pub(super) const _TAG_RESERVED: u8 = 0x0F;
43pub(super) const PAYLOAD_MASK: u64 = 0x00FF_FFFF_FFFF_FFFF;
45pub(super) const MAX_SMALL_NAT: u64 = PAYLOAD_MASK;
47pub(super) const MAX_SMALL_INT: i64 = (1_i64 << 55) - 1;
49pub(super) const MIN_SMALL_INT: i64 = -(1_i64 << 55);
51pub trait BoxInto {
53 fn box_into(self) -> RtObject;
55}
56pub trait UnboxFrom: Sized {
58 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}