1use error::{Error, Result};
2use ffi;
3use std::marker::PhantomData;
4use types::Ref;
5use util::{protect_duktape_closure, StackGuard};
6use value::{FromValue, ToValue, ToValues, Value};
7
8#[derive(Clone, Debug)]
10pub struct Object<'ducc>(pub(crate) Ref<'ducc>);
11
12impl<'ducc> Object<'ducc> {
13 pub fn get<K: ToValue<'ducc>, V: FromValue<'ducc>>(&self, key: K) -> Result<V> {
23 let ducc = self.0.ducc;
24 let key = key.to_value(ducc)?;
25 let value = unsafe {
26 assert_stack!(ducc.ctx, 0, {
27 ducc.push_ref(&self.0);
28 ducc.push_value(key);
29 protect_duktape_closure(ducc.ctx, 2, 1, |ctx| {
30 ffi::duk_get_prop(ctx, -2);
31 })?;
32 ducc.pop_value()
33 })
34 };
35 V::from_value(value, ducc)
36 }
37
38 pub fn set<K: ToValue<'ducc>, V: ToValue<'ducc>>(&self, key: K, value: V) -> Result<()> {
47 let ducc = self.0.ducc;
48 let key = key.to_value(ducc)?;
49 let value = value.to_value(ducc)?;
50 unsafe {
51 assert_stack!(ducc.ctx, 0, {
52 ducc.push_ref(&self.0);
53 ducc.push_value(key);
54 ducc.push_value(value);
55 protect_duktape_closure(ducc.ctx, 3, 0, |ctx| {
56 ffi::duk_put_prop(ctx, -3);
57 })
58 })
59 }
60 }
61
62 pub fn remove<K: ToValue<'ducc>>(&self, key: K) -> Result<()> {
72 let ducc = self.0.ducc;
73 let key = key.to_value(ducc)?;
74 unsafe {
75 assert_stack!(ducc.ctx, 0, {
76 ducc.push_ref(&self.0);
77 ducc.push_value(key);
78 protect_duktape_closure(ducc.ctx, 2, 0, |ctx| {
79 ffi::duk_del_prop(ctx, -2);
80 })
81 })
82 }
83 }
84
85 pub fn contains_key<K: ToValue<'ducc>>(&self, key: K) -> Result<bool> {
94 let ducc = self.0.ducc;
95 let key = key.to_value(ducc)?;
96 unsafe {
97 assert_stack!(ducc.ctx, 0, {
98 ducc.push_ref(&self.0);
99 ducc.push_value(key);
100 protect_duktape_closure(ducc.ctx, 2, 0, |ctx| {
101 ffi::duk_has_prop(ctx, -2) != 0
102 })
103 })
104 }
105 }
106
107 pub fn len(&self) -> Result<usize> {
112 let ducc = self.0.ducc;
113 unsafe {
114 assert_stack!(ducc.ctx, 0, {
115 ducc.push_ref(&self.0);
116 protect_duktape_closure(ducc.ctx, 1, 0, |ctx| {
117 ffi::duk_get_length(ctx, -1)
118 })
119 })
120 }
121 }
122
123 pub fn call_prop<K, A, R>(&self, key: K, args: A) -> Result<R>
126 where
127 K: ToValue<'ducc>,
128 A: ToValues<'ducc>,
129 R: FromValue<'ducc>,
130 {
131 let value: Value = self.get(key)?;
132 if let Some(func) = value.as_function() {
133 func.call_method(self.clone(), args)
134 } else {
135 Err(Error::not_a_function())
136 }
137 }
138
139 pub fn properties<K: FromValue<'ducc>, V: FromValue<'ducc>>(self) -> Properties<'ducc, K, V> {
143 let ducc = self.0.ducc;
144 unsafe {
145 let _sg = StackGuard::new(ducc.ctx);
146 ducc.push_ref(&self.0);
147 ffi::duk_require_stack(ducc.ctx, 1);
148 ffi::duk_enum(ducc.ctx, -1, 0);
149 Properties {
150 object_enum: ducc.pop_ref(),
151 _phantom: PhantomData,
152 }
153 }
154 }
155}
156
157pub struct Properties<'ducc, K, V> {
158 object_enum: Ref<'ducc>,
159 _phantom: PhantomData<(K, V)>,
160}
161
162impl<'ducc, K, V> Iterator for Properties<'ducc, K, V>
163where
164 K: FromValue<'ducc>,
165 V: FromValue<'ducc>,
166{
167 type Item = Result<(K, V)>;
168
169 fn next(&mut self) -> Option<Self::Item> {
170 let ducc = self.object_enum.ducc;
171 unsafe {
172 let _sg = StackGuard::new(ducc.ctx);
173 ducc.push_ref(&self.object_enum);
174 ffi::duk_require_stack(ducc.ctx, 2);
175 if ffi::duk_next(ducc.ctx, -1, 1) != 0 {
176 let value = match ducc.pop_value().into(ducc) {
177 Ok(value) => value,
178 Err(err) => return Some(Err(err)),
179 };
180 let key = match ducc.pop_value().into(ducc) {
181 Ok(key) => key,
182 Err(err) => return Some(Err(err)),
183 };
184 Some(Ok((key, value)))
185 } else {
186 None
187 }
188 }
189 }
190}