1 /*
2 * Copyright (c) 2012 Joyent, Inc. All rights reserved.
3 */
4
5 #include <sys/ccompile.h>
6 #include <stdlib.h>
7 #include <float.h>
8 #include <errno.h>
9 #include <libnvpair.h>
10 #include "example.h"
11
12 static nvlist_t *
13 example_set_impl(example_t *ep, nvpair_t *pp)
14 {
15 double dv;
16 const char *sv;
17 const char *ev;
18 uint64_t v;
19
20 switch (v8plus_typeof(pp)) {
21 case V8PLUS_TYPE_NUMBER:
22 (void) nvpair_value_double(pp, &dv);
23 if (dv > (1ULL << DBL_MANT_DIG) - 1) {
24 return (v8plus_error(V8PLUSERR_IMPRECISE,
25 "large number lacks integer precision"));
26 }
27 ep->e_val = (uint64_t)dv;
28 break;
29 case V8PLUS_TYPE_STRING:
30 (void) nvpair_value_string(pp, (char **)&sv);
31 errno = 0;
32 v = (uint64_t)strtoull(sv, (char **)&ev, 0);
33 if (errno == ERANGE) {
34 return (v8plus_error(V8PLUSERR_RANGE,
35 "value '%s' is out of range", sv));
36 }
37 if (ev != NULL && *ev != '\0') {
38 return (v8plus_error(V8PLUSERR_MALFORMED,
39 "value '%s' is malformed", sv));
40 }
41 ep->e_val = v;
42 break;
43 case V8PLUS_TYPE_UNDEFINED:
44 ep->e_val = 0;
45 break;
46 default:
47 return (v8plus_error(V8PLUSERR_BADARG,
48 "argument 0 is of incorrect type %d", v8plus_typeof(pp)));
49 }
50
51 return (v8plus_void());
52 }
53
54 static nvlist_t *
55 example_ctor(const nvlist_t *ap, void **epp)
56 {
57 nvpair_t *pp;
58 example_t *ep;
59
60 if (v8plus_args(ap, V8PLUS_ARG_F_NOEXTRA, V8PLUS_TYPE_NONE) != 0 &&
61 v8plus_args(ap, V8PLUS_ARG_F_NOEXTRA,
62 V8PLUS_TYPE_ANY, &pp, V8PLUS_TYPE_NONE) != 0)
63 return (NULL);
64
65 if ((ep = malloc(sizeof (example_t))) == NULL)
66 return (v8plus_error(V8PLUSERR_NOMEM, NULL));
67
68 (void) example_set_impl(ep, pp);
69 if (_v8plus_errno != V8PLUSERR_NOERROR) {
70 free(ep);
71 return (NULL);
72 }
73
74 *epp = ep;
75
76 return (v8plus_void());
77 }
78
79 static void
80 example_dtor(void *op)
81 {
82 free(op);
83 }
84
85 static nvlist_t *
86 example_set(void *op, const nvlist_t *ap)
87 {
88 nvpair_t *pp;
89 example_t *ep = op;
90
91 if (v8plus_args(ap, V8PLUS_ARG_F_NOEXTRA,
92 V8PLUS_TYPE_ANY, &pp,
93 V8PLUS_TYPE_NONE) != 0)
94 return (NULL);
95
96 (void) example_set_impl(ep, pp);
97 if (_v8plus_errno != V8PLUSERR_NOERROR)
98 return (NULL);
99
100 return (v8plus_void());
101 }
102
103 static nvlist_t *
104 example_add(void *op, const nvlist_t *ap)
105 {
106 example_t *ep = op;
107 example_t ae;
108 nvpair_t *pp;
109 nvlist_t *eap;
110 nvlist_t *erp;
111
112 if (v8plus_args(ap, V8PLUS_ARG_F_NOEXTRA,
113 V8PLUS_TYPE_ANY, &pp, V8PLUS_TYPE_NONE) != 0)
114 return (NULL);
115
116 (void) example_set_impl(&ae, pp);
117 if (_v8plus_errno != V8PLUSERR_NOERROR)
118 return (NULL);
119
120 ep->e_val += ae.e_val;
121
122 eap = v8plus_obj(V8PLUS_TYPE_STRING, "0", "add", V8PLUS_TYPE_NONE);
123 if (eap != NULL) {
124 erp = v8plus_method_call(op, "__emit", eap);
125 nvlist_free(eap);
126 nvlist_free(erp);
127 }
128
129 return (v8plus_void());
130 }
131
132 static nvlist_t *
133 example_static_add(const nvlist_t *ap)
134 {
135 example_t ae0, ae1;
136 nvpair_t *pp0, *pp1;
137 uint64_t rv;
138
139 if (v8plus_args(ap, V8PLUS_ARG_F_NOEXTRA,
140 V8PLUS_TYPE_ANY, &pp0,
141 V8PLUS_TYPE_ANY, &pp1,
142 V8PLUS_TYPE_NONE) != 0)
143 return (NULL);
144
145 (void) example_set_impl(&ae0, pp0);
146 if (_v8plus_errno != V8PLUSERR_NOERROR)
147 return (NULL);
148
149 (void) example_set_impl(&ae1, pp1);
150 if (_v8plus_errno != V8PLUSERR_NOERROR)
151 return (NULL);
152
153 rv = ae0.e_val + ae1.e_val;
154
155 return (v8plus_obj(
156 V8PLUS_TYPE_STRNUMBER64, "res", rv,
157 V8PLUS_TYPE_NONE));
158 }
159
160 static nvlist_t *
161 example_multiply(void *op, const nvlist_t *ap)
162 {
163 example_t *ep = op;
164 example_t ae;
165 nvpair_t *pp;
166
167 if (v8plus_args(ap, V8PLUS_ARG_F_NOEXTRA,
168 V8PLUS_TYPE_ANY, &pp, V8PLUS_TYPE_NONE) != 0)
169 return (NULL);
170
171 (void) example_set_impl(&ae, pp);
172 if (_v8plus_errno != V8PLUSERR_NOERROR)
173 return (NULL);
174
175 ep->e_val *= ae.e_val;
176
177 return (v8plus_void());
178 }
179
180 typedef struct async_multiply_ctx {
181 example_t amc_operand;
182 uint64_t amc_result;
183 v8plus_jsfunc_t amc_cb;
184 } async_multiply_ctx_t;
185
186 static void *
187 async_multiply_worker(void *op, void *ctx)
188 {
189 example_t *ep = op;
190 async_multiply_ctx_t *cp = ctx;
191 example_t *ap = &cp->amc_operand;
192
193 cp->amc_result = ep->e_val * ap->e_val;
194
195 return (NULL);
196 }
197
198 static void
199 async_multiply_done(void *op, void *ctx, void *res __UNUSED)
200 {
201 async_multiply_ctx_t *cp = ctx;
202 example_t *ep = op;
203 nvlist_t *rp;
204 nvlist_t *ap;
205
206 ep->e_val = cp->amc_result;
207 ap = v8plus_obj(V8PLUS_TYPE_NONE);
208 if (ap != NULL) {
209 rp = v8plus_call(cp->amc_cb, ap);
210 nvlist_free(ap);
211 nvlist_free(rp);
212 }
213
214 v8plus_jsfunc_rele(cp->amc_cb);
215 free(cp);
216 }
217
218 static nvlist_t *
219 example_multiplyAsync(void *op, const nvlist_t *ap)
220 {
221 nvpair_t *pp;
222 v8plus_jsfunc_t cb;
223 async_multiply_ctx_t *cp;
224
225 if (v8plus_args(ap, V8PLUS_ARG_F_NOEXTRA,
226 V8PLUS_TYPE_ANY, &pp,
227 V8PLUS_TYPE_JSFUNC, &cb,
228 V8PLUS_TYPE_NONE) != 0)
229 return (NULL);
230
231 if ((cp = malloc(sizeof (async_multiply_ctx_t))) == NULL)
232 return (v8plus_error(V8PLUSERR_NOMEM, "no memory for context"));
233
234 (void) example_set_impl(&cp->amc_operand, pp);
235 if (_v8plus_errno != V8PLUSERR_NOERROR) {
236 free(cp);
237 return (NULL);
238 }
239
240 v8plus_jsfunc_hold(cb);
241 cp->amc_cb = cb;
242
243 v8plus_defer(op, cp, async_multiply_worker, async_multiply_done);
244
245 return (v8plus_void());
246 }
247
248 static nvlist_t *
249 example_toString(void *op, const nvlist_t *ap)
250 {
251 example_t *ep = op;
252 nvpair_t *pp;
253
254 /*
255 * Example of decorated exceptions. Not strictly needed.
256 */
257 if (v8plus_args(ap, 0,
258 V8PLUS_TYPE_ANY, &pp, V8PLUS_TYPE_NONE) == 0) {
259 (void) v8plus_error(V8PLUSERR_EXTRAARG, NULL);
260 return (v8plus_obj(
261 V8PLUS_TYPE_INL_OBJECT, "err",
262 V8PLUS_TYPE_NUMBER, "example_argument", (double)0,
263 V8PLUS_TYPE_NUMBER, "example_type",
264 (double)v8plus_typeof(pp),
265 V8PLUS_TYPE_NONE,
266 V8PLUS_TYPE_NONE));
267 }
268
269 return (v8plus_obj(
270 V8PLUS_TYPE_STRNUMBER64, "res", (uint64_t)ep->e_val,
271 V8PLUS_TYPE_NONE));
272 }
273
274 static nvlist_t *
275 example_static_object(const nvlist_t *ap __UNUSED)
276 {
277 return (v8plus_obj(
278 V8PLUS_TYPE_INL_OBJECT, "res",
279 V8PLUS_TYPE_NUMBER, "fred", (double)555.5,
280 V8PLUS_TYPE_STRING, "barney", "the sky is blue",
281 V8PLUS_TYPE_INL_OBJECT, "betty",
282 V8PLUS_TYPE_STRING, "bert", "ernie",
283 V8PLUS_TYPE_BOOLEAN, "coffeescript_is_a_joke", B_TRUE,
284 V8PLUS_TYPE_NONE,
285 V8PLUS_TYPE_NULL, "wilma",
286 V8PLUS_TYPE_UNDEFINED, "pebbles",
287 V8PLUS_TYPE_NUMBER, "bam-bam", (double)-32,
288 V8PLUS_TYPE_STRNUMBER64, "dino", 0x1234567812345678ULL,
289 V8PLUS_TYPE_NONE,
290 V8PLUS_TYPE_NONE));
291 }
292
293 /*
294 * v8+ boilerplate
295 */
296 const v8plus_c_ctor_f v8plus_ctor = example_ctor;
297 const v8plus_c_dtor_f v8plus_dtor = example_dtor;
298 const char *v8plus_js_factory_name = "create";
299 const char *v8plus_js_class_name = "Example";
300 const v8plus_method_descr_t v8plus_methods[] = {
301 {
302 md_name: "set",
303 md_c_func: example_set
304 },
305 {
306 md_name: "add",
307 md_c_func: example_add
308 },
309 {
310 md_name: "multiply",
311 md_c_func: example_multiply
312 },
313 {
314 md_name: "toString",
315 md_c_func: example_toString
316 },
317 {
318 md_name: "multiplyAsync",
319 md_c_func: example_multiplyAsync
320 }
321 };
322 const uint_t v8plus_method_count =
323 sizeof (v8plus_methods) / sizeof (v8plus_methods[0]);
324
325 const v8plus_static_descr_t v8plus_static_methods[] = {
326 {
327 sd_name: "static_add",
328 sd_c_func: example_static_add
329 },
330 {
331 sd_name: "static_object",
332 sd_c_func: example_static_object
333 }
334 };
335 const uint_t v8plus_static_method_count =
336 sizeof (v8plus_static_methods) / sizeof (v8plus_static_methods[0]);