Skip to main content

hebi/public/
value.rs

1use super::object::{Any, ObjectRef};
2use crate::internal::error::Result;
3use crate::internal::{object, value};
4use crate::public::{Bind, Global, Unbind};
5
6decl_ref! {
7  struct Value(value::Value)
8}
9
10impl<'cx> Value<'cx> {
11  pub fn as_float(&self) -> Option<f64> {
12    self.inner.clone().to_float()
13  }
14
15  pub fn is_float(&self) -> bool {
16    self.inner.is_float()
17  }
18
19  pub fn as_int(&self) -> Option<i32> {
20    self.inner.clone().to_int()
21  }
22
23  pub fn is_int(&self) -> bool {
24    self.inner.is_int()
25  }
26
27  pub fn as_bool(&self) -> Option<bool> {
28    self.inner.clone().to_bool()
29  }
30
31  pub fn is_bool(&self) -> bool {
32    self.inner.is_bool()
33  }
34
35  pub fn as_none(&self) -> Option<()> {
36    self.inner.clone().to_none()
37  }
38
39  pub fn is_none(&self) -> bool {
40    self.inner.is_none()
41  }
42
43  pub fn as_object<T: ObjectRef<'cx>>(&self, global: Global<'cx>) -> Option<T> {
44    self.as_any().and_then(|v| Any::cast(v, global))
45  }
46
47  pub fn as_any(&self) -> Option<Any<'cx>> {
48    self.inner.clone().to_any().map(|v| {
49      // SAFETY: `self` is already bound to 'cx
50      unsafe { v.bind_raw::<'cx>() }
51    })
52  }
53
54  pub fn is_object(&self) -> bool {
55    self.inner.is_object()
56  }
57}
58
59pub trait FromValue<'cx>: Sized {
60  fn from_value(value: Value<'cx>, global: Global<'cx>) -> Result<Self>;
61}
62
63pub trait IntoValue<'cx>: Sized {
64  fn into_value(self, global: Global<'cx>) -> Result<Value<'cx>>;
65}
66
67impl<'cx> IntoValue<'cx> for Value<'cx> {
68  fn into_value(self, _: Global<'cx>) -> Result<Value<'cx>> {
69    Ok(self)
70  }
71}
72
73impl<'cx> FromValue<'cx> for Value<'cx> {
74  fn from_value(value: Value<'cx>, _: Global<'cx>) -> Result<Self> {
75    Ok(value)
76  }
77}
78
79impl<'cx> IntoValue<'cx> for i32 {
80  fn into_value(self, global: Global<'cx>) -> Result<Value<'cx>> {
81    Ok(value::Value::int(self).bind(global))
82  }
83}
84
85impl<'cx> FromValue<'cx> for i32 {
86  fn from_value(value: Value<'cx>, _: Global<'cx>) -> Result<Self> {
87    match value.as_int() {
88      Some(value) => Ok(value),
89      None => crate::fail!("value is not an int"),
90    }
91  }
92}
93
94impl<'cx> IntoValue<'cx> for f64 {
95  fn into_value(self, global: Global<'cx>) -> Result<Value<'cx>> {
96    Ok(value::Value::float(self).bind(global))
97  }
98}
99
100impl<'cx> FromValue<'cx> for f64 {
101  fn from_value(value: Value<'cx>, _: Global<'cx>) -> Result<Self> {
102    match value.as_float() {
103      Some(value) => Ok(value),
104      None => crate::fail!("value is not a float"),
105    }
106  }
107}
108
109impl<'cx> IntoValue<'cx> for bool {
110  fn into_value(self, global: Global<'cx>) -> Result<Value<'cx>> {
111    Ok(value::Value::bool(self).bind(global))
112  }
113}
114
115impl<'cx> FromValue<'cx> for bool {
116  fn from_value(value: Value<'cx>, _: Global<'cx>) -> Result<Self> {
117    match value.as_bool() {
118      Some(value) => Ok(value),
119      None => crate::fail!("value is not a bool"),
120    }
121  }
122}
123
124impl<'cx> IntoValue<'cx> for () {
125  fn into_value(self, global: Global<'cx>) -> Result<Value<'cx>> {
126    Ok(value::Value::none().bind(global))
127  }
128}
129
130impl<'cx> FromValue<'cx> for () {
131  fn from_value(value: Value<'cx>, global: Global<'cx>) -> Result<Self> {
132    let _ = (value, global);
133    Ok(())
134  }
135}
136
137impl<'cx, T> IntoValue<'cx> for Option<T>
138where
139  T: IntoValue<'cx>,
140{
141  fn into_value(self, global: Global<'cx>) -> Result<Value<'cx>> {
142    match self {
143      Some(value) => value.into_value(global),
144      None => Ok(value::Value::none().bind(global)),
145    }
146  }
147}
148
149impl<'cx, T> FromValue<'cx> for Option<T>
150where
151  T: FromValue<'cx>,
152{
153  fn from_value(value: Value<'cx>, global: Global<'cx>) -> Result<Self> {
154    if value.is_none() {
155      Ok(None)
156    } else {
157      T::from_value(value, global).map(Some)
158    }
159  }
160}
161
162impl<'cx, T> IntoValue<'cx> for Result<T>
163where
164  T: IntoValue<'cx>,
165{
166  fn into_value(self, global: Global<'cx>) -> Result<Value<'cx>> {
167    self?.into_value(global)
168  }
169}
170
171impl<'cx, T> IntoValue<'cx> for T
172where
173  T: ObjectRef<'cx>,
174{
175  fn into_value(self, global: Global<'cx>) -> Result<Value<'cx>> {
176    Ok(value::Value::object(self.as_any(global.clone()).unbind()).bind(global))
177  }
178}
179
180impl<'cx, T> FromValue<'cx> for T
181where
182  T: ObjectRef<'cx>,
183{
184  fn from_value(value: Value<'cx>, global: Global<'cx>) -> Result<Self> {
185    let object = value
186      .as_any()
187      .ok_or_else(|| error!("value is not an object"))?;
188    let object = T::from_any(object, global).ok_or_else(|| {
189      error!(
190        "value is not an instance of {}",
191        ::core::any::type_name::<T>()
192      )
193    })?;
194    Ok(object)
195  }
196}
197
198impl<'cx> FromValue<'cx> for String {
199  fn from_value(value: Value<'cx>, _: Global<'cx>) -> Result<Self> {
200    let Some(str) = value.unbind().to_object::<object::Str>() else {
201      fail!("value is not a string")
202    };
203    Ok(str.as_str().to_string())
204  }
205}
206
207impl<'cx> IntoValue<'cx> for String {
208  fn into_value(self, global: Global<'cx>) -> Result<Value<'cx>> {
209    global.new_string(self).into_value(global)
210  }
211}
212
213pub trait FromValuePack<'cx> {
214  type Output: Sized;
215  fn from_value_pack(args: &[value::Value], global: Global<'cx>) -> Result<Self::Output>;
216  fn len() -> usize;
217}
218
219impl<'cx> FromValuePack<'cx> for () {
220  type Output = ();
221
222  fn from_value_pack(args: &[value::Value], _: Global<'cx>) -> Result<Self::Output> {
223    #[allow(clippy::len_zero)]
224    if args.len() > 0 {
225      fail!("expected at most 0 args, got {}", args.len());
226    }
227    Ok(())
228  }
229
230  fn len() -> usize {
231    0
232  }
233}
234
235macro_rules! impl_from_value_pack {
236  ($($T:ident),*) => {
237    impl<'cx, $($T),*> FromValuePack<'cx> for ($($T,)*)
238    where
239      $(
240        $T: FromValue<'cx>,
241      )*
242    {
243      type Output = ($($T,)*);
244
245      #[allow(non_snake_case)]
246      fn from_value_pack(args: &[$crate::internal::value::Value], global: Global<'cx>) -> Result<Self::Output> {
247        let num_args = args.len();
248        let expected_num_args = Self::len();
249
250        if num_args > expected_num_args {
251          fail!("expected at most {expected_num_args} args, got {num_args}");
252        }
253        if num_args < expected_num_args {
254          fail!("expected at least {expected_num_args} args, got {num_args}");
255        }
256
257        let mut offset = 0;
258        $(
259          let $T = unsafe { args.get_unchecked(offset).clone() }.bind(global.clone());
260          let $T = <$T>::from_value($T, global.clone())?;
261          offset += 1;
262        )*
263        let _ = offset;
264
265        Ok(($($T,)*))
266      }
267
268      #[inline]
269      fn len() -> usize {
270        __count!($($T)*)
271      }
272    }
273  };
274}
275
276impl_from_value_pack!(A);
277impl_from_value_pack!(A, B);
278impl_from_value_pack!(A, B, C);
279impl_from_value_pack!(A, B, C, D);
280impl_from_value_pack!(A, B, C, D, E);
281impl_from_value_pack!(A, B, C, D, E, F);
282impl_from_value_pack!(A, B, C, D, E, F, G);
283impl_from_value_pack!(A, B, C, D, E, F, G, H);
284impl_from_value_pack!(A, B, C, D, E, F, G, H, I);
285impl_from_value_pack!(A, B, C, D, E, F, G, H, I, J);
286impl_from_value_pack!(A, B, C, D, E, F, G, H, I, J, K);
287impl_from_value_pack!(A, B, C, D, E, F, G, H, I, J, K, L);
288
289#[cfg(feature = "serde")]
290mod serde {
291  use ::serde::Serialize;
292
293  use super::*;
294
295  impl<'cx> Serialize for Value<'cx> {
296    fn serialize<S>(&self, serializer: S) -> std::result::Result<S::Ok, S::Error>
297    where
298      S: ::serde::Serializer,
299    {
300      self.inner.serialize(serializer)
301    }
302  }
303}