/ CData

Cdata in Jsi manipulates struct data using one of 2 interfaces:

  • The C-API interface for generating C code, and
  • The javascript interface which is described here-in.

Unlike the C-API, JS-defined structs are:

  1. invisible in sub-interps,
  2. incompatible with real structs due to packing differences, and
  3. not as convenient for C-extensions.

Nevertheless, once defined both use the same commands for accessing data.


A basic JS use of CData is:

CEnum.define('Fruit', 'apple,banana,orange,grape=9');
CStruct.define('Bee', 'int s:4; int r:3; int t=8; Fruit k;');
var bee  = new CData('Bee');
bee.get(null, 't');
bee.set(null, 't', 4);

Note: the above is extracted from test cdatatest.jsi.


There are 3 forms for enum definitions.

The simplest is the single-line form as above, which is split on comma:

CEnum.define('Fruit', 'apple,banana,orange,grape=9');

There is a multi-line form which is split on newlines, with comments extracted as help:

CEnum.define('Vegetable', '
    corn=0, // My favorite
    peas=2, // Your favorite

And there is an object form:

CEnum.define({name:'Herd'}, [
    {name:'goat', value:3, help:'set a value'},

Here are some test output from cdatatest.jsi:

CEnum.names() ==> [ "Fruit", "Herd", "Vegetable" ]
CEnum.names('Fruit') ==> [ "apple", "banana", "orange", "grape" ]
CEnum.conf('Fruit') ==> { flags:0, help:null, idx:4, name:"Fruit" }
CEnum.conf('Fruit', 'idx') ==> 4
CEnum.find('Fruit', 1) ==> banana
CEnum.fieldconf('Fruit', 'banana') ==> { flags:0, help:null, idx:1, name:"banana", value:1 }
CEnum.fieldconf('Fruit', 'banana', 'value') ==> 1
CEnum.value('Fruit', 'apple') ==> 0
CEnum.get('Fruit') ==> { fields:[ { name:"apple", value:0 }, { name:"banana", value:1 }, { name:"orange", value:2 }, { name:"grape", value:9 } ], name:"Fruit" }


As with CEnum, there are 3 forms of struct definitions.

The simplest is the single-line form as above, which is split on semicolon:

CStruct.define('Bee', 'int s:4; int r:3; int t=8; Fruit k;');

The multi-line form is split on newlines, with comments extracted as help:

CStruct.define('Pest', '
    int x=3;    // int field.
    Bee b;      // A sub-struct
    int y=5;

And there is an object form:

CStruct.define({name:'Bkey', help:'Struct to use for a key'}, [
        {name:'a', type:'int', help:'first key field'},
        {name:'b', type:'int', help:'second key field'}]

The type of a struct field is one of:

  • a base type (see below)
  • a struct
  • an array of base type or struct
  • an enum
  • a bitfield of an int type or enum
  • a bitset of an enum (name ends in @)

Struct data is initialized to zero by default, but individual fields can be given a simple value using =.

Here are some test output from cdatatest.jsi:

CStruct.conf('Bee') ==> { crc:0, flags:0, help:null, idx:4, name:"Bee", size:6, ssig:0, value:10 }
CStruct.conf('Bee','name') ==> Bee
CStruct.names() ==> [ "Bkey", "Pest", "Bee", "Flower" ]
CStruct.names('Bee') ==> []
CStruct.fieldconf('Bee', 't') ==> { arrSize:0, bits:0, boffset:7, flags:1, help:null, idx:2, info:null, init:8, name:"t", offset:1, size:4, type:"int" }
CStruct.fieldconf('Bee', 's', 'bits') ==> 4
CStruct.get('Bee') ==> { fields:[ { bitoffs:0, bitsize:4, id:"int", isbit:0, label:"", name:"s", offset:0, size:4 }, { bitoffs:4, bitsize:3, id:"int", isbit:0, label:"", name:"r", offset:0, size:4 }, { bitoffs:7, bitsize:0, id:"int", isbit:0, label:"", name:"t", offset:1, size:4 }, { bitoffs:39, bitsize:0, id:"Fruit", isbit:0, label:"", name:"k", offset:5, size:1 } ], name:"Bee", size:6 }


CType is simply available to query available types (usable as struct fields).

Here are some test output from cdatatest.jsi:

CType.names().sort() ==> [ "ARRAY", "BOOL", "CUSTOM", "DOUBLE", "DSTRING", "FLOAT", "FUNC", "INT", "INT16", "INT32", "INT64", "INT8", "INTPTR_T", "LDOUBLE", "LONG", "NUMBER", "OBJ", "REGEXP", "SHORT", "SIZE_T", "SSIZE_T", "STRBUF", "STRING", "STRKEY", "TIME_D", "TIME_T", "TIME_W", "UINT", "UINT16", "UINT32", "UINT64", "UINT8", "UINTPTR_T", "ULONG", "USEROBJ", "USHORT", "VALUE", "VAR" ]
CType.names(true).sort() ==> [ "Bee", "Bkey", "Flower", "Fruit", "Herd", "Jsi_DString", "Jsi_Number", "Jsi_Strbuf", "Jsi_Value*", "Pest", "Vegetable", "bool", "const char*", "double", "float", "int", "int16_t", "int32_t", "int64_t", "int8_t", "intptr_t", "ldouble", "long", "short", "size_t", "ssize_t", "time_d", "time_t", "time_w", "uint", "uint16_t", "uint32_t", "uint64_t", "uint8_t", "uintptr_t", "ulong", "ushort" ]
CType.conf('INT') ==> { cName:"int", flags:0, fmt:"d", help:"Integer", idName:"INT", size:4, user:0, xfmt:"#x" }
CType.conf('INT','flags') ==> 0


A basic JS use of CData to create and manipulate a single struct is:

var alpha  = new CData('Bee');
alpha.get(null, 't');
alpha.set(null, 't', 4);

Data is accessed with set/get/incr:

alpha.get(null) ==> { k:"apple", r:0, s:0, t:8 }
alpha.get(null, 't') ==> 8
alpha.set(null, 't', 4) ==> undefined
alpha.incr(null, 't', 1) ==> 5
n=alpha.get(null, 't') ==> 5

As above there is also an object form:

var bees   = new CData({structName:'Bee', arrSize:10, help:'An array of bees'});

The string form is the simplest way to create maps and hashes of structs.

var alpha, beta, tree, tree2, tree3, hash, hash2, hash3, pest, flower, n;
beta   = new CData('Bee[10]');      // Array
tree   = new CData('Bee{}');        // Map with string key
tree2  = new CData('Bee{0}');       // Map with number key
tree3  = new CData('Bee{@Bkey}');   // Map with struct key
hash   = new CData('Bee{#}');       // Hash with string key
hash2  = new CData('Bee{#0}');      // Hash with number key
hash3  = new CData('Bee{#@Bkey}');  // Hash with struct key

which are indexed with a non-null key:

beta.set(0, 't', 2);
tree.set('X', 't', 2);
hash.set('X', 't', 2);

Struct keys are also supported:

bkey={a:1,b:2} ==> { a:1, b:2 }
tree3.set(bkey, 't', 2) ==> undefined
tree3.get(bkey, 't') ==> 2


database definitions may be extracted from struct definitions and used with Sqlite.

db = new Sqlite('/tmp/bees.db') ==> "#Sqlite_1"
schema = CStruct.schema('Bee') ==> 
  s int
 ,r int
 ,t INT
 ,k TEXT
  -- MD5=2c2573332fca5f166b7272366bd888b0
);') ==> undefined
db.query('INSERT INTO Bee %s',{cdata:'beta'}) ==> 10
db.query('SELECT %s FROM Bee',{cdata:'beta'}) ==> 10