ferrijs_std/utils/
class.rs1use rquickjs::{
4 atom::PredefinedAtom, class::JsClass, object::Accessor, object::Property, prelude::This, Array,
5 Class, Ctx, Function, Object, Result, Symbol, Value,
6};
7
8use super::{
9 object::ObjectExt,
10 primordials::{BasePrimordials, Primordial},
11 result::OptionExt,
12};
13
14pub static CUSTOM_INSPECT_SYMBOL_DESCRIPTION: &str = "llrt.inspect.custom";
15
16#[derive(Clone, Copy)]
18pub enum IterKind {
19 Keys,
20 Values,
21 Entries,
22}
23
24pub fn iterator_result<'js>(
26 ctx: &Ctx<'js>,
27 kind: IterKind,
28 entry: Option<(Value<'js>, Value<'js>)>,
29) -> Result<Object<'js>> {
30 let obj = Object::new(ctx.clone())?;
31 match entry {
32 Some((key, value)) => {
33 obj.set(PredefinedAtom::Done, false)?;
34 match kind {
35 IterKind::Keys => obj.set(PredefinedAtom::Value, key)?,
36 IterKind::Values => obj.set(PredefinedAtom::Value, value)?,
37 IterKind::Entries => {
38 let entry = Array::new(ctx.clone())?;
39 entry.set(0, key)?;
40 entry.set(1, value)?;
41 obj.set(PredefinedAtom::Value, entry)?;
42 },
43 }
44 },
45 None => obj.set(PredefinedAtom::Done, true)?,
46 }
47 Ok(obj)
48}
49
50pub fn live_iterator<'js, C>(ctx: &Ctx<'js>, iter: C) -> Result<Class<'js, C>>
56where
57 C: JsClass<'js> + 'js,
58{
59 let instance = Class::<C>::instance(ctx.clone(), iter)?;
60 if let Some(proto) = Class::<C>::prototype(ctx)? {
61 let iterator_proto = &BasePrimordials::get(ctx)?.prototype_iterator;
62 if proto.get_prototype().as_ref() != Some(iterator_proto) {
63 proto.set_prototype(Some(iterator_proto))?;
64 let next_fn: Function = proto.get(PredefinedAtom::Next)?;
65 proto.prop(
66 PredefinedAtom::Next,
67 Property::from(next_fn)
68 .writable()
69 .enumerable()
70 .configurable(),
71 )?;
72 }
73 }
74 Ok(instance)
75}
76
77pub fn get_class_name(value: &Value) -> Result<Option<String>> {
78 value
79 .get_optional::<_, Object>(PredefinedAtom::Constructor)?
80 .and_then_ok(|ctor| ctor.get_optional::<_, String>(PredefinedAtom::Name))
81}
82
83#[inline(always)]
84pub fn get_class<'js, C>(provided: &Value<'js>) -> Result<Option<Class<'js, C>>>
85where
86 C: JsClass<'js>,
87{
88 if provided
89 .as_object()
90 .map(|p| p.instance_of::<C>())
91 .unwrap_or_default()
92 {
93 return Ok(Some(Class::<C>::from_value(provided)?));
94 }
95 Ok(None)
96}
97
98pub trait CustomInspectExtension<'js> {
99 fn define_with_custom_inspect(globals: &Object<'js>) -> Result<()>;
100}
101
102pub trait CustomInspect<'js>
103where
104 Self: JsClass<'js>,
105{
106 fn custom_inspect(&self, ctx: Ctx<'js>) -> Result<Object<'js>>;
107}
108
109impl<'js, C> CustomInspectExtension<'js> for Class<'js, C>
110where
111 C: JsClass<'js> + CustomInspect<'js> + 'js,
112{
113 fn define_with_custom_inspect(globals: &Object<'js>) -> Result<()> {
114 Self::define(globals)?;
115 let custom_inspect_symbol =
116 Symbol::new_global(globals.ctx().clone(), CUSTOM_INSPECT_SYMBOL_DESCRIPTION)?;
117 if let Some(proto) = Class::<C>::prototype(globals.ctx())? {
118 proto.prop(
119 custom_inspect_symbol,
120 Accessor::from(|this: This<Class<'js, C>>, ctx| this.borrow().custom_inspect(ctx)),
121 )?;
122 }
123 Ok(())
124 }
125}