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]);