1use core::{
4 any::{type_name, Any},
5 fmt,
6};
7
8use arithmetic_parser::Location;
9
10pub use self::{
11 function::{CallContext, Function, InterpretedFn, NativeFn},
12 object::Object,
13 tuple::Tuple,
14};
15use crate::{
16 alloc::{Arc, Vec},
17 fns,
18};
19
20mod function;
21mod object;
22mod ops;
23mod tuple;
24
25#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
27#[non_exhaustive]
28pub enum ValueType {
29 Prim,
31 Bool,
33 Function,
35 Tuple(usize),
37 Object,
39 Array,
44 Ref,
46}
47
48impl fmt::Display for ValueType {
49 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
50 match self {
51 Self::Prim => formatter.write_str("primitive value"),
52 Self::Bool => formatter.write_str("boolean value"),
53 Self::Function => formatter.write_str("function"),
54 Self::Tuple(1) => formatter.write_str("tuple with 1 element"),
55 Self::Object => formatter.write_str("object"),
56 Self::Tuple(size) => write!(formatter, "tuple with {size} elements"),
57 Self::Array => formatter.write_str("array"),
58 Self::Ref => formatter.write_str("reference"),
59 }
60 }
61}
62
63#[derive(Clone)]
74pub struct OpaqueRef {
75 value: Arc<dyn Any>,
76 type_name: &'static str,
77 dyn_eq: fn(&dyn Any, &dyn Any) -> bool,
78 dyn_fmt: fn(&dyn Any, &mut fmt::Formatter<'_>) -> fmt::Result,
79}
80
81impl OpaqueRef {
82 #[allow(clippy::missing_panics_doc)] pub fn new<T>(value: T) -> Self
87 where
88 T: Any + fmt::Debug + PartialEq,
89 {
90 Self {
91 value: Arc::new(value),
92 type_name: type_name::<T>(),
93
94 dyn_eq: |this, other| {
95 let this_cast = this.downcast_ref::<T>().unwrap();
96 other.downcast_ref::<T>() == Some(this_cast)
97 },
98 dyn_fmt: |this, formatter| {
99 let this_cast = this.downcast_ref::<T>().unwrap();
100 fmt::Debug::fmt(this_cast, formatter)
101 },
102 }
103 }
104
105 #[allow(clippy::missing_panics_doc)] pub fn with_identity_eq<T: Any>(value: T) -> Self {
111 Self {
112 value: Arc::new(value),
113 type_name: type_name::<T>(),
114
115 dyn_eq: |this, other| {
116 let this_data = (this as *const dyn Any).cast::<()>();
117 let other_data = (other as *const dyn Any).cast::<()>();
118 this_data == other_data
119 },
120 dyn_fmt: |this, formatter| fmt::Debug::fmt(&this.type_id(), formatter),
121 }
122 }
123
124 pub fn downcast_ref<T: Any>(&self) -> Option<&T> {
126 self.value.downcast_ref()
127 }
128}
129
130impl PartialEq for OpaqueRef {
131 fn eq(&self, other: &Self) -> bool {
132 (self.dyn_eq)(self.value.as_ref(), other.value.as_ref())
133 }
134}
135
136impl fmt::Debug for OpaqueRef {
137 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
138 formatter
139 .debug_tuple("OpaqueRef")
140 .field(&self.value.as_ref())
141 .finish()
142 }
143}
144
145impl fmt::Display for OpaqueRef {
146 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
147 write!(formatter, "{}::", self.type_name)?;
148 (self.dyn_fmt)(self.value.as_ref(), formatter)
149 }
150}
151
152#[derive(Debug, Clone)]
154#[non_exhaustive]
155pub enum Value<T> {
156 Prim(T),
162 Bool(bool),
164 Function(Function<T>),
166 Tuple(Tuple<T>),
168 Object(Object<T>),
170 Ref(OpaqueRef),
172}
173
174pub type SpannedValue<T> = Location<Value<T>>;
176
177impl<T> Value<T> {
178 pub fn native_fn(function: impl NativeFn<T> + 'static) -> Self {
180 Self::Function(Function::Native(Arc::new(function)))
181 }
182
183 pub fn wrapped_fn<const CTX: bool, Args, F>(fn_to_wrap: F) -> Self
191 where
192 fns::FnWrapper<Args, F, CTX>: NativeFn<T> + 'static,
193 {
194 let wrapped = fns::wrap::<CTX, Args, _>(fn_to_wrap);
195 Self::native_fn(wrapped)
196 }
197
198 pub(crate) fn interpreted_fn(function: InterpretedFn<T>) -> Self {
200 Self::Function(Function::Interpreted(Arc::new(function)))
201 }
202
203 pub const fn void() -> Self {
205 Self::Tuple(Tuple::void())
206 }
207
208 pub fn opaque_ref(value: impl Any + fmt::Debug + PartialEq) -> Self {
210 Self::Ref(OpaqueRef::new(value))
211 }
212
213 pub fn value_type(&self) -> ValueType {
215 match self {
216 Self::Prim(_) => ValueType::Prim,
217 Self::Bool(_) => ValueType::Bool,
218 Self::Function(_) => ValueType::Function,
219 Self::Tuple(elements) => ValueType::Tuple(elements.len()),
220 Self::Object(_) => ValueType::Object,
221 Self::Ref(_) => ValueType::Ref,
222 }
223 }
224
225 pub fn is_void(&self) -> bool {
227 matches!(self, Self::Tuple(tuple) if tuple.is_empty())
228 }
229
230 pub fn is_function(&self) -> bool {
232 matches!(self, Self::Function(_))
233 }
234
235 pub(crate) fn as_object(&self) -> Option<&Object<T>> {
236 match self {
237 Self::Object(object) => Some(object),
238 _ => None,
239 }
240 }
241}
242
243impl<T> From<Vec<Self>> for Value<T> {
244 fn from(elements: Vec<Self>) -> Self {
245 Self::Tuple(Tuple::from(elements))
246 }
247}
248
249impl<T: Clone> From<&Value<T>> for Value<T> {
250 fn from(reference: &Value<T>) -> Self {
251 reference.clone()
252 }
253}
254
255impl<T: PartialEq> PartialEq for Value<T> {
256 fn eq(&self, rhs: &Self) -> bool {
257 match (self, rhs) {
258 (Self::Prim(this), Self::Prim(other)) => this == other,
259 (Self::Bool(this), Self::Bool(other)) => this == other,
260 (Self::Tuple(this), Self::Tuple(other)) => this == other,
261 (Self::Object(this), Self::Object(other)) => this == other,
262 (Self::Function(this), Self::Function(other)) => this == other,
263 (Self::Ref(this), Self::Ref(other)) => this == other,
264 _ => false,
265 }
266 }
267}
268
269impl<T: fmt::Display> fmt::Display for Value<T> {
270 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
271 match self {
272 Self::Prim(value) => fmt::Display::fmt(value, formatter),
273 Self::Bool(true) => formatter.write_str("true"),
274 Self::Bool(false) => formatter.write_str("false"),
275 Self::Ref(opaque_ref) => fmt::Display::fmt(opaque_ref, formatter),
276 Self::Function(function) => fmt::Display::fmt(function, formatter),
277 Self::Object(object) => fmt::Display::fmt(object, formatter),
278 Self::Tuple(tuple) => fmt::Display::fmt(tuple, formatter),
279 }
280 }
281}
282
283#[cfg(test)]
284mod tests {
285 use core::cmp::Ordering;
286
287 use super::*;
288
289 #[test]
290 fn opaque_ref_equality() {
291 let value = Value::<f32>::opaque_ref(Ordering::Less);
292 let same_value = Value::<f32>::opaque_ref(Ordering::Less);
293 assert_eq!(value, same_value);
294 assert_eq!(value, value.clone());
295 let other_value = Value::<f32>::opaque_ref(Ordering::Greater);
296 assert_ne!(value, other_value);
297 }
298
299 #[test]
300 fn opaque_ref_formatting() {
301 let value = OpaqueRef::new(Ordering::Less);
302 assert_eq!(value.to_string(), "core::cmp::Ordering::Less");
303 }
304}