1mod raw;
2
3use std::any::Any;
4use std::borrow::Cow;
5use std::fmt;
6
7use mica_language::gc::Gc;
8use mica_language::value::{self, Closure, Dict, List, RawValue, Struct, Trait, UserData};
9
10use crate::{Error, Object};
11
12pub use raw::*;
13
14#[doc(hidden)]
16pub struct Hidden<T>(pub(crate) Gc<T>);
17
18impl<T> Clone for Hidden<T> {
19 fn clone(&self) -> Self {
20 Self(self.0.clone())
21 }
22}
23
24#[derive(Clone)]
26pub enum Value {
27 Nil,
28 False,
29 True,
30 Number(f64),
31 String(Gc<String>),
32 Function(Hidden<Closure>),
33 Struct(Hidden<Struct>),
34 Trait(Hidden<Trait>),
35 List(Hidden<List>),
36 Dict(Hidden<Dict>),
37 UserData(Gc<Box<dyn UserData>>),
38}
39
40impl Value {
41 pub fn type_name(&self) -> &str {
43 match self {
44 Value::Nil => "Nil",
45 Value::False => "False",
46 Value::True => "True",
47 Value::Number(_) => "Number",
48 Value::String(_) => "String",
49 Value::Function(_) => "Function",
50 Value::Struct(s) => &unsafe { s.0.dtable() }.type_name,
52 Value::Trait(s) => &s.0.dtable().type_name,
53 Value::List(_) => "List",
54 Value::Dict(_) => "Dict",
55 Value::UserData(u) => &unsafe { u.dtable() }.type_name,
56 }
57 }
58
59 pub fn is_falsy(&self) -> bool {
61 matches!(self, Self::Nil | Self::False)
62 }
63
64 pub fn is_truthy(&self) -> bool {
66 !self.is_falsy()
67 }
68}
69
70impl fmt::Debug for Value {
71 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
72 fmt::Debug::fmt(&self.to_raw_unmanaged(), f)
73 }
74}
75
76impl fmt::Display for Value {
77 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
78 fmt::Display::fmt(&self.to_raw_unmanaged(), f)
79 }
80}
81
82#[doc(hidden)]
84impl From<RawValue> for Value {
85 fn from(raw: RawValue) -> Self {
86 Self::from_raw(raw)
87 }
88}
89
90impl From<()> for Value {
92 fn from(_: ()) -> Self {
93 Self::Nil
94 }
95}
96
97impl From<bool> for Value {
98 fn from(b: bool) -> Self {
99 match b {
100 true => Self::True,
101 false => Self::False,
102 }
103 }
104}
105
106macro_rules! value_from_number {
107 ($T:ty $(, $doc:literal)?) => {
108 $(#[doc = $doc])?
109 impl From<$T> for Value {
110 fn from(x: $T) -> Self {
111 Value::Number(x as f64)
112 }
113 }
114 };
115}
116
117value_from_number!(i8);
118value_from_number!(i16);
119value_from_number!(i32);
120value_from_number!(i64, "**NOTE:** This is a lossy conversion, as an `f64` cannot represent the entire range of an `i64`.");
121value_from_number!(isize, "**NOTE:** This is a lossy conversion, as an `f64` cannot represent the entire range of an `isize`.");
122
123value_from_number!(u8);
124value_from_number!(u16);
125value_from_number!(u32);
126value_from_number!(u64, "**NOTE:** This is a lossy conversion, as an `f64` cannot represent the entire range of a `u64`.");
127value_from_number!(usize, "**NOTE:** This is a lossy conversion, as an `f64` cannot represent the entire range of a `usize`.");
128
129value_from_number!(f32);
130value_from_number!(f64);
131
132impl From<char> for Value {
133 fn from(c: char) -> Self {
134 Self::from(c.to_string())
135 }
136}
137
138impl From<&str> for Value {
139 fn from(s: &str) -> Self {
140 Self::String(Gc::new(s.to_string()))
141 }
142}
143
144impl From<String> for Value {
145 fn from(s: String) -> Self {
146 Self::String(Gc::new(s))
147 }
148}
149
150impl From<Gc<String>> for Value {
151 fn from(s: Gc<String>) -> Self {
152 Self::String(s)
153 }
154}
155
156impl<T> From<Option<T>> for Value
157where
158 T: Into<Value>,
159{
160 fn from(opt: Option<T>) -> Self {
161 match opt {
162 Some(value) => value.into(),
163 None => Value::Nil,
164 }
165 }
166}
167
168#[doc(hidden)]
172impl From<Vec<RawValue>> for Value {
173 fn from(v: Vec<RawValue>) -> Self {
174 Value::List(Hidden(Gc::new(List::new(v))))
175 }
176}
177
178#[doc(hidden)]
181impl From<Dict> for Value {
182 fn from(d: Dict) -> Self {
183 Value::Dict(Hidden(Gc::new(d)))
184 }
185}
186
187impl<T> From<Object<T>> for Value
188where
189 T: Any,
190{
191 fn from(o: Object<T>) -> Self {
192 let user_data: Box<dyn value::UserData> = Box::new(o);
193 Self::UserData(Gc::new(user_data))
194 }
195}
196
197pub trait TryFromValue
199where
200 Self: Sized,
201{
202 fn try_from_value(value: &Value) -> Result<Self, Error>;
203}
204
205fn type_mismatch(expected: impl Into<Cow<'static, str>>, got: &Value) -> Error {
206 Error::TypeMismatch {
207 expected: expected.into(),
208 got: got.type_name().to_string().into(),
209 }
210}
211
212impl TryFromValue for Value {
213 fn try_from_value(value: &Value) -> Result<Self, Error> {
214 Ok(value.clone())
215 }
216}
217
218#[doc(hidden)]
222impl TryFromValue for RawValue {
223 fn try_from_value(value: &Value) -> Result<Self, Error> {
224 Ok(value.to_raw_unmanaged())
225 }
226}
227
228impl TryFromValue for () {
229 fn try_from_value(value: &Value) -> Result<Self, Error> {
230 if let Value::Nil = value {
231 Ok(())
232 } else {
233 Err(type_mismatch("Nil", value))
234 }
235 }
236}
237
238impl TryFromValue for bool {
239 fn try_from_value(value: &Value) -> Result<Self, Error> {
240 match value {
241 Value::True => Ok(true),
242 Value::False => Ok(false),
243 _ => Err(type_mismatch("Boolean", value)),
244 }
245 }
246}
247
248macro_rules! try_from_value_numeric {
249 ($T:ty) => {
250 impl TryFromValue for $T {
251 fn try_from_value(value: &Value) -> Result<Self, Error> {
252 if let Value::Number(number) = value {
253 Ok(*number as $T)
254 } else {
255 Err(type_mismatch("Number", value))
256 }
257 }
258 }
259 };
260}
261
262try_from_value_numeric!(u8);
263try_from_value_numeric!(u16);
264try_from_value_numeric!(u32);
265try_from_value_numeric!(u64);
266try_from_value_numeric!(usize);
267
268try_from_value_numeric!(i8);
269try_from_value_numeric!(i16);
270try_from_value_numeric!(i32);
271try_from_value_numeric!(i64);
272try_from_value_numeric!(isize);
273
274try_from_value_numeric!(f32);
275try_from_value_numeric!(f64);
276
277impl TryFromValue for Gc<String> {
278 fn try_from_value(value: &Value) -> Result<Self, Error> {
279 if let Value::String(s) = value {
280 Ok(Gc::clone(s))
281 } else {
282 Err(type_mismatch("String", value))
283 }
284 }
285}
286
287impl TryFromValue for String {
288 fn try_from_value(value: &Value) -> Result<Self, Error> {
289 <Gc<String>>::try_from_value(value).map(|s| s.to_string())
290 }
291}
292
293impl<T> TryFromValue for Option<T>
294where
295 T: TryFromValue,
296{
297 fn try_from_value(value: &Value) -> Result<Self, Error> {
298 match value {
299 Value::Nil => Ok(None),
300 _ => Ok(Some(T::try_from_value(value).map_err(|error| {
301 if let Error::TypeMismatch { expected, got } = error {
302 Error::TypeMismatch {
303 expected: format!("{} or Nil", expected).into(),
304 got,
305 }
306 } else {
307 unreachable!()
308 }
309 })?)),
310 }
311 }
312}