ion/function/
arguments.rs1use std::borrow::Cow;
8use std::iter::repeat_with;
9
10use mozjs::jsapi::CallArgs;
11use mozjs::jsval::JSVal;
12
13use crate::conversions::FromValue;
14use crate::function::{Opt, Rest};
15use crate::{Context, Error, ErrorKind, Function, Local, Object, Result, Value};
16
17pub struct Arguments<'cx> {
20 cx: &'cx Context,
21 args: u16,
22 callee: Object<'cx>,
23 call_args: CallArgs,
24}
25
26impl<'cx> Arguments<'cx> {
27 pub unsafe fn new(cx: &'cx Context, argc: u32, vp: *mut JSVal) -> Arguments<'cx> {
28 unsafe {
29 let call_args = CallArgs::from_vp(vp, argc);
30 let callee = cx.root(call_args.callee()).into();
31
32 Arguments {
33 cx,
34 args: u16::try_from(argc).unwrap(),
35 callee,
36 call_args,
37 }
38 }
39 }
40
41 pub fn check_args(&self, cx: &Context, min: u16, key: Option<&str>) -> Result<()> {
43 if self.args < min {
44 let key = key.map_or_else(
45 || {
46 let callee = Function::from_object(cx, &self.callee).unwrap();
47 callee.name(cx).map(Cow::Owned)
48 },
49 |k| Ok(Cow::Borrowed(k)),
50 )?;
51 let suffix = if min == 1 { "" } else { "s" };
52 let verb = if min == 1 { "was" } else { "were" };
53
54 return Err(Error::new(
55 format!(
56 "{key}: At least {min} argument{suffix} expected, but only {} {verb} passed.",
57 self.args,
58 ),
59 ErrorKind::Type,
60 ));
61 }
62 Ok(())
63 }
64
65 pub fn len(&self) -> u16 {
67 self.args
68 }
69
70 pub fn is_empty(&self) -> bool {
72 self.len() == 0
73 }
74
75 pub fn cx(&self) -> &'cx Context {
77 self.cx
78 }
79
80 pub fn callee(&self) -> Object<'cx> {
82 Object::from(Local::from_handle(self.callee.handle()))
83 }
84
85 pub fn this(&self) -> Value<'cx> {
88 Value::from(unsafe { Local::from_raw_handle(self.call_args.thisv()) })
89 }
90
91 pub fn rval(&mut self) -> Value<'cx> {
94 Value::from(unsafe { Local::from_raw_handle_mut(self.call_args.rval()) })
95 }
96
97 pub fn new_target(&self) -> Option<Value<'cx>> {
99 self.is_constructing()
100 .then(|| Value::from(unsafe { Local::from_raw_handle_mut(self.call_args.new_target()) }))
101 }
102
103 pub fn value(&self, index: u16) -> Option<Value<'cx>> {
105 if index < self.len() {
106 return Some(Value::from(unsafe {
107 Local::from_raw_handle(self.call_args.get(u32::from(index)))
108 }));
109 }
110 None
111 }
112
113 pub fn is_constructing(&self) -> bool {
115 self.call_args.constructing_()
116 }
117
118 pub fn ignores_return_value(&self) -> bool {
120 self.call_args.ignoresReturnValue_()
121 }
122
123 pub fn call_args(&self) -> &CallArgs {
124 &self.call_args
125 }
126
127 pub fn access<'a>(&'a mut self) -> Accessor<'a, 'cx> {
128 Accessor { args: self, index: 0 }
129 }
130}
131
132pub struct Accessor<'a, 'cx> {
133 args: &'a mut Arguments<'cx>,
134 index: u16,
135}
136
137impl<'cx> Accessor<'_, 'cx> {
138 pub fn len(&self) -> u16 {
140 self.args.len() - self.index
141 }
142
143 pub fn is_empty(&self) -> bool {
145 self.index == self.args.len()
146 }
147
148 pub fn cx(&self) -> &'cx Context {
150 self.args.cx()
151 }
152
153 pub fn callee(&self) -> Object<'cx> {
155 self.args.callee()
156 }
157
158 pub fn this(&self) -> Value<'cx> {
161 self.args.this()
162 }
163
164 pub fn value(&mut self) -> Value<'cx> {
169 assert!(self.index < self.args.len());
170 let arg = self.args.value(self.index).unwrap();
171 self.index += 1;
172 arg
173 }
174
175 pub fn is_constructing(&self) -> bool {
177 self.args.is_constructing()
178 }
179
180 pub fn ignores_return_value(&self) -> bool {
182 self.args.ignores_return_value()
183 }
184}
185
186pub trait FromArgument<'a, 'cx>: Sized {
187 type Config;
188
189 fn from_argument(accessor: &'a mut Accessor<'_, 'cx>, config: Self::Config) -> Result<Self>;
191}
192
193impl<'cx> FromArgument<'_, 'cx> for &'cx Context {
194 type Config = ();
195
196 fn from_argument(accessor: &mut Accessor<'_, 'cx>, _: ()) -> Result<&'cx Context> {
197 Ok(accessor.cx())
198 }
199}
200
201impl<'a, 'cx> FromArgument<'a, 'cx> for &'a mut Arguments<'cx> {
202 type Config = ();
203
204 fn from_argument(accessor: &'a mut Accessor<'_, 'cx>, _: ()) -> Result<&'a mut Arguments<'cx>> {
205 Ok(accessor.args)
206 }
207}
208
209impl<'cx, T: FromValue<'cx>> FromArgument<'_, 'cx> for T {
210 type Config = T::Config;
211
212 fn from_argument(accessor: &mut Accessor<'_, 'cx>, config: T::Config) -> Result<T> {
213 T::from_value(accessor.cx(), &accessor.value(), false, config)
214 }
215}
216
217impl<'cx, T: FromValue<'cx>> FromArgument<'_, 'cx> for Opt<T> {
218 type Config = T::Config;
219
220 fn from_argument(accessor: &mut Accessor<'_, 'cx>, config: Self::Config) -> Result<Opt<T>> {
221 if accessor.is_empty() {
222 Ok(Opt(None))
223 } else {
224 T::from_value(accessor.cx(), &accessor.value(), false, config).map(Some).map(Opt)
225 }
226 }
227}
228
229impl<'cx, T: FromValue<'cx>> FromArgument<'_, 'cx> for Rest<T>
230where
231 T::Config: Clone,
232{
233 type Config = T::Config;
234
235 fn from_argument(accessor: &mut Accessor<'_, 'cx>, config: Self::Config) -> Result<Rest<T>> {
236 let len = accessor.len();
237 repeat_with(|| T::from_value(accessor.cx(), &accessor.value(), false, config.clone()))
238 .take(len.into())
239 .collect::<Result<Box<[_]>>>()
240 .map(Rest)
241 }
242}