rquickjs_core/value/proxy/
handler.rs

1use alloc::string::String as StdString;
2
3use crate::{atom::PredefinedAtom, Ctx, Error, FromJs, Function, IntoJs, Object, Result, Value};
4
5/// Helper type for the proxy target
6#[derive(Debug, PartialEq, Clone, Hash, Eq)]
7pub struct ProxyTarget<'js>(pub Object<'js>);
8
9impl<'js> FromJs<'js> for ProxyTarget<'js> {
10    fn from_js(_: &Ctx<'js>, value: Value<'js>) -> Result<Self> {
11        Ok(Self(Object::from_value(value)?))
12    }
13}
14
15/// Helper type for the proxy property
16#[derive(Debug, PartialEq, Clone, Hash, Eq)]
17pub struct ProxyProperty<'js>(pub Value<'js>);
18
19impl<'js> ProxyProperty<'js> {
20    pub fn is_symbol(&self) -> bool {
21        self.0.is_symbol()
22    }
23
24    pub fn is_string(&self) -> bool {
25        self.0.is_string()
26    }
27
28    pub fn to_string(&self) -> Result<StdString> {
29        if let Some(string) = self.0.as_string() {
30            string.to_string()
31        } else if let Some(symbol) = self.0.as_symbol() {
32            symbol.as_atom().to_string()
33        } else {
34            Err(Error::Unknown)
35        }
36    }
37}
38
39impl<'js> FromJs<'js> for ProxyProperty<'js> {
40    fn from_js(_: &Ctx<'js>, value: Value<'js>) -> Result<Self> {
41        Ok(Self(value))
42    }
43}
44
45/// Helper type for the proxy handler
46#[derive(Debug, PartialEq, Clone, Hash, Eq)]
47pub struct ProxyReceiver<'js>(pub Value<'js>);
48
49impl<'js> FromJs<'js> for ProxyReceiver<'js> {
50    fn from_js(_: &Ctx<'js>, value: Value<'js>) -> Result<Self> {
51        Ok(Self(value))
52    }
53}
54
55/// Rust representation of a JavaScript proxy handler.
56#[derive(Debug, PartialEq, Clone, Hash, Eq)]
57#[repr(transparent)]
58pub struct ProxyHandler<'js>(pub(crate) Object<'js>);
59
60impl<'js> ProxyHandler<'js> {
61    /// Create a new empty proxy handler
62    pub fn new(ctx: Ctx<'js>) -> Result<Self> {
63        Ok(Self(Object::new(ctx)?))
64    }
65
66    /// Create a new proxy handler from a existing object
67    pub fn from_object(object: Object<'js>) -> Result<Self> {
68        Ok(Self(object))
69    }
70
71    /// Set the getter function for the proxy handler
72    pub fn set_getter<F, V>(&self, get: F) -> Result<()>
73    where
74        F: Fn(ProxyTarget<'js>, ProxyProperty<'js>, ProxyReceiver<'js>) -> Result<V> + 'js,
75        V: IntoJs<'js> + 'js,
76    {
77        self.0.set(
78            PredefinedAtom::Getter,
79            Function::new(self.0.ctx().clone(), get)?,
80        )?;
81        Ok(())
82    }
83
84    /// Set the getter function for the proxy handler
85    pub fn with_getter<F, V>(self, get: F) -> Result<Self>
86    where
87        F: Fn(ProxyTarget<'js>, ProxyProperty<'js>, ProxyReceiver<'js>) -> Result<V> + 'js,
88        V: IntoJs<'js> + 'js,
89    {
90        self.set_getter(get)?;
91        Ok(self)
92    }
93
94    /// Set the setter function for the proxy handler
95    pub fn set_setter<F>(&self, set: F) -> Result<()>
96    where
97        F: Fn(ProxyTarget<'js>, ProxyProperty<'js>, Value<'js>, ProxyReceiver<'js>) -> Result<bool>
98            + 'js,
99    {
100        self.0.set(
101            PredefinedAtom::Setter,
102            Function::new(self.0.ctx().clone(), set)?,
103        )?;
104        Ok(())
105    }
106
107    /// Set the setter function for the proxy handler
108    pub fn with_setter<F>(self, set: F) -> Result<Self>
109    where
110        F: Fn(ProxyTarget<'js>, ProxyProperty<'js>, Value<'js>, ProxyReceiver<'js>) -> Result<bool>
111            + 'js,
112    {
113        self.set_setter(set)?;
114        Ok(self)
115    }
116
117    /// Set the has function for the proxy handler
118    pub fn set_has<F>(&self, has: F) -> Result<()>
119    where
120        F: Fn(ProxyTarget<'js>, ProxyProperty<'js>) -> Result<bool> + 'js,
121    {
122        self.0.set(
123            PredefinedAtom::Has,
124            Function::new(self.0.ctx().clone(), has)?,
125        )?;
126        Ok(())
127    }
128
129    /// Set the has function for the proxy handler
130    pub fn with_has<F>(self, has: F) -> Result<Self>
131    where
132        F: Fn(ProxyTarget<'js>, ProxyProperty<'js>) -> Result<bool> + 'js,
133    {
134        self.set_has(has)?;
135        Ok(self)
136    }
137
138    /// Set the delete function for the proxy handler
139    pub fn set_delete<F>(&self, delete: F) -> Result<()>
140    where
141        F: Fn(ProxyTarget<'js>, ProxyProperty<'js>) -> Result<bool> + 'js,
142    {
143        self.0.set(
144            PredefinedAtom::DeleteProperty,
145            Function::new(self.0.ctx().clone(), delete)?,
146        )?;
147        Ok(())
148    }
149
150    /// Set the delete function for the proxy handler
151    pub fn with_delete<F>(self, delete: F) -> Result<Self>
152    where
153        F: Fn(ProxyTarget<'js>, ProxyProperty<'js>) -> Result<bool> + 'js,
154    {
155        self.set_delete(delete)?;
156        Ok(self)
157    }
158}
159
160impl<'js> IntoJs<'js> for ProxyHandler<'js> {
161    fn into_js(self, ctx: &Ctx<'js>) -> Result<Value<'js>> {
162        self.0.into_js(ctx)
163    }
164}