cao_lang/vm/runtime/
cao_lang_object.rs1use std::ptr::NonNull;
2
3use crate::value::Value;
4
5use super::{
6 cao_lang_function::{CaoLangClosure, CaoLangFunction, CaoLangNativeFunction, CaoLangUpvalue},
7 cao_lang_string::CaoLangString,
8 cao_lang_table::CaoLangTable,
9};
10
11#[derive(Debug, Clone, Copy)]
13pub enum GcMarker {
14 White,
16 Gray,
18 Black,
20 Protected,
22}
23
24#[derive(Debug)]
25pub struct CaoLangObject {
26 pub marker: GcMarker,
27 pub body: CaoLangObjectBody,
28}
29
30#[derive(Debug)]
31pub enum CaoLangObjectBody {
32 Table(CaoLangTable),
33 String(CaoLangString),
34 Function(CaoLangFunction),
35 NativeFunction(CaoLangNativeFunction),
36 Closure(CaoLangClosure),
37 Upvalue(CaoLangUpvalue),
38}
39
40pub struct ObjectGcGuard(pub(crate) NonNull<CaoLangObject>);
43
44impl std::ops::Deref for ObjectGcGuard {
45 type Target = CaoLangObject;
46
47 fn deref(&self) -> &Self::Target {
48 unsafe { self.0.as_ref() }
49 }
50}
51
52impl std::ops::DerefMut for ObjectGcGuard {
53 fn deref_mut(&mut self) -> &mut Self::Target {
54 unsafe { self.0.as_mut() }
55 }
56}
57
58impl Drop for ObjectGcGuard {
59 fn drop(&mut self) {
60 unsafe {
61 self.0.as_mut().marker = GcMarker::White;
62 }
63 }
64}
65
66impl ObjectGcGuard {
67 pub fn new(mut obj: NonNull<CaoLangObject>) -> Self {
68 unsafe {
69 obj.as_mut().marker = GcMarker::Protected;
70 }
71 Self(obj)
72 }
73
74 pub fn into_inner(self) -> NonNull<CaoLangObject> {
75 self.0
76 }
77}
78
79impl From<ObjectGcGuard> for Value {
80 fn from(value: ObjectGcGuard) -> Self {
81 Value::Object(value.0)
82 }
83}
84
85impl CaoLangObject {
86 pub fn type_name(&self) -> &'static str {
87 match &self.body {
88 CaoLangObjectBody::Table(_) => "Table",
89 CaoLangObjectBody::String(_) => "String",
90 CaoLangObjectBody::Function(_) => "Function",
91 CaoLangObjectBody::NativeFunction(_) => "NativeFunction",
92 CaoLangObjectBody::Closure(_) => "Closure",
93 CaoLangObjectBody::Upvalue(_) => "Upvalue",
94 }
95 }
96
97 pub fn as_table(&self) -> Option<&CaoLangTable> {
98 match &self.body {
99 CaoLangObjectBody::Table(v) => Some(v),
100 _ => None,
101 }
102 }
103
104 pub fn as_table_mut(&mut self) -> Option<&mut CaoLangTable> {
105 match &mut self.body {
106 CaoLangObjectBody::Table(v) => Some(v),
107 _ => None,
108 }
109 }
110
111 pub fn as_str(&self) -> Option<&str> {
112 match &self.body {
113 CaoLangObjectBody::String(s) => Some(s.as_str()),
114 _ => None,
115 }
116 }
117
118 pub fn as_function(&self) -> Option<&CaoLangFunction> {
119 match &self.body {
120 CaoLangObjectBody::Function(f) => Some(f),
121 _ => None,
122 }
123 }
124
125 pub fn as_closure(&self) -> Option<&CaoLangClosure> {
126 match &self.body {
127 CaoLangObjectBody::Closure(f) => Some(f),
128 _ => None,
129 }
130 }
131
132 pub fn as_upvalue(&self) -> Option<&CaoLangUpvalue> {
133 match &self.body {
134 CaoLangObjectBody::Upvalue(v) => Some(v),
135 _ => None,
136 }
137 }
138
139 pub fn as_upvalue_mut(&mut self) -> Option<&mut CaoLangUpvalue> {
140 match &mut self.body {
141 CaoLangObjectBody::Upvalue(v) => Some(v),
142 _ => None,
143 }
144 }
145
146 pub fn len(&self) -> usize {
147 match &self.body {
148 CaoLangObjectBody::Table(t) => t.len(),
149 CaoLangObjectBody::String(s) => s.len(),
150 CaoLangObjectBody::Function(_) => 0,
151 CaoLangObjectBody::NativeFunction(_) => 0,
152 CaoLangObjectBody::Closure(_) => 0,
153 CaoLangObjectBody::Upvalue(_) => 0,
154 }
155 }
156
157 pub fn is_empty(&self) -> bool {
158 match &self.body {
159 CaoLangObjectBody::Table(_) | CaoLangObjectBody::String(_) => self.len() == 0,
160 CaoLangObjectBody::Function(_)
161 | CaoLangObjectBody::Closure(_)
162 | CaoLangObjectBody::Upvalue(_)
163 | CaoLangObjectBody::NativeFunction(_) => false,
164 }
165 }
166}
167
168impl std::hash::Hash for CaoLangObject {
169 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
170 match &self.body {
171 CaoLangObjectBody::Table(o) => {
172 for (k, v) in o.iter() {
173 k.hash(state);
174 v.hash(state);
175 }
176 }
177 CaoLangObjectBody::String(s) => {
178 s.as_str().hash(state);
179 }
180 CaoLangObjectBody::Function(f) => {
181 f.handle.value().hash(state);
182 f.arity.hash(state);
183 }
184 CaoLangObjectBody::NativeFunction(f) => f.handle.value().hash(state),
185 CaoLangObjectBody::Closure(c) => {
186 c.function.handle.value().hash(state);
187 c.function.arity.hash(state);
188 }
189 CaoLangObjectBody::Upvalue(u) => {
190 u.location.hash(state);
191 }
192 }
193 }
194}
195
196impl PartialEq for CaoLangObject {
197 fn eq(&self, other: &Self) -> bool {
198 match (&self.body, &other.body) {
199 (CaoLangObjectBody::Table(lhs), CaoLangObjectBody::Table(rhs)) => {
200 if lhs.len() != rhs.len() {
201 return false;
202 }
203 for ((kl, vl), (kr, vr)) in lhs.iter().zip(rhs.iter()) {
204 if kl != kr || vl != vr {
205 return false;
206 }
207 }
208 true
209 }
210 (CaoLangObjectBody::String(lhs), CaoLangObjectBody::String(rhs)) => {
211 lhs.as_str().eq(rhs.as_str())
212 }
213 _ => false,
214 }
215 }
216}
217
218impl PartialOrd for CaoLangObject {
219 fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
220 self.eq(other)
221 .then_some(std::cmp::Ordering::Equal)
222 .or_else(|| {
223 let res = self.len().cmp(&other.len());
225 match res {
226 std::cmp::Ordering::Equal => None,
227 _ => Some(res),
228 }
229 })
230 }
231}