rune/core/object/
vector.rs1use super::{CloneIn, Gc, IntoObject, MutObjCell, ObjCell, Object};
2use crate::{
3 core::gc::{Block, GcHeap, GcState, Trace},
4 derive_GcMoveable,
5};
6use anyhow::{Result, anyhow};
7use bumpalo::collections::Vec as GcVec;
8use rune_core::hashmap::HashSet;
9use rune_macros::Trace;
10use std::{
11 cell::Cell,
12 fmt::{self, Write},
13 ops::Deref,
14 ptr::addr_of,
15};
16
17struct LispVecInner {
18 is_const: bool,
19 inner: Cell<*const [ObjCell]>,
20}
21
22#[derive(PartialEq, Eq, Trace)]
26pub(crate) struct LispVec(GcHeap<LispVecInner>);
27
28derive_GcMoveable!(LispVec);
29
30impl Deref for LispVec {
31 type Target = [ObjCell];
32
33 fn deref(&self) -> &Self::Target {
34 self.0.get_slice()
35 }
36}
37
38impl PartialEq for LispVecInner {
39 fn eq(&self, other: &Self) -> bool {
40 self.get_slice() == other.get_slice()
41 }
42}
43
44impl Eq for LispVecInner {}
45
46impl LispVec {
47 pub(in crate::core) unsafe fn new(ptr: *const [Object], constant: bool) -> Self {
50 Self(GcHeap::new(LispVecInner::new(ptr, constant), constant))
51 }
52
53 pub(crate) fn to_vec(&self) -> Vec<Object> {
54 let obj_slice = unsafe { &*(addr_of!(*self.0.inner.get()) as *const [Object]) };
56 obj_slice.to_vec()
57 }
58}
59
60impl LispVecInner {
61 fn get_slice(&self) -> &[ObjCell] {
62 unsafe { &*self.inner.get() }
63 }
64}
65
66impl LispVec {
67 pub(crate) fn try_mut(&self) -> Result<&[MutObjCell]> {
68 if self.0.is_const {
69 Err(anyhow!("Attempt to mutate constant Vector"))
70 } else {
71 unsafe { Ok(&*(self.0.inner.get() as *const [MutObjCell])) }
73 }
74 }
75}
76
77impl<'new> CloneIn<'new, &'new Self> for LispVec {
78 fn clone_in<const C: bool>(&self, bk: &'new Block<C>) -> Gc<&'new Self> {
79 let mut vec = GcVec::with_capacity_in(self.len(), &bk.objects);
80 vec.extend(self.iter().map(|x| x.get().clone_in(bk)));
81 vec.into_obj(bk)
82 }
83}
84
85impl Trace for LispVecInner {
86 fn trace(&self, state: &mut GcState) {
87 assert!(!self.is_const, "Attempt to trace mutable vector");
88 let slice = unsafe { &*(self.inner.get() as *mut [Object]) };
94 let new = state.to_space.alloc_slice_copy(slice);
95 let new = unsafe { std::mem::transmute::<&mut [Object], &mut [ObjCell]>(new) };
96 for x in &mut *new {
97 x.trace(state);
98 }
99 self.inner.set(new);
100 }
101}
102
103impl fmt::Display for LispVec {
104 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
105 self.display_walk(f, &mut HashSet::default())
106 }
107}
108
109impl fmt::Debug for LispVec {
110 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
111 self.display_walk(f, &mut HashSet::default())
112 }
113}
114
115impl LispVec {
116 pub(super) fn display_walk(
117 &self,
118 f: &mut fmt::Formatter,
119 seen: &mut HashSet<*const u8>,
120 ) -> fmt::Result {
121 let ptr = (&*self.0 as *const LispVecInner).cast();
122 if seen.contains(&ptr) {
123 return write!(f, "#0");
124 }
125 seen.insert(ptr);
126
127 f.write_char('[')?;
128 for (i, x) in self.iter().enumerate() {
129 if i != 0 {
130 f.write_char(' ')?;
131 }
132 x.get().untag().display_walk(f, seen)?;
133 }
134 f.write_char(']')
135 }
136}
137
138impl LispVecInner {
139 unsafe fn new(ptr: *const [Object], is_const: bool) -> Self {
140 let ptr = ptr as *mut [ObjCell];
141 Self { is_const, inner: Cell::new(ptr) }
142 }
143}
144
145#[repr(transparent)]
146pub(crate) struct RecordBuilder<'ob>(pub(crate) GcVec<'ob, Object<'ob>>);
147
148#[derive(PartialEq, Eq, Trace)]
149pub(crate) struct Record(GcHeap<LispVecInner>);
150
151derive_GcMoveable!(Record);
152
153impl Deref for Record {
154 type Target = [ObjCell];
155
156 fn deref(&self) -> &Self::Target {
157 self.0.get_slice()
158 }
159}
160
161impl<'new> CloneIn<'new, &'new Self> for Record {
162 fn clone_in<const C: bool>(&self, bk: &'new Block<C>) -> Gc<&'new Self> {
163 let mut vec = GcVec::with_capacity_in(self.len(), &bk.objects);
164 vec.extend(self.iter().map(|x| x.get().clone_in(bk)));
165 RecordBuilder(vec).into_obj(bk)
166 }
167}
168
169impl fmt::Display for Record {
170 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
171 self.display_walk(f, &mut HashSet::default())
172 }
173}
174
175impl Record {
176 pub(crate) fn try_mut(&self) -> Result<&[MutObjCell]> {
177 if self.0.is_const {
178 Err(anyhow!("Attempt to mutate constant Vector"))
179 } else {
180 unsafe { Ok(&*(self.0.inner.get() as *const [MutObjCell])) }
182 }
183 }
184
185 pub(super) fn display_walk(
186 &self,
187 f: &mut fmt::Formatter,
188 seen: &mut HashSet<*const u8>,
189 ) -> fmt::Result {
190 let ptr = (self as *const Self).cast();
191 if seen.contains(&ptr) {
192 return write!(f, "#0");
193 }
194 seen.insert(ptr);
195 write!(f, "#s(")?;
196 for (i, x) in self.iter().enumerate() {
197 if i != 0 {
198 f.write_char(' ')?;
199 }
200 x.get().untag().display_walk(f, seen)?;
201 }
202 f.write_char(')')
203 }
204}