1use std::rc::Rc;
35
36use crate::value::FunctionValue;
37
38pub type PersistentMap = im::HashMap<u64, (NanValue, NanValue)>;
40
41const QNAN: u64 = 0x7FFC_0000_0000_0000;
46const QNAN_MASK: u64 = 0xFFFC_0000_0000_0000;
47const TAG_SHIFT: u32 = 46;
48const TAG_MASK: u64 = 0xF;
49const PAYLOAD_MASK: u64 = (1u64 << 46) - 1;
50
51const TAG_INT: u64 = 0;
52const TAG_IMMEDIATE: u64 = 1;
53const TAG_WRAPPER: u64 = 2;
54const TAG_STRING: u64 = 3;
55const TAG_LIST: u64 = 4;
56const TAG_TUPLE: u64 = 5;
57const TAG_MAP: u64 = 6;
58const TAG_RECORD: u64 = 7;
59const TAG_VARIANT: u64 = 8;
60const TAG_FN: u64 = 9;
61const TAG_BUILTIN: u64 = 10;
62const TAG_NAMESPACE: u64 = 11;
63
64const IMM_FALSE: u64 = 0;
65const IMM_TRUE: u64 = 1;
66const IMM_UNIT: u64 = 2;
67const IMM_NONE: u64 = 3;
68
69const WRAP_SOME: u64 = 0;
70const WRAP_OK: u64 = 1;
71const WRAP_ERR: u64 = 2;
72
73const INT_BIG_BIT: u64 = 1u64 << 45;
74const INT_INLINE_MASK: u64 = (1u64 << 45) - 1;
75const INT_INLINE_MAX: i64 = (1i64 << 44) - 1;
76const INT_INLINE_MIN: i64 = -(1i64 << 44);
77
78#[derive(Clone, Copy)]
83pub struct NanValue(u64);
84
85impl NanValue {
88 #[inline]
89 fn encode(tag: u64, payload: u64) -> Self {
90 debug_assert!(tag <= TAG_MASK);
91 debug_assert!(payload <= PAYLOAD_MASK);
92 NanValue(QNAN | (tag << TAG_SHIFT) | payload)
93 }
94
95 #[inline]
96 fn is_nan_boxed(self) -> bool {
97 (self.0 & QNAN_MASK) == QNAN
98 }
99
100 #[inline]
101 fn tag(self) -> u64 {
102 (self.0 >> TAG_SHIFT) & TAG_MASK
103 }
104
105 #[inline]
106 fn payload(self) -> u64 {
107 self.0 & PAYLOAD_MASK
108 }
109
110 #[inline]
113 pub fn new_float(f: f64) -> Self {
114 let bits = f.to_bits();
115 if (bits & QNAN_MASK) == QNAN {
116 NanValue(bits ^ 1)
117 } else {
118 NanValue(bits)
119 }
120 }
121
122 #[inline]
123 pub fn as_float(self) -> f64 {
124 f64::from_bits(self.0)
125 }
126
127 #[inline]
128 pub fn new_int_inline(i: i64) -> Self {
129 debug_assert!((INT_INLINE_MIN..=INT_INLINE_MAX).contains(&i));
130 let payload = (i as u64) & INT_INLINE_MASK;
131 Self::encode(TAG_INT, payload)
132 }
133
134 #[inline]
135 pub fn new_int_arena(arena_index: u32) -> Self {
136 Self::encode(TAG_INT, INT_BIG_BIT | (arena_index as u64))
137 }
138
139 #[inline]
140 pub fn new_int(i: i64, arena: &mut Arena) -> Self {
141 if (INT_INLINE_MIN..=INT_INLINE_MAX).contains(&i) {
142 Self::new_int_inline(i)
143 } else {
144 let idx = arena.push_i64(i);
145 Self::new_int_arena(idx)
146 }
147 }
148
149 #[inline]
150 pub fn as_int(self, arena: &Arena) -> i64 {
151 let p = self.payload();
152 if p & INT_BIG_BIT != 0 {
153 let idx = (p & !INT_BIG_BIT) as u32;
154 arena.get_i64(idx)
155 } else {
156 let raw = p & INT_INLINE_MASK;
157 if raw & (1u64 << 44) != 0 {
158 (raw | !INT_INLINE_MASK) as i64
159 } else {
160 raw as i64
161 }
162 }
163 }
164
165 pub const FALSE: NanValue = NanValue(QNAN | (TAG_IMMEDIATE << TAG_SHIFT) | IMM_FALSE);
168 pub const TRUE: NanValue = NanValue(QNAN | (TAG_IMMEDIATE << TAG_SHIFT) | IMM_TRUE);
169 pub const UNIT: NanValue = NanValue(QNAN | (TAG_IMMEDIATE << TAG_SHIFT) | IMM_UNIT);
170 pub const NONE: NanValue = NanValue(QNAN | (TAG_IMMEDIATE << TAG_SHIFT) | IMM_NONE);
171
172 #[inline]
173 pub fn new_bool(b: bool) -> Self {
174 if b { Self::TRUE } else { Self::FALSE }
175 }
176
177 #[inline]
178 pub fn as_bool(self) -> bool {
179 self.0 == Self::TRUE.0
180 }
181
182 #[inline]
185 pub fn new_some(inner_index: u32) -> Self {
186 Self::encode(TAG_WRAPPER, WRAP_SOME | ((inner_index as u64) << 2))
187 }
188
189 #[inline]
190 pub fn new_ok(inner_index: u32) -> Self {
191 Self::encode(TAG_WRAPPER, WRAP_OK | ((inner_index as u64) << 2))
192 }
193
194 #[inline]
195 pub fn new_err(inner_index: u32) -> Self {
196 Self::encode(TAG_WRAPPER, WRAP_ERR | ((inner_index as u64) << 2))
197 }
198
199 #[inline]
200 pub fn wrapper_kind(self) -> u64 {
201 self.payload() & 3
202 }
203
204 #[inline]
205 pub fn wrapper_index(self) -> u32 {
206 (self.payload() >> 2) as u32
207 }
208
209 #[inline]
212 pub fn new_string(arena_index: u32) -> Self {
213 Self::encode(TAG_STRING, arena_index as u64)
214 }
215
216 #[inline]
217 pub fn new_list(arena_index: u32) -> Self {
218 Self::encode(TAG_LIST, arena_index as u64)
219 }
220
221 #[inline]
222 pub fn new_tuple(arena_index: u32) -> Self {
223 Self::encode(TAG_TUPLE, arena_index as u64)
224 }
225
226 #[inline]
227 pub fn new_map(arena_index: u32) -> Self {
228 Self::encode(TAG_MAP, arena_index as u64)
229 }
230
231 #[inline]
232 pub fn new_record(arena_index: u32) -> Self {
233 Self::encode(TAG_RECORD, arena_index as u64)
234 }
235
236 #[inline]
237 pub fn new_variant(arena_index: u32) -> Self {
238 Self::encode(TAG_VARIANT, arena_index as u64)
239 }
240
241 #[inline]
242 pub fn new_fn(arena_index: u32) -> Self {
243 Self::encode(TAG_FN, arena_index as u64)
244 }
245
246 #[inline]
247 pub fn new_builtin(arena_index: u32) -> Self {
248 Self::encode(TAG_BUILTIN, arena_index as u64)
249 }
250
251 #[inline]
252 pub fn new_namespace(arena_index: u32) -> Self {
253 Self::encode(TAG_NAMESPACE, arena_index as u64)
254 }
255
256 #[inline]
257 pub fn arena_index(self) -> u32 {
258 self.payload() as u32
259 }
260
261 #[inline]
262 pub fn heap_index(self) -> Option<u32> {
263 if !self.is_nan_boxed() {
264 return None;
265 }
266 match self.tag() {
267 TAG_INT => {
268 let p = self.payload();
269 if p & INT_BIG_BIT != 0 {
270 Some((p & !INT_BIG_BIT) as u32)
271 } else {
272 None
273 }
274 }
275 TAG_WRAPPER => Some(self.wrapper_index()),
276 TAG_STRING | TAG_LIST | TAG_TUPLE | TAG_MAP | TAG_RECORD | TAG_VARIANT | TAG_FN
277 | TAG_BUILTIN | TAG_NAMESPACE => Some(self.arena_index()),
278 _ => None,
279 }
280 }
281
282 #[inline]
283 pub fn with_heap_index(self, index: u32) -> Self {
284 if !self.is_nan_boxed() {
285 return self;
286 }
287 match self.tag() {
288 TAG_INT => {
289 debug_assert!(self.payload() & INT_BIG_BIT != 0);
290 Self::new_int_arena(index)
291 }
292 TAG_WRAPPER => match self.wrapper_kind() {
293 WRAP_SOME => Self::new_some(index),
294 WRAP_OK => Self::new_ok(index),
295 WRAP_ERR => Self::new_err(index),
296 _ => self,
297 },
298 TAG_STRING => Self::new_string(index),
299 TAG_LIST => Self::new_list(index),
300 TAG_TUPLE => Self::new_tuple(index),
301 TAG_MAP => Self::new_map(index),
302 TAG_RECORD => Self::new_record(index),
303 TAG_VARIANT => Self::new_variant(index),
304 TAG_FN => Self::new_fn(index),
305 TAG_BUILTIN => Self::new_builtin(index),
306 TAG_NAMESPACE => Self::new_namespace(index),
307 _ => self,
308 }
309 }
310
311 #[inline]
314 pub fn is_float(self) -> bool {
315 !self.is_nan_boxed()
316 }
317
318 #[inline]
319 pub fn is_int(self) -> bool {
320 self.is_nan_boxed() && self.tag() == TAG_INT
321 }
322
323 #[inline]
324 pub fn is_bool(self) -> bool {
325 self.is_nan_boxed()
326 && self.tag() == TAG_IMMEDIATE
327 && (self.payload() == IMM_TRUE || self.payload() == IMM_FALSE)
328 }
329
330 #[inline]
331 pub fn is_unit(self) -> bool {
332 self.0 == Self::UNIT.0
333 }
334
335 #[inline]
336 pub fn is_none(self) -> bool {
337 self.0 == Self::NONE.0
338 }
339
340 #[inline]
341 pub fn is_some(self) -> bool {
342 self.is_nan_boxed() && self.tag() == TAG_WRAPPER && self.wrapper_kind() == WRAP_SOME
343 }
344
345 #[inline]
346 pub fn is_ok(self) -> bool {
347 self.is_nan_boxed() && self.tag() == TAG_WRAPPER && self.wrapper_kind() == WRAP_OK
348 }
349
350 #[inline]
351 pub fn is_err(self) -> bool {
352 self.is_nan_boxed() && self.tag() == TAG_WRAPPER && self.wrapper_kind() == WRAP_ERR
353 }
354
355 #[inline]
356 pub fn is_string(self) -> bool {
357 self.is_nan_boxed() && self.tag() == TAG_STRING
358 }
359
360 #[inline]
361 pub fn is_list(self) -> bool {
362 self.is_nan_boxed() && self.tag() == TAG_LIST
363 }
364
365 #[inline]
366 pub fn is_record(self) -> bool {
367 self.is_nan_boxed() && self.tag() == TAG_RECORD
368 }
369
370 #[inline]
371 pub fn is_fn(self) -> bool {
372 self.is_nan_boxed() && self.tag() == TAG_FN
373 }
374
375 #[inline]
376 pub fn is_variant(self) -> bool {
377 self.is_nan_boxed() && self.tag() == TAG_VARIANT
378 }
379
380 #[inline]
381 pub fn is_map(self) -> bool {
382 self.is_nan_boxed() && self.tag() == TAG_MAP
383 }
384
385 #[inline]
386 pub fn is_tuple(self) -> bool {
387 self.is_nan_boxed() && self.tag() == TAG_TUPLE
388 }
389
390 #[inline]
391 pub fn is_builtin(self) -> bool {
392 self.is_nan_boxed() && self.tag() == TAG_BUILTIN
393 }
394
395 #[inline]
396 pub fn is_namespace(self) -> bool {
397 self.is_nan_boxed() && self.tag() == TAG_NAMESPACE
398 }
399
400 pub fn type_name(self) -> &'static str {
401 if self.is_float() {
402 return "Float";
403 }
404 match self.tag() {
405 TAG_INT => "Int",
406 TAG_IMMEDIATE => match self.payload() {
407 IMM_FALSE | IMM_TRUE => "Bool",
408 IMM_UNIT => "Unit",
409 IMM_NONE => "Option.None",
410 _ => "Unknown",
411 },
412 TAG_WRAPPER => match self.wrapper_kind() {
413 WRAP_SOME => "Option.Some",
414 WRAP_OK => "Result.Ok",
415 WRAP_ERR => "Result.Err",
416 _ => "Unknown",
417 },
418 TAG_STRING => "String",
419 TAG_LIST => "List",
420 TAG_TUPLE => "Tuple",
421 TAG_MAP => "Map",
422 TAG_RECORD => "Record",
423 TAG_VARIANT => "Variant",
424 TAG_FN => "Fn",
425 TAG_BUILTIN => "Builtin",
426 TAG_NAMESPACE => "Namespace",
427 _ => "Unknown",
428 }
429 }
430
431 #[inline]
433 pub fn bits(self) -> u64 {
434 self.0
435 }
436
437 pub fn map_key_hash(self, arena: &Arena) -> u64 {
442 if self.is_string() {
443 use std::hash::{Hash, Hasher};
444 let mut hasher = std::collections::hash_map::DefaultHasher::new();
445 3u8.hash(&mut hasher);
446 arena.get_string(self.arena_index()).hash(&mut hasher);
447 hasher.finish()
448 } else {
449 self.bits()
450 }
451 }
452}
453
454impl std::fmt::Debug for NanValue {
457 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
458 if self.is_float() {
459 return write!(f, "Float({})", self.as_float());
460 }
461 match self.tag() {
462 TAG_INT => {
463 if self.payload() & INT_BIG_BIT != 0 {
464 write!(f, "Int(arena:{})", (self.payload() & !INT_BIG_BIT) as u32)
465 } else {
466 let raw = self.payload() & INT_INLINE_MASK;
467 let val = if raw & (1u64 << 44) != 0 {
468 (raw | !INT_INLINE_MASK) as i64
469 } else {
470 raw as i64
471 };
472 write!(f, "Int({})", val)
473 }
474 }
475 TAG_IMMEDIATE => match self.payload() {
476 IMM_FALSE => write!(f, "False"),
477 IMM_TRUE => write!(f, "True"),
478 IMM_UNIT => write!(f, "Unit"),
479 IMM_NONE => write!(f, "None"),
480 _ => write!(f, "Immediate({})", self.payload()),
481 },
482 TAG_WRAPPER => {
483 let kind = match self.wrapper_kind() {
484 WRAP_SOME => "Some",
485 WRAP_OK => "Ok",
486 WRAP_ERR => "Err",
487 _ => "?",
488 };
489 write!(f, "{}(arena:{})", kind, self.wrapper_index())
490 }
491 _ => write!(f, "{}(arena:{})", self.type_name(), self.arena_index()),
492 }
493 }
494}
495
496#[derive(Debug, Clone)]
501pub struct Arena {
502 young_entries: Vec<ArenaEntry>,
503 yard_entries: Vec<ArenaEntry>,
504 handoff_entries: Vec<ArenaEntry>,
505 stable_entries: Vec<ArenaEntry>,
506 scratch_young: Vec<u32>,
507 scratch_yard: Vec<u32>,
508 scratch_handoff: Vec<u32>,
509 scratch_stable: Vec<u32>,
510 peak_usage: ArenaUsage,
511 alloc_space: AllocSpace,
512 pub(crate) type_names: Vec<String>,
513 pub(crate) type_field_names: Vec<Vec<String>>,
514 pub(crate) type_variant_names: Vec<Vec<String>>,
515}
516
517#[derive(Debug, Clone)]
518pub enum ArenaEntry {
519 Int(i64),
520 String(Rc<str>),
521 List(ArenaList),
522 Tuple(Vec<NanValue>),
523 Map(PersistentMap),
524 Record {
525 type_id: u32,
526 fields: Vec<NanValue>,
527 },
528 Variant {
529 type_id: u32,
530 variant_id: u16,
531 fields: Vec<NanValue>,
532 },
533 Fn(Rc<FunctionValue>),
534 Builtin(Rc<str>),
535 Namespace {
536 name: Rc<str>,
537 members: Vec<(Rc<str>, NanValue)>,
538 },
539 Boxed(NanValue),
540}
541
542#[derive(Debug, Clone)]
543pub enum ArenaList {
544 Flat {
545 items: Rc<Vec<NanValue>>,
546 start: usize,
547 },
548 Prepend {
549 head: NanValue,
550 tail: NanValue,
551 len: usize,
552 },
553 Concat {
554 left: NanValue,
555 right: NanValue,
556 len: usize,
557 },
558 Segments {
559 current: NanValue,
560 rest: Rc<Vec<NanValue>>,
561 start: usize,
562 len: usize,
563 },
564}
565
566const LIST_APPEND_CHUNK_LIMIT: usize = 128;
567
568#[derive(Debug, Clone, Copy, PartialEq, Eq)]
569enum HeapSpace {
570 Young = 0,
571 Yard = 1,
572 Handoff = 2,
573 Stable = 3,
574}
575
576#[derive(Debug, Clone, Copy, PartialEq, Eq)]
577pub enum AllocSpace {
578 Young,
579 Yard,
580 Handoff,
581}
582
583#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
584pub struct ArenaUsage {
585 pub young: usize,
586 pub yard: usize,
587 pub handoff: usize,
588 pub stable: usize,
589}
590
591impl ArenaUsage {
592 pub fn total(self) -> usize {
593 self.young + self.yard + self.handoff + self.stable
594 }
595}
596
597const HEAP_SPACE_SHIFT: u32 = 30;
598const HEAP_SPACE_MASK_U32: u32 = 0b11 << HEAP_SPACE_SHIFT;
599const HEAP_INDEX_MASK_U32: u32 = (1 << HEAP_SPACE_SHIFT) - 1;
600
601mod arena;
602mod compare;
603mod convert;
604mod lists;
605mod memory;
606
607#[cfg(test)]
608#[allow(clippy::approx_constant)]
609mod tests;