├── .npmignore ├── .gitignore ├── .jshintrc ├── test ├── binding.gyp ├── struct.js └── struct_tests.cc ├── .travis.yml ├── package.json ├── appveyor.yml ├── CHANGELOG.md ├── README.md └── lib └── struct.js /.npmignore: -------------------------------------------------------------------------------- 1 | /test -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /node_modules 2 | /test/build 3 | /?.js 4 | -------------------------------------------------------------------------------- /.jshintrc: -------------------------------------------------------------------------------- 1 | { 2 | "asi": true, 3 | "laxcomma": true, 4 | "node": true, 5 | "strict": false 6 | } 7 | -------------------------------------------------------------------------------- /test/binding.gyp: -------------------------------------------------------------------------------- 1 | { 2 | 'targets': [ 3 | { 4 | 'target_name': 'struct_tests', 5 | 'sources': [ 'struct_tests.cc' ], 6 | 'include_dirs': [ 7 | ' (http://tootallnate.net)", 14 | "repository": { 15 | "type": "git", 16 | "url": "git://github.com/TooTallNate/ref-struct.git" 17 | }, 18 | "main": "./lib/struct.js", 19 | "license": "MIT", 20 | "scripts": { 21 | "test": "node-gyp rebuild --directory test && mocha -gc --reporter spec" 22 | }, 23 | "dependencies": { 24 | "debug": "2", 25 | "ref": "1" 26 | }, 27 | "devDependencies": { 28 | "bindings": "~1.2.0", 29 | "nan": "2", 30 | "mocha": "*", 31 | "ref-array": "~1.1.2" 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /appveyor.yml: -------------------------------------------------------------------------------- 1 | # http://www.appveyor.com/docs/appveyor-yml 2 | 3 | # Test against these versions of Node.js. 4 | environment: 5 | # Visual Studio Version 6 | MSVS_VERSION: 2013 7 | # Test against these versions of Node.js and io.js 8 | matrix: 9 | - nodejs_version: "4" 10 | - nodejs_version: "6" 11 | - nodejs_version: "7" 12 | - nodejs_version: "8" 13 | 14 | platform: 15 | - x86 16 | - x64 17 | 18 | # Install scripts. (runs after repo cloning) 19 | install: 20 | # Get the latest stable version of Node 0.STABLE.latest 21 | - ps: if($env:nodejs_version -eq "0.8") {Install-Product node $env:nodejs_version} 22 | - ps: if($env:nodejs_version -ne "0.8") {Update-NodeJsInstallation (Get-NodeJsLatestBuild $env:nodejs_version)} 23 | # Node 0.8 comes with a too obsolete npm 24 | - IF %nodejs_version% == 0.8 (npm install -g npm@1.4.28) 25 | # Install latest NPM only for node.js versions until built in node-gyp adds io.js support 26 | # Update is required for node.js 0.8 because built in npm(node-gyp) does not know VS2013 27 | - IF %nodejs_version% LSS 1 (npm install -g npm@2) 28 | - IF %nodejs_version% LSS 1 set PATH=%APPDATA%\npm;%PATH% 29 | # Typical npm stuff. 30 | - npm install --msvs_version=%MSVS_VERSION% 31 | 32 | # Post-install test scripts. 33 | test_script: 34 | # Output useful info for debugging. 35 | - node --version 36 | - npm --version 37 | # run tests 38 | - npm test 39 | 40 | # Don't actually build. 41 | build: off 42 | 43 | # Set build version format here instead of in the admin panel. 44 | version: "{build}" 45 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | 2 | 1.1.0 / 2016-08-02 3 | ================== 4 | 5 | * [[`eb4550fdaa`](https://github.com/TooTallNate/ref-struct/commit/eb4550fdaa)] - Implement `pack` option (Lee, SungUk) 6 | * [[`17c1c7a8ef`](https://github.com/TooTallNate/ref-struct/commit/17c1c7a8ef)] - fix StructType constructor name in README (typo) (David Corticchiato) 7 | * [[`54b72bde07`](https://github.com/TooTallNate/ref-struct/commit/54b72bde07)] - **appveyor**: fix node v0.8, test io.js v2.5 and v3 (Nathan Rajlich) 8 | 9 | 1.0.2 / 2015-08-27 10 | ================== 11 | 12 | * appveyor: drop v0.11, iojs v1.5.1, test x64 13 | * travis: drop v0.11, test iojs v2.5 and v3 14 | * package: add license attribute (#17, @pdehaan) 15 | * package: update "ref-array" to v1.1.2 16 | * package: update "nan" v2 for native tests 17 | * README: use SVG for appveyor badge 18 | 19 | 1.0.1 / 2015-03-24 20 | ================== 21 | 22 | * removed travis testing for node_js version "0.6" and added 0.12 and iojs 23 | * added appveyor test versions as per node-ffi library for iojs & 0.12 24 | * package: allow any "ref" v "1" 25 | * npmignore: add `test` dir 26 | 27 | 1.0.0 / 2014-11-03 28 | ================== 29 | 30 | * bumping to v1.0.0 for better-defined semver semantics 31 | 32 | 0.0.7 / 2014-11-03 33 | ================== 34 | 35 | * gitignore: ignore single letter ?.js test files 36 | * lib: only slice buffer in set() in the non-instance case 37 | * package: allow any "debug" v2 38 | 39 | 0.0.6 / 2014-06-19 40 | ================== 41 | 42 | * package: update "ref" to v0.3.2 43 | * package: update "debug" to v1.0.1 44 | * test: remove v8 namespace import 45 | * test: use "bindings" module to load the native tests 46 | * README: add appveyor build badge 47 | * History: match `git changelog` syntax 48 | * package: loosely pin the deps 49 | * test: nan-ify tests 50 | * README: fix Travis badge 51 | * README: use svg for Travis badge 52 | * travis: test node v0.8, v0.10, and v0.11 53 | * add appveyor.yml file for Windows testing 54 | * package: remove "engines" field 55 | * package: beautify 56 | * add a couple comments 57 | 58 | 0.0.5 / 2013-01-24 59 | ================== 60 | 61 | * rename the backing buffer property to `ref.buffer` 62 | * add .jshintrc file 63 | * some minor optimizations 64 | 65 | 0.0.4 / 2012-09-26 66 | ================== 67 | 68 | * struct: correct the field alignment logic (TJ Fontaine) 69 | * test: add failing test from #1 70 | * test: more stucts with arrays tests 71 | * add support for "ref-array" types 72 | * add `toObject()`, `toJSON()`, and `inspect()` functions to struct instances 73 | * change `_pointer` to `buffer` 74 | * don't allow types with size == 0 like 'void' 75 | * test: add test case using "void *" as the type 76 | * test: fix deprecation warning 77 | * package: use the -C switch on node-gyp for the `npm test` command 78 | * travis: test node v0.7 and node v0.8 79 | * adjust the custom `toString()` output 80 | 81 | 0.0.3 / 2012-06-01 82 | ================== 83 | 84 | * set the "name" property of StructType instances 85 | * add a `toString()` override 86 | * fix a bug in the alignment calculation logic 87 | 88 | 0.0.2 / 2012-05-16 89 | ================== 90 | 91 | * Windows support (only the test suite needed tweaks) 92 | * make ref().deref() work 93 | * make string type identifiers work (type coersion) 94 | * don't make the constructors' prototype inherit from `Function.protoype` 95 | 96 | 0.0.1 / 2012-05-09 97 | ================== 98 | 99 | * Initial release 100 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ref-struct 2 | ========== 3 | ### Create ABI-compliant "[struct][]" instances on top of Buffers 4 | [![Build Status](https://secure.travis-ci.org/TooTallNate/ref-struct.svg)](https://travis-ci.org/TooTallNate/ref-struct) 5 | [![Build Status](https://ci.appveyor.com/api/projects/status/6v4h5v5kh9kmtke8?svg=true)](https://ci.appveyor.com/project/TooTallNate/ref-struct) 6 | 7 | 8 | This module offers a "struct" implementation on top of Node.js Buffers 9 | using the ref "type" interface. 10 | 11 | Installation 12 | ------------ 13 | 14 | Install with `npm`: 15 | 16 | ``` bash 17 | $ npm install ref-struct 18 | ``` 19 | 20 | 21 | Examples 22 | -------- 23 | 24 | Say you wanted to emulate the `timeval` struct from the stdlib: 25 | 26 | ``` c 27 | struct timeval { 28 | time_t tv_sec; /* seconds since Jan. 1, 1970 */ 29 | suseconds_t tv_usec; /* and microseconds */ 30 | }; 31 | ``` 32 | 33 | ``` js 34 | var ref = require('ref') 35 | var StructType = require('ref-struct') 36 | 37 | // define the time types 38 | var time_t = ref.types.long 39 | var suseconds_t = ref.types.long 40 | 41 | // define the "timeval" struct type 42 | var timeval = StructType({ 43 | tv_sec: time_t, 44 | tv_usec: suseconds_t 45 | }) 46 | 47 | // now we can create instances of it 48 | var tv = new timeval 49 | ``` 50 | 51 | #### With `node-ffi` 52 | 53 | This gets very powerful when combined with `node-ffi` to invoke C functions: 54 | 55 | ``` js 56 | var ffi = require('ffi') 57 | 58 | var tv = new timeval 59 | gettimeofday(tv.ref(), null) 60 | ``` 61 | 62 | #### Progressive API 63 | 64 | You can build up a Struct "type" incrementally (useful when interacting with a 65 | parser) using the `defineProperty()` function. But as soon as you _create_ an 66 | instance of the struct type, then the struct type is finalized, and no more 67 | properties may be added to it. 68 | 69 | ``` js 70 | var ref = require('ref') 71 | var StructType = require('ref-struct') 72 | 73 | var MyStruct = StructType() 74 | MyStruct.defineProperty('width', ref.types.int) 75 | MyStruct.defineProperty('height', ref.types.int) 76 | 77 | var i = new MyStruct({ width: 5, height: 10 }) 78 | 79 | MyStruct.defineProperty('weight', ref.types.int) 80 | // AssertionError: an instance of this Struct type has already been created, cannot add new "fields" anymore 81 | // at Function.defineProperty (/Users/nrajlich/ref-struct/lib/struct.js:180:3) 82 | ``` 83 | 84 | 85 | License 86 | ------- 87 | 88 | (The MIT License) 89 | 90 | Copyright (c) 2012 Nathan Rajlich <nathan@tootallnate.net> 91 | 92 | Permission is hereby granted, free of charge, to any person obtaining 93 | a copy of this software and associated documentation files (the 94 | 'Software'), to deal in the Software without restriction, including 95 | without limitation the rights to use, copy, modify, merge, publish, 96 | distribute, sublicense, and/or sell copies of the Software, and to 97 | permit persons to whom the Software is furnished to do so, subject to 98 | the following conditions: 99 | 100 | The above copyright notice and this permission notice shall be 101 | included in all copies or substantial portions of the Software. 102 | 103 | THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, 104 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 105 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 106 | IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 107 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 108 | TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 109 | SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 110 | 111 | [struct]: http://wikipedia.org/wiki/Struct_(C_programming_language) 112 | -------------------------------------------------------------------------------- /lib/struct.js: -------------------------------------------------------------------------------- 1 | 2 | /** 3 | * An interface for modeling and instantiating C-style data structures. This is 4 | * not a constructor per-say, but a constructor generator. It takes an array of 5 | * tuples, the left side being the type, and the right side being a field name. 6 | * The order should be the same order it would appear in the C-style struct 7 | * definition. It returns a function that can be used to construct an object that 8 | * reads and writes to the data structure using properties specified by the 9 | * initial field list. 10 | * 11 | * The only verboten field names are "ref", which is used used on struct 12 | * instances as a function to retrieve the backing Buffer instance of the 13 | * struct, and "ref.buffer" which contains the backing Buffer instance. 14 | * 15 | * 16 | * Example: 17 | * 18 | * ``` javascript 19 | * var ref = require('ref') 20 | * var Struct = require('ref-struct') 21 | * 22 | * // create the `char *` type 23 | * var charPtr = ref.refType(ref.types.char) 24 | * var int = ref.types.int 25 | * 26 | * // create the struct "type" / constructor 27 | * var PasswordEntry = Struct({ 28 | * 'username': 'string' 29 | * , 'password': 'string' 30 | * , 'salt': int 31 | * }) 32 | * 33 | * // create an instance of the struct, backed a Buffer instance 34 | * var pwd = new PasswordEntry() 35 | * pwd.username = 'ricky' 36 | * pwd.password = 'rbransonlovesnode.js' 37 | * pwd.salt = (Math.random() * 1000000) | 0 38 | * 39 | * pwd.username // → 'ricky' 40 | * pwd.password // → 'rbransonlovesnode.js' 41 | * pwd.salt // → 820088 42 | * ``` 43 | */ 44 | 45 | /** 46 | * Module dependencies. 47 | */ 48 | 49 | var ref = require('ref') 50 | var util = require('util') 51 | var assert = require('assert') 52 | var debug = require('debug')('ref:struct') 53 | 54 | /** 55 | * Module exports. 56 | */ 57 | 58 | module.exports = Struct 59 | 60 | /** 61 | * The Struct "type" meta-constructor. 62 | */ 63 | 64 | function Struct () { 65 | debug('defining new struct "type"') 66 | 67 | /** 68 | * This is the "constructor" of the Struct type that gets returned. 69 | * 70 | * Invoke it with `new` to create a new Buffer instance backing the struct. 71 | * Pass it an existing Buffer instance to use that as the backing buffer. 72 | * Pass in an Object containing the struct fields to auto-populate the 73 | * struct with the data. 74 | */ 75 | 76 | function StructType (arg, data) { 77 | if (!(this instanceof StructType)) { 78 | return new StructType(arg, data) 79 | } 80 | debug('creating new struct instance') 81 | var store 82 | if (Buffer.isBuffer(arg)) { 83 | debug('using passed-in Buffer instance to back the struct', arg) 84 | assert(arg.length >= StructType.size, 'Buffer instance must be at least ' + 85 | StructType.size + ' bytes to back this struct type') 86 | store = arg 87 | arg = data 88 | } else { 89 | debug('creating new Buffer instance to back the struct (size: %d)', StructType.size) 90 | store = new Buffer(StructType.size) 91 | } 92 | 93 | // set the backing Buffer store 94 | store.type = StructType 95 | this['ref.buffer'] = store 96 | 97 | if (arg) { 98 | for (var key in arg) { 99 | // hopefully hit the struct setters 100 | this[key] = arg[key] 101 | } 102 | } 103 | StructType._instanceCreated = true 104 | } 105 | 106 | // make instances inherit from the `proto` 107 | StructType.prototype = Object.create(proto, { 108 | constructor: { 109 | value: StructType 110 | , enumerable: false 111 | , writable: true 112 | , configurable: true 113 | } 114 | }) 115 | 116 | StructType.defineProperty = defineProperty 117 | StructType.toString = toString 118 | StructType.fields = {} 119 | 120 | var opt = (arguments.length > 0 && arguments[1]) ? arguments[1] : {}; 121 | // Setup the ref "type" interface. The constructor doubles as the "type" object 122 | StructType.size = 0 123 | StructType.alignment = 0 124 | StructType.indirection = 1 125 | StructType.isPacked = opt.packed ? Boolean(opt.packed) : false 126 | StructType.get = get 127 | StructType.set = set 128 | 129 | // Read the fields list and apply all the fields to the struct 130 | // TODO: Better arg handling... (maybe look at ES6 binary data API?) 131 | var arg = arguments[0] 132 | if (Array.isArray(arg)) { 133 | // legacy API 134 | arg.forEach(function (a) { 135 | var type = a[0] 136 | var name = a[1] 137 | StructType.defineProperty(name, type) 138 | }) 139 | } else if (typeof arg === 'object') { 140 | Object.keys(arg).forEach(function (name) { 141 | var type = arg[name] 142 | StructType.defineProperty(name, type) 143 | }) 144 | } 145 | 146 | return StructType 147 | } 148 | 149 | /** 150 | * The "get" function of the Struct "type" interface 151 | */ 152 | 153 | function get (buffer, offset) { 154 | debug('Struct "type" getter for buffer at offset', buffer, offset) 155 | if (offset > 0) { 156 | buffer = buffer.slice(offset) 157 | } 158 | return new this(buffer) 159 | } 160 | 161 | /** 162 | * The "set" function of the Struct "type" interface 163 | */ 164 | 165 | function set (buffer, offset, value) { 166 | debug('Struct "type" setter for buffer at offset', buffer, offset, value) 167 | var isStruct = value instanceof this 168 | if (isStruct) { 169 | // optimization: copy the buffer contents directly rather 170 | // than going through the ref-struct constructor 171 | value['ref.buffer'].copy(buffer, offset, 0, this.size) 172 | } else { 173 | if (offset > 0) { 174 | buffer = buffer.slice(offset) 175 | } 176 | new this(buffer, value) 177 | } 178 | } 179 | 180 | /** 181 | * Custom `toString()` override for struct type instances. 182 | */ 183 | 184 | function toString () { 185 | return '[StructType]' 186 | } 187 | 188 | /** 189 | * Adds a new field to the struct instance with the given name and type. 190 | * Note that this function will throw an Error if any instances of the struct 191 | * type have already been created, therefore this function must be called at the 192 | * beginning, before any instances are created. 193 | */ 194 | 195 | function defineProperty (name, type) { 196 | debug('defining new struct type field', name) 197 | 198 | // allow string types for convenience 199 | type = ref.coerceType(type) 200 | 201 | assert(!this._instanceCreated, 'an instance of this Struct type has already ' + 202 | 'been created, cannot add new "fields" anymore') 203 | assert.equal('string', typeof name, 'expected a "string" field name') 204 | assert(type && /object|function/i.test(typeof type) && 'size' in type && 205 | 'indirection' in type 206 | , 'expected a "type" object describing the field type: "' + type + '"') 207 | assert(type.indirection > 1 || type.size > 0, 208 | '"type" object must have a size greater than 0') 209 | assert(!(name in this.prototype), 'the field "' + name + 210 | '" already exists in this Struct type') 211 | 212 | var field = { 213 | type: type 214 | } 215 | this.fields[name] = field 216 | 217 | // define the getter/setter property 218 | var desc = { enumerable: true , configurable: true } 219 | desc.get = function () { 220 | debug('getting "%s" struct field (offset: %d)', name, field.offset) 221 | return ref.get(this['ref.buffer'], field.offset, type) 222 | } 223 | desc.set = function (value) { 224 | debug('setting "%s" struct field (offset: %d)', name, field.offset, value) 225 | return ref.set(this['ref.buffer'], field.offset, value, type) 226 | } 227 | 228 | // calculate the new size and field offsets 229 | recalc(this) 230 | 231 | Object.defineProperty(this.prototype, name, desc) 232 | } 233 | 234 | function recalc (struct) { 235 | 236 | // reset size and alignment 237 | struct.size = 0 238 | struct.alignment = 0 239 | 240 | var fieldNames = Object.keys(struct.fields) 241 | 242 | // first loop through is to determine the `alignment` of this struct 243 | fieldNames.forEach(function (name) { 244 | var field = struct.fields[name] 245 | var type = field.type 246 | var alignment = type.alignment || ref.alignof.pointer 247 | if (type.indirection > 1) { 248 | alignment = ref.alignof.pointer 249 | } 250 | if (struct.isPacked) { 251 | struct.alignment = Math.min(struct.alignment || alignment, alignment) 252 | } else { 253 | struct.alignment = Math.max(struct.alignment, alignment) 254 | } 255 | }) 256 | 257 | // second loop through sets the `offset` property on each "field" 258 | // object, and sets the `struct.size` as we go along 259 | fieldNames.forEach(function (name) { 260 | var field = struct.fields[name] 261 | var type = field.type 262 | 263 | if (null != type.fixedLength) { 264 | // "ref-array" types set the "fixedLength" prop. don't treat arrays like one 265 | // contiguous entity. instead, treat them like individual elements in the 266 | // struct. doing this makes the padding end up being calculated correctly. 267 | field.offset = addType(type.type) 268 | for (var i = 1; i < type.fixedLength; i++) { 269 | addType(type.type) 270 | } 271 | } else { 272 | field.offset = addType(type) 273 | } 274 | }) 275 | 276 | function addType (type) { 277 | var offset = struct.size 278 | var align = type.indirection === 1 ? type.alignment : ref.alignof.pointer 279 | var padding = struct.isPacked ? 0 : (align - (offset % align)) % align 280 | var size = type.indirection === 1 ? type.size : ref.sizeof.pointer 281 | 282 | offset += padding 283 | 284 | if (!struct.isPacked) { 285 | assert.equal(offset % align, 0, "offset should align") 286 | } 287 | 288 | // adjust the "size" of the struct type 289 | struct.size = offset + size 290 | 291 | // return the calulated offset 292 | return offset 293 | } 294 | 295 | // any final padding? 296 | var left = struct.size % struct.alignment 297 | if (left > 0) { 298 | debug('additional padding to the end of struct:', struct.alignment - left) 299 | struct.size += struct.alignment - left 300 | } 301 | } 302 | 303 | /** 304 | * this is the custom prototype of Struct type instances. 305 | */ 306 | 307 | var proto = {} 308 | 309 | /** 310 | * set a placeholder variable on the prototype so that defineProperty() will 311 | * throw an error if you try to define a struct field with the name "buffer". 312 | */ 313 | 314 | proto['ref.buffer'] = ref.NULL 315 | 316 | /** 317 | * Flattens the Struct instance into a regular JavaScript Object. This function 318 | * "gets" all the defined properties. 319 | * 320 | * @api public 321 | */ 322 | 323 | proto.toObject = function toObject () { 324 | var obj = {} 325 | Object.keys(this.constructor.fields).forEach(function (k) { 326 | obj[k] = this[k] 327 | }, this) 328 | return obj 329 | } 330 | 331 | /** 332 | * Basic `JSON.stringify(struct)` support. 333 | */ 334 | 335 | proto.toJSON = function toJSON () { 336 | return this.toObject() 337 | } 338 | 339 | /** 340 | * `.inspect()` override. For the REPL. 341 | * 342 | * @api public 343 | */ 344 | 345 | proto.inspect = function inspect () { 346 | var obj = this.toObject() 347 | // add instance's "own properties" 348 | Object.keys(this).forEach(function (k) { 349 | obj[k] = this[k] 350 | }, this) 351 | return util.inspect(obj) 352 | } 353 | 354 | /** 355 | * returns a Buffer pointing to this struct data structure. 356 | */ 357 | 358 | proto.ref = function ref () { 359 | return this['ref.buffer'] 360 | } 361 | -------------------------------------------------------------------------------- /test/struct.js: -------------------------------------------------------------------------------- 1 | 2 | var assert = require('assert') 3 | , ref = require('ref') 4 | , ArrayType = require('ref-array') 5 | , Struct = require('../') 6 | , bindings = require('bindings')({ module_root: __dirname, bindings: 'struct_tests' }) 7 | 8 | describe('Struct', function () { 9 | 10 | afterEach(gc) 11 | 12 | it('should be a function', function () { 13 | assert.equal('function', typeof Struct) 14 | }) 15 | 16 | it('should return a struct constuctor function', function () { 17 | var S = Struct() 18 | assert.equal('function', typeof S) 19 | }) 20 | 21 | it('should throw when the same field name is speicified more than once', function () { 22 | var S = Struct({ a: ref.types.int }) 23 | assert.throws(function () { 24 | S.defineProperty('a', ref.types.int) 25 | }) 26 | }) 27 | 28 | it('should throw when given a type with "size" == 0', function () { 29 | assert.throws(function () { 30 | Struct({ v: 'void' }) 31 | }) 32 | }) 33 | 34 | it('should work in a simple case', function () { 35 | var SimpleStruct = Struct({ 36 | 'first': ref.types.byte 37 | , 'last': ref.types.byte 38 | }) 39 | assert.equal(2, SimpleStruct.size) 40 | assert.equal(1, SimpleStruct.alignment) 41 | 42 | var ss = new SimpleStruct({ first: 50, last: 100 }) 43 | assert.equal(50, ss.first) 44 | assert.equal(100, ss.last) 45 | }) 46 | 47 | it('should work in a more complex case', function () { 48 | var MegaStruct = Struct({ 49 | 'byteVal': ref.types.byte 50 | , 'int8Val': ref.types.int8 51 | , 'int16Val': ref.types.int16 52 | , 'uint16Val': ref.types.uint16 53 | , 'int32Val': ref.types.int32 54 | , 'uint32Val': ref.types.uint32 55 | , 'floatVal': ref.types.float 56 | , 'doubleVal': ref.types.double 57 | , 'pointer': ref.refType('void') 58 | }) 59 | var msTestPtr = new Buffer(1) 60 | var ms = new MegaStruct({ 61 | byteVal: 100 62 | , int8Val: -100 63 | , int16Val: -1000 64 | , uint16Val: 1000 65 | , int32Val: -10000 66 | , uint32Val: 10000 67 | , floatVal: 1.25 68 | , doubleVal: 1000.0005 69 | , pointerVal: msTestPtr 70 | }) 71 | assert.equal(100, ms.byteVal) 72 | assert.equal(-100, ms.int8Val) 73 | assert.equal(-1000, ms.int16Val) 74 | assert.equal(1000, ms.uint16Val) 75 | assert.equal(-10000, ms.int32Val) 76 | assert.equal(10000, ms.uint32Val) 77 | assert.equal(1.25, ms.floatVal) 78 | assert.equal(1000.0005, ms.doubleVal) 79 | assert.equal(ms.pointerVal.address(), msTestPtr.address()) 80 | }) 81 | 82 | it('should allow Struct nesting', function () { 83 | 84 | var ChildStruct = Struct({ 85 | 'a': ref.types.int 86 | , 'b': ref.types.int 87 | }) 88 | var ParentStruct = Struct({ 89 | 'childA': ChildStruct 90 | , 'childB': ChildStruct 91 | }) 92 | 93 | var ps = new ParentStruct({ 94 | childA: { a: 100, b: 200 } 95 | , childB: { a: 300, b: 400 } 96 | }) 97 | 98 | assert.equal(100, ps.childA.a) 99 | assert.equal(200, ps.childA.b) 100 | assert.equal(300, ps.childB.a) 101 | assert.equal(400, ps.childB.b) 102 | }) 103 | 104 | describe('string type identifiers', function () { 105 | 106 | it('should work with string type identifiers', function () { 107 | var S = Struct({ 108 | 'int': 'int' 109 | , 'long': 'long' 110 | , 'string': 'string' 111 | }) 112 | 113 | assert.strictEqual(ref.types.int, S.fields.int.type) 114 | assert.strictEqual(ref.types.long, S.fields.long.type) 115 | assert.strictEqual(ref.types.CString, S.fields.string.type) 116 | }) 117 | 118 | it('should work as expected with "void *" as a type', function () { 119 | var S = Struct({ 120 | 'ptr1': 'void *', 121 | 'ptr2': 'void *' 122 | }) 123 | var s = new S() 124 | var b = new Buffer(1) 125 | s.ptr1 = ref.NULL 126 | s.ptr2 = b 127 | assert.equal(ref.NULL.address(), s.ptr1.address()) 128 | assert.equal(b.address(), s.ptr2.address()) 129 | }) 130 | 131 | }) 132 | 133 | describe('set()', function () { 134 | 135 | it('should work to set() an Object', function () { 136 | var Foo = Struct({ 137 | test1: ref.types.int, 138 | test2: ref.types.int 139 | }); 140 | 141 | var b = new Buffer(Foo.size * 2); 142 | 143 | Foo.set(b, Foo.size * 0, { 144 | test1: 7123, 145 | test2: -555 146 | }); 147 | 148 | var f = new Foo(b); 149 | assert.equal(f.test1, 7123); 150 | assert.equal(f.test2, -555); 151 | 152 | Foo.set(b, Foo.size * 1, { 153 | test1: 1234, 154 | test2: -1234 155 | }); 156 | 157 | f = new Foo(b.slice(Foo.size * 1)); 158 | assert.equal(f.test1, 1234); 159 | assert.equal(f.test2, -1234); 160 | }); 161 | 162 | it('should work to set() a Struct instance', function () { 163 | // see: https://github.com/TooTallNate/ref-struct/issues/11 164 | var Foo = Struct({ 165 | test1: ref.types.int, 166 | test2: ref.types.int 167 | }); 168 | 169 | var b = new Buffer(Foo.size * 2); 170 | 171 | Foo.set(b, Foo.size * 0, new Foo({ 172 | test1: 7123, 173 | test2: -555 174 | })); 175 | 176 | var f = new Foo(b); 177 | assert.equal(f.test1, 7123); 178 | assert.equal(f.test2, -555); 179 | 180 | Foo.set(b, Foo.size * 1, new Foo({ 181 | test1: 1234, 182 | test2: -1234 183 | })); 184 | 185 | f = new Foo(b.slice(Foo.size * 1)); 186 | assert.equal(f.test1, 1234); 187 | assert.equal(f.test2, -1234); 188 | }); 189 | 190 | }); 191 | 192 | describe('ref(), deref()', function () { 193 | 194 | it('should work to ref() and then deref() 1 level deep', function () { 195 | var S = Struct({ d: 'double' }) 196 | var s = new S({ d: Math.PI }) 197 | var sref = s.ref() 198 | assert(Buffer.isBuffer(sref)) 199 | var _s = sref.deref() 200 | assert(_s instanceof S) 201 | assert.equal(Math.PI, _s.d) 202 | }) 203 | 204 | }) 205 | 206 | describe('offsets and sizeofs', function () { 207 | 208 | function test (structType, testNumber) { 209 | describe('Struct test' + testNumber, function () { 210 | it('should have its `size` matching sizeof()', function () { 211 | var expectedSize = bindings['test' + testNumber + ' sizeof'] 212 | assert.equal(expectedSize, structType.size, 'test' + testNumber + 213 | ': sizeof(): expected ' + structType.size + ' to equal ' + expectedSize) 214 | }) 215 | it('should have its `alignment` matching __alignof__()', function () { 216 | var expectedAlignment = bindings['test' + testNumber + ' alignof'] 217 | assert.equal(expectedAlignment, structType.alignment, 'test' + testNumber + 218 | ': __alignof__(): expected ' + structType.alignment + ' to equal ' + expectedAlignment) 219 | }) 220 | Object.keys(structType.fields).forEach(function (name) { 221 | it('should have a matching offsetof() for "' + name + '"', function () { 222 | var expectedOffset = bindings['test' + testNumber + ' offsetof ' + name] 223 | var offset = structType.fields[name].offset 224 | assert.equal(expectedOffset, offset, 'test' + testNumber + 225 | ': offsetof(' + name + '): expected ' + offset + ' to equal ' + expectedOffset) 226 | }) 227 | }) 228 | }) 229 | } 230 | 231 | var test1 = Struct({ 232 | 'a': ref.types.int 233 | , 'b': ref.types.int 234 | , 'c': ref.types.double 235 | }) 236 | test(test1, 1) 237 | 238 | var test2 = Struct({ 239 | 'a': ref.types.int 240 | , 'b': ref.types.double 241 | , 'c': ref.types.int 242 | }) 243 | test(test2, 2) 244 | 245 | var test3 = Struct({ 246 | 'a': ref.types.double 247 | , 'b': ref.types.int 248 | , 'c': ref.types.int 249 | }) 250 | test(test3, 3) 251 | 252 | var test4 = Struct({ 253 | 'a': ref.types.double 254 | , 'b': ref.types.double 255 | , 'c': ref.types.int 256 | }) 257 | test(test4, 4) 258 | 259 | var test5 = Struct({ 260 | 'a': ref.types.int 261 | , 'b': ref.types.double 262 | , 'c': ref.types.double 263 | }) 264 | test(test5, 5) 265 | 266 | var test6 = Struct({ 267 | 'a': ref.types.char 268 | , 'b': ref.types.short 269 | , 'c': ref.types.int 270 | }) 271 | test(test6, 6) 272 | 273 | var test7 = Struct({ 274 | 'a': ref.types.int 275 | , 'b': ref.types.short 276 | , 'c': ref.types.char 277 | }) 278 | test(test7, 7) 279 | 280 | var test8 = Struct({ 281 | 'a': ref.types.int 282 | , 'b': ref.types.short 283 | , 'c': ref.types.char 284 | , 'd': ref.types.char 285 | }) 286 | test(test8, 8) 287 | 288 | var test9 = Struct({ 289 | 'a': ref.types.int 290 | , 'b': ref.types.short 291 | , 'c': ref.types.char 292 | , 'd': ref.types.char 293 | , 'e': ref.types.char 294 | }) 295 | test(test9, 9) 296 | 297 | var test10 = Struct({ 298 | 'a': test1 299 | , 'b': ref.types.char 300 | }) 301 | test(test10, 10) 302 | 303 | var test11 = Struct() 304 | test11.defineProperty('a', ref.types.size_t) 305 | test11.defineProperty('b', ref.types.ushort) 306 | test11.defineProperty('c', ref.types.ushort) 307 | // this struct contains an Array of `test11 *` structs, so `test11 **`... 308 | var test11_ptr_ptr = ref.refType(ref.refType(test11)) 309 | test11.defineProperty('d', test11_ptr_ptr) 310 | test(test11, 11) 311 | 312 | var test12 = Struct({ 313 | 'a': ref.refType(ref.types.char) 314 | , 'b': ref.types.int 315 | }) 316 | test(test12, 12) 317 | 318 | var test13 = Struct({ 319 | 'a': ref.types.char 320 | , 'b': ArrayType('char', 2) 321 | }) 322 | test(test13, 13) 323 | 324 | var test14 = Struct({ 325 | 'a': ref.types.char 326 | , 'b': ArrayType('char', 2) 327 | , 'c': ref.types.short 328 | , 'd': ref.types.char 329 | }) 330 | test(test14, 14) 331 | 332 | var test15 = Struct({ 333 | 'a': test1 334 | , 'b': test1 335 | }) 336 | test(test15, 15) 337 | 338 | var test16 = Struct({ 339 | 'a': ArrayType('double', 10) 340 | , 'b': ArrayType('char', 3) 341 | , 'c': ArrayType('int', 6) 342 | }) 343 | test(test16, 16) 344 | 345 | var test17 = Struct({ 346 | 'a': ArrayType('char', 3) 347 | }) 348 | test(test17, 17) 349 | 350 | var test18 = Struct({ 351 | 'a': ArrayType(test17, 100) 352 | }) 353 | test(test18, 18) 354 | 355 | // this example from libdespotify 356 | // see: https://github.com/TooTallNate/ref-struct/issues/1 357 | var STRING_LENGTH = 256; 358 | var test19 = Struct(); 359 | test19.defineProperty('has_meta_data', 'bool'); 360 | test19.defineProperty('playable', 'bool'); 361 | test19.defineProperty('geo_restricted', 'bool'); 362 | test19.defineProperty('track_id', ArrayType('uchar', 33)); 363 | test19.defineProperty('file_id', ArrayType('uchar', 41)); 364 | test19.defineProperty('file_bitrate', 'uint'); 365 | test19.defineProperty('album_id', ArrayType('uchar', 33)); 366 | test19.defineProperty('cover_id', ArrayType('uchar', 41)); 367 | test19.defineProperty('key','uchar *'); 368 | test19.defineProperty('allowed', 'char *'); 369 | test19.defineProperty('forbidden', 'char *'); 370 | test19.defineProperty('title', ArrayType('char', STRING_LENGTH)); 371 | test19.defineProperty('artist', 'void *'); 372 | test19.defineProperty('album', ArrayType('char', STRING_LENGTH)); 373 | test19.defineProperty('length', 'int'); 374 | test19.defineProperty('tracknumber', 'int'); 375 | test19.defineProperty('year', 'int'); 376 | test19.defineProperty('popularity', 'float'); 377 | test19.defineProperty('next', ref.refType(test19)); 378 | test(test19, 19); 379 | 380 | }) 381 | 382 | describe('packed struct', function () { 383 | 384 | it('with-padding/no-padding struct', function () { 385 | var np = Struct({ a: 'char', p: ref.refType('void') }, {packed: true}) 386 | assert.equal(bindings['test20 sizeof'], np.size) 387 | assert.equal(bindings['test20 alignof'], np.alignment) 388 | 389 | var wp = Struct({ a: 'char', p: ref.refType('void') }) 390 | assert.equal(bindings['test21 sizeof'], wp.size) 391 | assert.equal(bindings['test21 alignof'], wp.alignment) 392 | }) 393 | 394 | }) 395 | 396 | }) 397 | -------------------------------------------------------------------------------- /test/struct_tests.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include "nan.h" 3 | 4 | #ifdef _WIN32 5 | #define __alignof__ __alignof 6 | #endif 7 | 8 | using namespace node; 9 | 10 | namespace { 11 | 12 | typedef struct _test1 { 13 | int a; 14 | int b; 15 | double c; 16 | } test1; 17 | 18 | typedef struct _test2 { 19 | int a; 20 | double b; 21 | int c; 22 | } test2; 23 | 24 | typedef struct _test3 { 25 | double a; 26 | int b; 27 | int c; 28 | } test3; 29 | 30 | typedef struct _test4 { 31 | double a; 32 | double b; 33 | int c; 34 | } test4; 35 | 36 | typedef struct _test5 { 37 | int a; 38 | double b; 39 | double c; 40 | } test5; 41 | 42 | typedef struct _test6 { 43 | char a; 44 | short b; 45 | int c; 46 | } test6; 47 | 48 | typedef struct _test7 { 49 | int a; 50 | short b; 51 | char c; 52 | } test7; 53 | 54 | typedef struct _test8 { 55 | int a; 56 | short b; 57 | char c; 58 | char d; 59 | } test8; 60 | 61 | typedef struct _test9 { 62 | int a; 63 | short b; 64 | char c; 65 | char d; 66 | char e; 67 | } test9; 68 | 69 | typedef struct _test10 { 70 | test1 a; 71 | char b; 72 | } test10; 73 | 74 | // this one simulates the `ffi_type` struct 75 | typedef struct _test11 { 76 | size_t a; 77 | unsigned short b; 78 | unsigned short c; 79 | struct _test11 **d; 80 | } test11; 81 | 82 | typedef struct _test12 { 83 | char *a; 84 | int b; 85 | } test12; 86 | 87 | typedef struct _test13 { 88 | char a; 89 | char b[2]; 90 | } test13; 91 | 92 | typedef struct _test14 { 93 | char a; 94 | char b[2]; 95 | short c; 96 | char d; 97 | } test14; 98 | 99 | typedef struct _test15 { 100 | test1 a; 101 | test1 b; 102 | } test15; 103 | 104 | typedef struct _test16 { 105 | double a[10]; 106 | char b[3]; 107 | int c[6]; 108 | } test16; 109 | 110 | typedef struct _test17 { 111 | char a[3]; 112 | } test17; 113 | 114 | typedef struct _test18 { 115 | test17 a[100]; 116 | } test18; 117 | 118 | /* test19 example is from libdespotify 119 | * See: https://github.com/TooTallNate/ref-struct/issues/1 120 | */ 121 | 122 | #define STRING_LENGTH 256 123 | typedef struct _test19 { 124 | bool has_meta_data; 125 | bool playable; 126 | bool geo_restricted; 127 | unsigned char track_id[33]; 128 | unsigned char file_id[41]; 129 | unsigned int file_bitrate; 130 | unsigned char album_id[33]; 131 | unsigned char cover_id[41]; 132 | unsigned char *key; 133 | 134 | char *allowed; 135 | char *forbidden; 136 | 137 | char title[STRING_LENGTH]; 138 | struct artist* artist; 139 | char album[STRING_LENGTH]; 140 | int length; 141 | int tracknumber; 142 | int year; 143 | float popularity; 144 | struct _test19 *next; /* in case of multiple tracks 145 | in an album or playlist struct */ 146 | } test19; 147 | 148 | #pragma pack(1) 149 | typedef struct _test20 { 150 | char a; 151 | void *p; 152 | } test20; 153 | 154 | #pragma pack() 155 | typedef struct _test21 { 156 | char a; 157 | void *p; 158 | } test21; 159 | 160 | void Initialize(v8::Handle target) { 161 | Nan::HandleScope scope; 162 | 163 | target->Set(Nan::New("test1 sizeof").ToLocalChecked(), Nan::New(sizeof(test1))); 164 | target->Set(Nan::New("test1 alignof").ToLocalChecked(), Nan::New(__alignof__(test1))); 165 | target->Set(Nan::New("test1 offsetof a").ToLocalChecked(), Nan::New(offsetof(test1, a))); 166 | target->Set(Nan::New("test1 offsetof b").ToLocalChecked(), Nan::New(offsetof(test1, b))); 167 | target->Set(Nan::New("test1 offsetof c").ToLocalChecked(), Nan::New(offsetof(test1, c))); 168 | 169 | target->Set(Nan::New("test2 sizeof").ToLocalChecked(), Nan::New(sizeof(test2))); 170 | target->Set(Nan::New("test2 alignof").ToLocalChecked(), Nan::New(__alignof__(test2))); 171 | target->Set(Nan::New("test2 offsetof a").ToLocalChecked(), Nan::New(offsetof(test2, a))); 172 | target->Set(Nan::New("test2 offsetof b").ToLocalChecked(), Nan::New(offsetof(test2, b))); 173 | target->Set(Nan::New("test2 offsetof c").ToLocalChecked(), Nan::New(offsetof(test2, c))); 174 | 175 | target->Set(Nan::New("test3 sizeof").ToLocalChecked(), Nan::New(sizeof(test3))); 176 | target->Set(Nan::New("test3 alignof").ToLocalChecked(), Nan::New(__alignof__(test3))); 177 | target->Set(Nan::New("test3 offsetof a").ToLocalChecked(), Nan::New(offsetof(test3, a))); 178 | target->Set(Nan::New("test3 offsetof b").ToLocalChecked(), Nan::New(offsetof(test3, b))); 179 | target->Set(Nan::New("test3 offsetof c").ToLocalChecked(), Nan::New(offsetof(test3, c))); 180 | 181 | target->Set(Nan::New("test4 sizeof").ToLocalChecked(), Nan::New(sizeof(test4))); 182 | target->Set(Nan::New("test4 alignof").ToLocalChecked(), Nan::New(__alignof__(test4))); 183 | target->Set(Nan::New("test4 offsetof a").ToLocalChecked(), Nan::New(offsetof(test4, a))); 184 | target->Set(Nan::New("test4 offsetof b").ToLocalChecked(), Nan::New(offsetof(test4, b))); 185 | target->Set(Nan::New("test4 offsetof c").ToLocalChecked(), Nan::New(offsetof(test4, c))); 186 | 187 | target->Set(Nan::New("test5 sizeof").ToLocalChecked(), Nan::New(sizeof(test5))); 188 | target->Set(Nan::New("test5 alignof").ToLocalChecked(), Nan::New(__alignof__(test5))); 189 | target->Set(Nan::New("test5 offsetof a").ToLocalChecked(), Nan::New(offsetof(test5, a))); 190 | target->Set(Nan::New("test5 offsetof b").ToLocalChecked(), Nan::New(offsetof(test5, b))); 191 | target->Set(Nan::New("test5 offsetof c").ToLocalChecked(), Nan::New(offsetof(test5, c))); 192 | 193 | target->Set(Nan::New("test6 sizeof").ToLocalChecked(), Nan::New(sizeof(test6))); 194 | target->Set(Nan::New("test6 alignof").ToLocalChecked(), Nan::New(__alignof__(test6))); 195 | target->Set(Nan::New("test6 offsetof a").ToLocalChecked(), Nan::New(offsetof(test6, a))); 196 | target->Set(Nan::New("test6 offsetof b").ToLocalChecked(), Nan::New(offsetof(test6, b))); 197 | target->Set(Nan::New("test6 offsetof c").ToLocalChecked(), Nan::New(offsetof(test6, c))); 198 | 199 | target->Set(Nan::New("test7 sizeof").ToLocalChecked(), Nan::New(sizeof(test7))); 200 | target->Set(Nan::New("test7 alignof").ToLocalChecked(), Nan::New(__alignof__(test7))); 201 | target->Set(Nan::New("test7 offsetof a").ToLocalChecked(), Nan::New(offsetof(test7, a))); 202 | target->Set(Nan::New("test7 offsetof b").ToLocalChecked(), Nan::New(offsetof(test7, b))); 203 | target->Set(Nan::New("test7 offsetof c").ToLocalChecked(), Nan::New(offsetof(test7, c))); 204 | 205 | target->Set(Nan::New("test8 sizeof").ToLocalChecked(), Nan::New(sizeof(test8))); 206 | target->Set(Nan::New("test8 alignof").ToLocalChecked(), Nan::New(__alignof__(test8))); 207 | target->Set(Nan::New("test8 offsetof a").ToLocalChecked(), Nan::New(offsetof(test8, a))); 208 | target->Set(Nan::New("test8 offsetof b").ToLocalChecked(), Nan::New(offsetof(test8, b))); 209 | target->Set(Nan::New("test8 offsetof c").ToLocalChecked(), Nan::New(offsetof(test8, c))); 210 | target->Set(Nan::New("test8 offsetof d").ToLocalChecked(), Nan::New(offsetof(test8, d))); 211 | 212 | target->Set(Nan::New("test9 sizeof").ToLocalChecked(), Nan::New(sizeof(test9))); 213 | target->Set(Nan::New("test9 alignof").ToLocalChecked(), Nan::New(__alignof__(test9))); 214 | target->Set(Nan::New("test9 offsetof a").ToLocalChecked(), Nan::New(offsetof(test9, a))); 215 | target->Set(Nan::New("test9 offsetof b").ToLocalChecked(), Nan::New(offsetof(test9, b))); 216 | target->Set(Nan::New("test9 offsetof c").ToLocalChecked(), Nan::New(offsetof(test9, c))); 217 | target->Set(Nan::New("test9 offsetof d").ToLocalChecked(), Nan::New(offsetof(test9, d))); 218 | target->Set(Nan::New("test9 offsetof e").ToLocalChecked(), Nan::New(offsetof(test9, e))); 219 | 220 | target->Set(Nan::New("test10 sizeof").ToLocalChecked(), Nan::New(sizeof(test10))); 221 | target->Set(Nan::New("test10 alignof").ToLocalChecked(), Nan::New(__alignof__(test10))); 222 | target->Set(Nan::New("test10 offsetof a").ToLocalChecked(), Nan::New(offsetof(test10, a))); 223 | target->Set(Nan::New("test10 offsetof b").ToLocalChecked(), Nan::New(offsetof(test10, b))); 224 | 225 | target->Set(Nan::New("test11 sizeof").ToLocalChecked(), Nan::New(sizeof(test11))); 226 | target->Set(Nan::New("test11 alignof").ToLocalChecked(), Nan::New(__alignof__(test11))); 227 | target->Set(Nan::New("test11 offsetof a").ToLocalChecked(), Nan::New(offsetof(test11, a))); 228 | target->Set(Nan::New("test11 offsetof b").ToLocalChecked(), Nan::New(offsetof(test11, b))); 229 | target->Set(Nan::New("test11 offsetof c").ToLocalChecked(), Nan::New(offsetof(test11, c))); 230 | target->Set(Nan::New("test11 offsetof d").ToLocalChecked(), Nan::New(offsetof(test11, d))); 231 | 232 | target->Set(Nan::New("test12 sizeof").ToLocalChecked(), Nan::New(sizeof(test12))); 233 | target->Set(Nan::New("test12 alignof").ToLocalChecked(), Nan::New(__alignof__(test12))); 234 | target->Set(Nan::New("test12 offsetof a").ToLocalChecked(), Nan::New(offsetof(test12, a))); 235 | target->Set(Nan::New("test12 offsetof b").ToLocalChecked(), Nan::New(offsetof(test12, b))); 236 | 237 | target->Set(Nan::New("test13 sizeof").ToLocalChecked(), Nan::New(sizeof(test13))); 238 | target->Set(Nan::New("test13 alignof").ToLocalChecked(), Nan::New(__alignof__(test13))); 239 | target->Set(Nan::New("test13 offsetof a").ToLocalChecked(), Nan::New(offsetof(test13, a))); 240 | target->Set(Nan::New("test13 offsetof b").ToLocalChecked(), Nan::New(offsetof(test13, b))); 241 | 242 | target->Set(Nan::New("test14 sizeof").ToLocalChecked(), Nan::New(sizeof(test14))); 243 | target->Set(Nan::New("test14 alignof").ToLocalChecked(), Nan::New(__alignof__(test14))); 244 | target->Set(Nan::New("test14 offsetof a").ToLocalChecked(), Nan::New(offsetof(test14, a))); 245 | target->Set(Nan::New("test14 offsetof b").ToLocalChecked(), Nan::New(offsetof(test14, b))); 246 | target->Set(Nan::New("test14 offsetof c").ToLocalChecked(), Nan::New(offsetof(test14, c))); 247 | target->Set(Nan::New("test14 offsetof d").ToLocalChecked(), Nan::New(offsetof(test14, d))); 248 | 249 | target->Set(Nan::New("test15 sizeof").ToLocalChecked(), Nan::New(sizeof(test15))); 250 | target->Set(Nan::New("test15 alignof").ToLocalChecked(), Nan::New(__alignof__(test15))); 251 | target->Set(Nan::New("test15 offsetof a").ToLocalChecked(), Nan::New(offsetof(test15, a))); 252 | target->Set(Nan::New("test15 offsetof b").ToLocalChecked(), Nan::New(offsetof(test15, b))); 253 | 254 | target->Set(Nan::New("test16 sizeof").ToLocalChecked(), Nan::New(sizeof(test16))); 255 | target->Set(Nan::New("test16 alignof").ToLocalChecked(), Nan::New(__alignof__(test16))); 256 | target->Set(Nan::New("test16 offsetof a").ToLocalChecked(), Nan::New(offsetof(test16, a))); 257 | target->Set(Nan::New("test16 offsetof b").ToLocalChecked(), Nan::New(offsetof(test16, b))); 258 | target->Set(Nan::New("test16 offsetof c").ToLocalChecked(), Nan::New(offsetof(test16, c))); 259 | 260 | target->Set(Nan::New("test17 sizeof").ToLocalChecked(), Nan::New(sizeof(test17))); 261 | target->Set(Nan::New("test17 alignof").ToLocalChecked(), Nan::New(__alignof__(test17))); 262 | target->Set(Nan::New("test17 offsetof a").ToLocalChecked(), Nan::New(offsetof(test17, a))); 263 | 264 | target->Set(Nan::New("test18 sizeof").ToLocalChecked(), Nan::New(sizeof(test18))); 265 | target->Set(Nan::New("test18 alignof").ToLocalChecked(), Nan::New(__alignof__(test18))); 266 | target->Set(Nan::New("test18 offsetof a").ToLocalChecked(), Nan::New(offsetof(test18, a))); 267 | 268 | target->Set(Nan::New("test19 sizeof").ToLocalChecked(), Nan::New(sizeof(test19))); 269 | target->Set(Nan::New("test19 alignof").ToLocalChecked(), Nan::New(__alignof__(test19))); 270 | target->Set(Nan::New("test19 offsetof has_meta_data").ToLocalChecked(), Nan::New(offsetof(test19, has_meta_data))); 271 | target->Set(Nan::New("test19 offsetof playable").ToLocalChecked(), Nan::New(offsetof(test19, playable))); 272 | target->Set(Nan::New("test19 offsetof geo_restricted").ToLocalChecked(), Nan::New(offsetof(test19, geo_restricted))); 273 | target->Set(Nan::New("test19 offsetof track_id").ToLocalChecked(), Nan::New(offsetof(test19, track_id))); 274 | target->Set(Nan::New("test19 offsetof file_id").ToLocalChecked(), Nan::New(offsetof(test19, file_id))); 275 | target->Set(Nan::New("test19 offsetof file_bitrate").ToLocalChecked(), Nan::New(offsetof(test19, file_bitrate))); 276 | target->Set(Nan::New("test19 offsetof album_id").ToLocalChecked(), Nan::New(offsetof(test19, album_id))); 277 | target->Set(Nan::New("test19 offsetof cover_id").ToLocalChecked(), Nan::New(offsetof(test19, cover_id))); 278 | target->Set(Nan::New("test19 offsetof key").ToLocalChecked(), Nan::New(offsetof(test19, key))); 279 | target->Set(Nan::New("test19 offsetof allowed").ToLocalChecked(), Nan::New(offsetof(test19, allowed))); 280 | target->Set(Nan::New("test19 offsetof forbidden").ToLocalChecked(), Nan::New(offsetof(test19, forbidden))); 281 | target->Set(Nan::New("test19 offsetof title").ToLocalChecked(), Nan::New(offsetof(test19, title))); 282 | target->Set(Nan::New("test19 offsetof artist").ToLocalChecked(), Nan::New(offsetof(test19, artist))); 283 | target->Set(Nan::New("test19 offsetof album").ToLocalChecked(), Nan::New(offsetof(test19, album))); 284 | target->Set(Nan::New("test19 offsetof length").ToLocalChecked(), Nan::New(offsetof(test19, length))); 285 | target->Set(Nan::New("test19 offsetof tracknumber").ToLocalChecked(), Nan::New(offsetof(test19, tracknumber))); 286 | target->Set(Nan::New("test19 offsetof year").ToLocalChecked(), Nan::New(offsetof(test19, year))); 287 | target->Set(Nan::New("test19 offsetof popularity").ToLocalChecked(), Nan::New(offsetof(test19, popularity))); 288 | target->Set(Nan::New("test19 offsetof next").ToLocalChecked(), Nan::New(offsetof(test19, next))); 289 | 290 | target->Set(Nan::New("test20 sizeof").ToLocalChecked(), Nan::New(sizeof(test20))); 291 | target->Set(Nan::New("test20 alignof").ToLocalChecked(), Nan::New(__alignof__(test20))); 292 | 293 | target->Set(Nan::New("test21 sizeof").ToLocalChecked(), Nan::New(sizeof(test21))); 294 | target->Set(Nan::New("test21 alignof").ToLocalChecked(), Nan::New(__alignof__(test21))); 295 | } 296 | 297 | } // anonymous namespace 298 | 299 | NODE_MODULE(struct_tests, Initialize); 300 | --------------------------------------------------------------------------------