Skip to content
Browse files

add example code in the spirit of node.js docs

allow returning primitives in addition to objects
fix a bunch of memory leaks, add C dtor
clarify docs and fix a few typos
  • Loading branch information...
1 parent e2a9198 commit 35eac559123bf60ef855f32646520a45a76ebcbb @wesolows wesolows committed
Showing with 524 additions and 112 deletions.
  1. +3 −3 Makefile.v8plus.defs
  2. +83 −11 README.md
  3. +16 −0 examples/Makefile
  4. +34 −0 examples/errno.json
  5. +223 −0 examples/example.c
  6. +21 −0 examples/example.h
  7. +44 −0 examples/test.js
  8. +3 −1 v8plus_glue.h
  9. +3 −3 v8plus_impl.h
  10. +14 −7 v8plus_objectwrap.cc
  11. +80 −87 v8plus_subr.cc
View
6 Makefile.v8plus.defs
@@ -8,20 +8,20 @@ WHICH_NODE = dirname `bash -c 'hash node; hash -t node'`
CC = gcc
CXX = g++
PREFIX_NODE = $(WHICH_NODE:sh)/..
-V8PLUS = $(PWD)/v8plus
DEBUG_FLAGS = -g
WARN_FLAGS = -Wall -Wextra -Werror
PIC_FLAGS = -fPIC
+OPT_FLAGS = -O2
-CFLAGS = $(DEBUG_FLAGS) $(WARN_FLAGS) $(PIC_FLAGS)
+CFLAGS = $(DEBUG_FLAGS) $(WARN_FLAGS) $(PIC_FLAGS) $(OPT_FLAGS)
CXXFLAGS = $(CFLAGS)
STD_DEFS = -D_GNU_SOURCE
NODE_DEFS = -DBUILDING_NODE_EXTENSION
LF64_DEFS = -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64
PIC_DEFS = -DPIC
-NODE_INCS = -isystem $(PREFIX_NODE)/include/node -I.
+NODE_INCS = -isystem $(PREFIX_NODE)/include/node -I. -I$(V8PLUS)
CPPFLAGS = $(STD_DEFS) $(NODE_DEFS) $(LF64_DEFS) $(PIC_DEFS) $(NODE_INCS)
CXXPPFLAGS = $(CPPFLAGS)
View
94 README.md
@@ -32,6 +32,11 @@ may return v8plus_void() if your function does not return anything, or
an nvlist containing a 'res' member as described in 'Returning Values'
below. If you need to throw a JavaScript exception, see Exceptions below.
+If your constructor (or any method's implementation) allocates memory, free
+it in your destructor, which will be passed the pointer set by your
+constructor when the object is garbage collected. Set v8plus_dtor to an
+appropriate destructor, which may be an empty function.
+
### Argument Handling
When JavaScript objects cross the boundary from C++ to C, they are
@@ -50,13 +55,18 @@ member ".__v8plus_type" set to the object's JavaScript type name. Note
that the member name itself begins with a . to reduce the likelihood of a
collision with an actual JavaScript member name.
+Because JavaScript arrays may be sparse, we cannot use the libnvpair array
+types. Consider them reserved for internal use. JavaScript Arrays are
+represented as they really are in JavaScript: objects with properties whose
+names happen to be integers.
+
Other data types cannot be represented and will result in a TypeError
being thrown. If your object has methods that need other argument types,
you cannot use v8+. XXX Callbacks need to be represented as pointers
somehow so that they can be called.
-Side effects within the VM, including modification of the arguments, is
-not supported. If you need this, you cannot use v8+.
+Side effects within the VM, including modification of the arguments, are
+not supported. If you need them, you cannot use v8+.
### Returning Values
@@ -82,11 +92,43 @@ generic exception to be thrown, return the value returned by v8plus_error().
In this case, the error code will be translated to an exception type and the
message string will be used as the message member of the exception. Other
members will not be present in the exception unless you also return an
-nvlist containing an 'err' member (or, from a constructor, any nvlist)
-Only basic v8-provided exception types can be thrown;
-if your addon needs to throw some other kind of exception, you will need
-to either use v8 directly or catch and re-throw from a JavaScript
-wrapper.
+nvlist containing an 'err' member (or, from a constructor, any nvlist) Only
+basic v8-provided exception types can be thrown; if your addon needs to
+throw some other kind of exception, you will need to either use v8 directly
+or catch and re-throw from a JavaScript wrapper.
+
+## Errors
+
+The v8plus_errno_t enumerated type and a family of utility functions are
+automatically generated by generrno.js from a simple JSON file. The schema
+of this file is as follows:
+
+ {
+ "error_base": <string>,
+ "errors": [
+ {
+ "code": <string>,
+ "msg": <string>,
+ "exception": <string>
+ },
+ ... ]
+ }
+
+For each entry in the errors array, an identifier V8PLUSERR_<code> will be
+added to v8plus_errno_t. By convention, code should be all upper case. The
+default error message (present in JavaScript exceptions if a more specific
+error message is not provided to v8plus_error()) is given by the msg
+property. The exception property must be one of "Error", "TypeError",
+"ReferenceError", "RangeError", or "SyntaxError"; i.e., the standard
+exception types available in v8. This is the type of exception that will be
+generated and thrown when a C function returns NULL with this error code
+set. In addition, the built-in error codes V8PLUSERR_NOMEM,
+V8PLUSERR_YOUSUCK, and V8PLUSERR_UNKNOWN are available for your use,
+indicating an out of memory condition, programmer error (e.g., failure of
+something you would assert in JavaScript), and an error code that cannot be
+translated, respectively.
+
+Set the make variable ERRNO_JSON to the name of this file.
## Installation
@@ -106,13 +148,19 @@ the src/ subdirectory of your Node module. That is,
Because v8+ doesn't do anything itself, there's no installation procedure and
no npm support. All you need to do to use v8+ is:
-1. Create a Makefile for your native module that includes the v8+ makefiles.
-See the example for help.
+0. Write the C code that does whatever your module does. Be sure to
+#include "v8plus/v8plus_glue.h". Do not include any other v8+ headers.
-2. Add posix-getopt to your module's dependency list in package.json and
+1. Add posix-getopt to your module's dependency list in package.json and
make sure it's installed.
-3. Run make.
+2. Create a JSON file defining the error codes your module will use. See
+Errors above.
+
+3. Create a Makefile for your native module that includes the v8+ makefiles.
+See the example for help.
+
+4. Run make.
It's not necessary for v8+ sources to be located immediately beneath the build
directory or your sources. Set V8PLUS to the appropriate location in your
@@ -129,6 +177,21 @@ trying to understand a bunch of implicit side effects or typing templated
identifiers that can't fit in 80 columns without falling afoul of the
language's ambiguous grammar. Don't get me started.
+- Why not use [FFI](https://github.com/rbranson/node-ffi)?
+
+FFI is really cool; it offers us the ability to use C libraries without
+writing bindings at all. However, it also exposes a lot of C nastiness to
+JavaScript code, essentially placing the interface boundary in consuming
+code itself. This pretty much breaks the JavaScript interface model --
+for example, you can't really have a function that inspects the types of its
+arguments -- and requires you to write an additional C library anyway if you
+want or need to do something natively that's not quite what the C library
+already does. Of course, one could use it to write "bindings" in JavaScript
+that actually look like a JavaScript interface, which may end up being the
+best answer, especially if those are autogenerated from CTF! In short, v8+
+and FFI are different approaches to the problem. Use whichever fits your
+need, and note that they're not mutually exclusive, either.
+
- What systems can I use this on?
[illumos](http://illumos.org) distributions, or possibly other platforms with
@@ -163,6 +226,15 @@ name of your addon. Using it would therefore require the source to v8+ to
be generated at build time to match your module's name, which is
inconvenient. There may be a way to work around this.
+- Why can't I see my exception's decorative properties in JavaScript?
+
+Be careful when decorating exceptions. There are several built-in hidden
+properties; if you decorate the exception with a property with the same
+name, you will change the hidden property's value but it will still be
+hidden. This almost certainly is not what you want, so you should prefix
+the decorative property names with something unique to your module to avoid
+stepping on v8's (or JavaScript's) property namespace.
+
- What if the factory model doesn't work for me?
See "License" below.
View
16 examples/Makefile
@@ -0,0 +1,16 @@
+V8PLUS = ..
+
+include $(V8PLUS)/Makefile.v8plus.defs
+
+MODULE = example
+
+SRCS = \
+ example.c
+
+ERRNO_JSON = errno.json
+
+PREFIX_NODE = /opt/node
+CC = /opt/local/bin/gcc
+CXX = /opt/local/bin/g++
+
+include $(V8PLUS)/Makefile.v8plus.targ
View
34 examples/errno.json
@@ -0,0 +1,34 @@
+{
+ "error_base": "0x2000",
+ "errors": [
+ {
+ "code": "BADARG",
+ "msg": "incorrect type for argument",
+ "exception": "TypeError"
+ },
+ {
+ "code": "MISSINGARG",
+ "msg": "missing argument",
+ "exception": "TypeError"
+ },
+ {
+ "code": "EXTRAARG",
+ "msg": "illegal superfluous argument",
+ "exception": "TypeError"
+ },
+ {
+ "code": "IMPRECISE",
+ "msg": "numerical value lacks adequate precision",
+ "exception": "TypeError"
+ },
+ {
+ "code": "RANGE",
+ "msg": "value out of range",
+ "exception": "RangeError"
+ },
+ {
+ "code": "MALFORMED",
+ "msg": "value is malformed or unparseable",
+ "exception": "TypeError"
+ } ]
+}
View
223 examples/example.c
@@ -0,0 +1,223 @@
+#include <sys/ccompile.h>
+#include <stdlib.h>
+#include <float.h>
+#include <errno.h>
+#include <libnvpair.h>
+#include "example.h"
+
+static nvlist_t *
+example_set_impl(example_t *ep, nvpair_t *pp)
+{
+ double dv;
+ const char *sv;
+ const char *ev;
+ uint64_t v;
+
+ switch (nvpair_type(pp)) {
+ case DATA_TYPE_DOUBLE:
+ (void) nvpair_value_double(pp, &dv);
+ if (dv > (1ULL << DBL_MANT_DIG) - 1) {
+ return (v8plus_error(V8PLUSERR_IMPRECISE,
+ "translation of large number will lose precision"));
+ }
+ ep->e_val = (uint64_t)dv;
+ break;
+ case DATA_TYPE_STRING:
+ (void) nvpair_value_string(pp, (char **)&sv);
+ errno = 0;
+ v = (uint64_t)strtoull(sv, (char **)&ev, 0);
+ if (errno == ERANGE) {
+ return (v8plus_error(V8PLUSERR_RANGE,
+ "value is out of range"));
+ }
+ if (ev != NULL && *ev != '\0') {
+ return (v8plus_error(V8PLUSERR_MALFORMED,
+ "value '%s' is malformed", sv));
+ }
+ ep->e_val = v;
+ break;
+ case DATA_TYPE_BOOLEAN: /* undefined */
+ ep->e_val = 0;
+ break;
+ default:
+ return (v8plus_error(V8PLUSERR_BADARG,
+ "argument 0 is of incorrect type %d", nvpair_type(pp)));
+ }
+
+ return (v8plus_void());
+}
+
+static nvlist_t *
+example_ctor(const nvlist_t *ap, void **epp)
+{
+ nvpair_t *pp;
+ example_t *ep = malloc(sizeof (example_t));
+
+ if (ep == NULL)
+ return (v8plus_error(V8PLUSERR_NOMEM, NULL));
+
+ if (nvlist_lookup_nvpair((nvlist_t *)ap, "0", &pp) == 0) {
+ (void)example_set_impl(ep, pp);
+ if (_v8plus_errno != V8PLUSERR_NOERROR) {
+ free(ep);
+ return (NULL);
+ }
+ } else {
+ ep->e_val = 0;
+ }
+
+ *epp = ep;
+
+ return (v8plus_void());
+}
+
+static void
+example_dtor(void *op)
+{
+ free(op);
+}
+
+static nvlist_t *
+example_set(void *op, const nvlist_t *ap)
+{
+ nvpair_t *pp;
+ example_t *ep = op;
+
+ if (nvlist_lookup_nvpair((nvlist_t *)ap, "0", &pp) != 0) {
+ return (v8plus_error(V8PLUSERR_MISSINGARG,
+ "argument 0 is required"));
+ }
+
+ (void) example_set_impl(ep, pp);
+ if (_v8plus_errno != V8PLUSERR_NOERROR)
+ return (NULL);
+
+ return (v8plus_void());
+}
+
+static nvlist_t *
+example_add(void *op, const nvlist_t *ap)
+{
+ example_t *ep = op;
+ example_t ae;
+ nvpair_t *pp;
+
+ if (nvlist_lookup_nvpair((nvlist_t *)ap, "0", &pp) != 0) {
+ return (v8plus_error(V8PLUSERR_MISSINGARG,
+ "argument 0 is required"));
+ }
+
+ (void) example_set_impl(&ae, pp);
+ if (_v8plus_errno != V8PLUSERR_NOERROR)
+ return (NULL);
+
+ ep->e_val += ae.e_val;
+
+ return (v8plus_void());
+}
+
+static nvlist_t *
+example_multiply(void *op, const nvlist_t *ap)
+{
+ example_t *ep = op;
+ example_t ae;
+ nvpair_t *pp;
+
+ if (nvlist_lookup_nvpair((nvlist_t *)ap, "0", &pp) != 0) {
+ return (v8plus_error(V8PLUSERR_MISSINGARG,
+ "argument 0 is required"));
+ }
+
+ (void) example_set_impl(&ae, pp);
+ if (_v8plus_errno != V8PLUSERR_NOERROR)
+ return (NULL);
+
+ ep->e_val *= ae.e_val;
+
+ return (v8plus_void());
+}
+
+static nvlist_t *
+example_toString(void *op, const nvlist_t *ap)
+{
+ example_t *ep = op;
+ nvpair_t *pp;
+ nvlist_t *rp;
+ int err;
+ char vbuf[16];
+
+ if ((err = nvlist_alloc(&rp, NV_UNIQUE_NAME, 0)) != 0)
+ return (v8plus_nverr(err, NULL));
+
+ /*
+ * Example of decorated exceptions. Not strictly needed. And yeah,
+ * this interface kind of sucks.
+ */
+ if (nvlist_lookup_nvpair((nvlist_t *)ap, "0", &pp) == 0) {
+ nvlist_t *xp;
+
+ if ((err = nvlist_alloc(&xp, NV_UNIQUE_NAME, 0)) != 0) {
+ nvlist_free(rp);
+ return (v8plus_nverr(err, NULL));
+ }
+
+ if ((err = nvlist_add_double(xp, "example_argument", 0)) != 0) {
+ nvlist_free(rp);
+ return (v8plus_nverr(err, "example_argument"));
+ }
+
+ if ((err = nvlist_add_double(xp,
+ "example_type", nvpair_type(pp))) != 0) {
+ nvlist_free(rp);
+ return (v8plus_nverr(err, "example_type"));
+ }
+
+ if ((err = nvlist_add_nvlist(rp, "err", xp)) != 0) {
+ nvlist_free(xp);
+ nvlist_free(rp);
+ return (v8plus_nverr(err, "err"));
+ }
+
+ (void) v8plus_error(V8PLUSERR_EXTRAARG,
+ "unsupported superfluous argument(s) found");
+ return (rp);
+ }
+
+ (void)snprintf(vbuf, sizeof (vbuf), "%llu",
+ (unsigned long long)ep->e_val);
+
+ if ((err = nvlist_add_string(rp, "res", vbuf)) != 0) {
+ nvlist_free(rp);
+ return (v8plus_nverr(err, "res"));
+ }
+
+ return (rp);
+}
+
+/*
+ * v8+ boilerplate
+ */
+const v8plus_c_ctor_f v8plus_ctor = example_ctor;
+const v8plus_c_dtor_f v8plus_dtor = example_dtor;
+const char *v8plus_js_factory_name = "create";
+const char *v8plus_js_class_name = "Example";
+const v8plus_method_descr_t v8plus_methods[] = {
+ {
+ md_name: "set",
+ md_c_func: example_set
+ },
+ {
+ md_name: "add",
+ md_c_func: example_add
+ },
+ {
+ md_name: "multiply",
+ md_c_func: example_multiply
+ },
+ {
+ md_name: "toString",
+ md_c_func: example_toString
+ }
+};
+const uint_t v8plus_method_count =
+ sizeof (v8plus_methods) / sizeof (v8plus_methods[0]);
View
21 examples/example.h
@@ -0,0 +1,21 @@
+#ifndef _EXAMPLE_H
+#define _EXAMPLE_H
+
+#include <stdarg.h>
+#include <sys/types.h>
+#include <libnvpair.h>
+#include "v8plus_glue.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+typedef struct example {
+ uint64_t e_val;
+} example_t;
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* _EXAMPLE_H */
View
44 examples/test.js
@@ -0,0 +1,44 @@
+var example = require('./example');
+var util = require('util');
+
+var e = example.create();
+var f = example.create('8000000000');
+
+console.log('e = ' + e.toString());
+console.log('f = ' + f.toString());
+
+e.add(132);
+console.log('e = ' + e.toString());
+
+try {
+ e.set(0x1111111111111111);
+} catch (e) {
+ console.log('got exception: ' + e.name + ' (' + e.message + ')');
+}
+
+e.set('0x1111111111111111');
+console.log('e = ' + e.toString());
+
+e.multiply(5);
+console.log('e = ' + e.toString());
+
+try {
+ e.toString(33, 'fred');
+} catch (e) {
+ console.log('got exception: ' + e.name + ' (' + e.message + ')');
+ console.log(util.inspect(e, false, null));
+}
+
+e.set(50000000);
+f.set(22222222);
+e.multiply(f.toString());
+console.log('e = ' + e.toString());
+console.log('f = ' + f.toString());
+
+function
+x()
+{
+ var n = example.create(32);
+}
+
+x();
View
4 v8plus_glue.h
@@ -16,10 +16,11 @@ extern "C" {
#define V8PLUS_ERRMSG_LEN 512
/*
- * C constructor and method prototypes. See README.md.
+ * C constructor, destructor, and method prototypes. See README.md.
*/
typedef nvlist_t *(*v8plus_c_ctor_f)(const nvlist_t *, void **);
typedef nvlist_t *(*v8plus_c_method_f)(void *, const nvlist_t *);
+typedef void (*v8plus_c_dtor_f)(void *);
typedef struct v8plus_method_descr {
const char *md_name;
@@ -70,6 +71,7 @@ extern const char *v8plus_excptype(v8plus_errno_t);
* Provided by C code. See README.md.
*/
extern const v8plus_c_ctor_f v8plus_ctor;
+extern const v8plus_c_dtor_f v8plus_dtor;
extern const char *v8plus_js_factory_name;
extern const char *v8plus_js_class_name;
extern const v8plus_method_descr_t v8plus_methods[];
View
6 v8plus_impl.h
@@ -36,15 +36,15 @@ class ObjectWrap : public node::ObjectWrap {
static v8plus_method_descr_t *_mtbl;
void *_c_impl;
- ObjectWrap() {};
- ~ObjectWrap() {};
+ ObjectWrap() : _c_impl(NULL) {};
+ ~ObjectWrap() { v8plus_dtor(_c_impl); };
static v8::Handle<v8::Value> _new(const v8::Arguments &);
static v8::Handle<v8::Value> _entry(const v8::Arguments &);
};
extern nvlist_t *v8_Arguments_to_nvlist(const v8::Arguments &);
-extern v8::Local<v8::Object> nvlist_to_v8_Object(const nvlist_t *);
+extern v8::Handle<v8::Value> nvpair_to_v8_Value(const nvpair_t *);
extern v8::Local<v8::Value> exception(const char *, const nvlist_t *,
const char *, ...) __PRINTFLIKE(3);
extern void panic(const char *, ...) __PRINTFLIKE(1) __NORETURN;
View
21 v8plus_objectwrap.cc
@@ -65,7 +65,7 @@ v8plus::ObjectWrap::init()
}
v8::Handle<v8::Value>
-v8plus::ObjectWrap::_new(const v8::Arguments& args)
+v8plus::ObjectWrap::_new(const v8::Arguments &args)
{
v8::HandleScope scope;
v8plus::ObjectWrap *op = new v8plus::ObjectWrap();
@@ -116,7 +116,8 @@ v8plus::ObjectWrap::_entry(const v8::Arguments &args)
node::ObjectWrap::Unwrap<v8plus::ObjectWrap>(args.This());
nvlist_t *c_args;
nvlist_t *c_out;
- nvlist_t *res, *excp;
+ nvlist_t *excp;
+ nvpair_t *rpp;
v8::Local<v8::String> self = args.Callee()->GetName()->ToString();
v8::String::Utf8Value selfsv(self);
const char *fn = *selfsv;
@@ -147,12 +148,18 @@ v8plus::ObjectWrap::_entry(const v8::Arguments &args)
else
return (V8PLUS_THROW_DEFAULT());
} else {
- if (nvlist_lookup_nvlist(c_out, "err", &excp) == 0)
- return (V8PLUS_THROW_DECORATED(excp));
- else if (nvlist_lookup_nvlist(c_out, "res", &res) == 0)
- return (scope.Close(v8plus::nvlist_to_v8_Object(res)));
- else
+ if (nvlist_lookup_nvlist(c_out, "err", &excp) == 0) {
+ v8::Handle<v8::Value> x = V8PLUS_THROW_DECORATED(excp);
+ nvlist_free(c_out);
+ return (x);
+ } else if (nvlist_lookup_nvpair(c_out, "res", &rpp) == 0) {
+ v8::Handle<v8::Value> r =
+ v8plus::nvpair_to_v8_Value(rpp);
+ nvlist_free(c_out);
+ return (scope.Close(r));
+ } else {
v8plus::panic("bad encoded object in return");
+ }
}
/*NOTREACHED*/
View
167 v8plus_subr.cc
@@ -120,9 +120,11 @@ nvlist_add_v8_Value(nvlist_t *lp, const char *name,
return (err);
}
} else {
- /* XXX exception or something, fuck */
- (void) fprintf(stderr, "can't handle %s", type);
- abort();
+ /*
+ * XXX This is (C) programmer error. Should
+ * we plumb up a way to throw here?
+ */
+ (void) v8plus::panic("can't handle %s", type);
}
}
@@ -178,108 +180,99 @@ v8plus::v8_Arguments_to_nvlist(const v8::Arguments &args)
return (lp);
}
-#define SET(_o, _p, _jt, _ct, _xt, _pt) \
- do { \
- _ct _v; \
- (void) nvpair_value_##_pt((_p), &_v); \
- (_o)->Set(v8::String::New(nvpair_name((_p))), \
- v8::_jt::New((_xt)_v)); \
- } while (0)
-
-#define SET_JS(_o, _p, _c) \
- (_o)->Set(v8::String::New(nvpair_name((_p))), (_c))
-
/* XXX pass Handle/Local by value or reference? */
static void
-decorate_object(v8::Local<v8::Object> &obj, const nvlist_t *lp)
+decorate_object(v8::Local<v8::Object> &oh, const nvlist_t *lp)
{
nvpair_t *pp = NULL;
while ((pp =
nvlist_next_nvpair(const_cast<nvlist_t *>(lp), pp)) != NULL) {
- switch (nvpair_type(pp)) {
- case DATA_TYPE_BOOLEAN:
- SET_JS(obj, pp, v8::Undefined());
- break;
- case DATA_TYPE_BOOLEAN_VALUE:
- SET(obj, pp, Boolean, boolean_t, bool, boolean_value);
- break;
- case DATA_TYPE_BYTE:
- {
- uint8_t _v = (uint8_t)-1;
-
- if (nvpair_value_byte(pp, &_v) != 0 || _v != 0)
- v8plus::panic("bad byte value %02x\n", _v);
-
- SET_JS(obj, pp, v8::Null());
- }
- break;
- case DATA_TYPE_INT8:
- SET(obj, pp, Number, int8_t, double, int8);
- break;
- case DATA_TYPE_UINT8:
- SET(obj, pp, Number, uint8_t, double, uint8);
- break;
- case DATA_TYPE_INT16:
- SET(obj, pp, Number, int16_t, double, int16);
- break;
- case DATA_TYPE_UINT16:
- SET(obj, pp, Number, uint16_t, double, uint16);
- break;
- case DATA_TYPE_INT32:
- SET(obj, pp, Number, int32_t, double, int32);
- break;
- case DATA_TYPE_UINT32:
- SET(obj, pp, Number, uint32_t, double, uint32);
- break;
- case DATA_TYPE_INT64:
- SET(obj, pp, Number, int64_t, double, int64);
- break;
- case DATA_TYPE_UINT64:
- SET(obj, pp, Number, uint64_t, double, uint64);
- break;
- case DATA_TYPE_STRING:
- SET(obj, pp, String,
- char *, const char *, string);
- break;
- case DATA_TYPE_NVLIST:
- {
- nvlist_t *clp = NULL;
- (void) nvpair_value_nvlist(pp, &clp);
- SET_JS(obj, pp, v8plus::nvlist_to_v8_Object(clp));
- }
- break;
- default:
- v8plus::panic("bad data type %d\n", nvpair_type(pp));
- }
+ oh->Set(v8::String::New(nvpair_name(pp)),
+ v8plus::nvpair_to_v8_Value(pp));
}
}
-#undef SET
-#undef SET_JS
+#define RETURN_JS(_p, _jt, _ct, _xt, _pt) \
+ do { \
+ _ct _v; \
+ (void) nvpair_value_##_pt(const_cast<nvpair_t *>(_p), &_v); \
+ return (v8::_jt::New((_xt)_v)); \
+ } while (0)
-v8::Local<v8::Object>
-v8plus::nvlist_to_v8_Object(const nvlist_t *lp)
+v8::Handle<v8::Value>
+v8plus::nvpair_to_v8_Value(const nvpair_t *pp)
{
- v8::Local<v8::Object> obj;
const char *type;
- if (nvlist_lookup_string(const_cast<nvlist_t *>(lp),
- V8PLUS_OBJ_TYPE_MEMBER, const_cast<char **>(&type)) != 0)
- type = "Object";
-
- if (strcmp(type, "Array") == 0)
- obj = v8::Array::New()->ToObject();
- else if (strcmp(type, "Object") != 0)
- v8plus::panic("bad object type %s\n", type);
- else
- obj = v8::Object::New();
+ switch (nvpair_type(const_cast<nvpair_t *>(pp))) {
+ case DATA_TYPE_BOOLEAN:
+ return (v8::Undefined());
+ case DATA_TYPE_BOOLEAN_VALUE:
+ RETURN_JS(pp, Boolean, boolean_t, bool, boolean_value);
+ case DATA_TYPE_BYTE:
+ {
+ uint8_t _v = (uint8_t)-1;
+
+ if (nvpair_value_byte(const_cast<nvpair_t *>(pp), &_v) != 0 ||
+ _v != 0) {
+ v8plus::panic("bad byte value %02x\n", _v);
+ }
- decorate_object(obj, lp);
+ return (v8::Null());
+ }
+ case DATA_TYPE_INT8:
+ RETURN_JS(pp, Number, int8_t, double, int8);
+ case DATA_TYPE_UINT8:
+ RETURN_JS(pp, Number, uint8_t, double, uint8);
+ case DATA_TYPE_INT16:
+ RETURN_JS(pp, Number, int16_t, double, int16);
+ case DATA_TYPE_UINT16:
+ RETURN_JS(pp, Number, uint16_t, double, uint16);
+ case DATA_TYPE_INT32:
+ RETURN_JS(pp, Number, int32_t, double, int32);
+ case DATA_TYPE_UINT32:
+ RETURN_JS(pp, Number, uint32_t, double, uint32);
+ case DATA_TYPE_INT64:
+ RETURN_JS(pp, Number, int64_t, double, int64);
+ case DATA_TYPE_UINT64:
+ RETURN_JS(pp, Number, uint64_t, double, uint64);
+ case DATA_TYPE_DOUBLE:
+ RETURN_JS(pp, Number, double, double, double);
+ case DATA_TYPE_STRING:
+ RETURN_JS(pp, String, char *, const char *, string);
+ case DATA_TYPE_NVLIST:
+ {
+ nvlist_t *lp;
+ v8::Local<v8::Object> oh;
+
+ (void) nvpair_value_nvlist(const_cast<nvpair_t *>(pp), &lp);
+
+ if (nvlist_lookup_string(const_cast<nvlist_t *>(lp),
+ V8PLUS_OBJ_TYPE_MEMBER, const_cast<char **>(&type)) != 0)
+ type = "Object";
+
+ if (strcmp(type, "Array") == 0)
+ oh = v8::Array::New()->ToObject();
+ else if (strcmp(type, "Object") != 0)
+ v8plus::panic("bad object type %s\n", type);
+ else
+ oh = v8::Object::New();
+
+ decorate_object(oh, lp);
+ return (oh);
+ }
+ default:
+ v8plus::panic("bad data type %d\n",
+ nvpair_type(const_cast<nvpair_t *>(pp)));
+ }
- return (obj);
+ /*NOTREACHED*/
+ return (v8::Undefined());
}
+#undef RETURN_JS
+
static v8::Local<v8::Value>
sexception(const char *type, const nvlist_t *lp, const char *msg)
{

0 comments on commit 35eac55

Please sign in to comment.
Something went wrong with that request. Please try again.