Jsctypes/api: Difference between revisions

Jump to navigation Jump to search
1,171 bytes added ,  29 September 2009
Line 102: Line 102:
A ''type'' maps JS values to C/C++ values and vice versa. They're used when declaring functions. They can also be used to create and populate C/C++ data structures entirely from JS.
A ''type'' maps JS values to C/C++ values and vice versa. They're used when declaring functions. They can also be used to create and populate C/C++ data structures entirely from JS.


=== The types provided by ctypes ===
=== Built-in types ===


ctypes provides the following builtin types:
ctypes provides the following types:


:'''<code>ctypes.int8_t, uint8_t, int16_t, uint16_t, int32_t, uint32_t, int64_t, uint64_t, float32_t, float64_t</code>''' - Primitive numeric types that behave the same way on all platforms (with the usual caveat that every platform has slightly different floating-point behavior, in corner cases, and there's nothing we can realistically do about it).
:'''<code>ctypes.int8_t, uint8_t, int16_t, uint16_t, int32_t, uint32_t, int64_t, uint64_t, float32_t, float64_t</code>''' - Primitive numeric types that behave the same way on all platforms (with the usual caveat that every platform has slightly different floating-point behavior, in corner cases, and there's a limit to what we can realistically do about it).
 
:'''<code>ctypes.size_t, ssize_t, intptr_t, uintptr_t</code>''' - Primitive types whose size depends on the platform. These types do not autoconvert to JavaScript numbers because on some platforms, there are values of these types that cannot be precisely represented as a JS number.
 
:''(Open issue: Operator overloading will eventually come to JS. JS will likely have a 64-bit integer object type someday. The above non-autoconverting behavior prevents us from later autoconverting these CTypes to 64-bit values.)''


:'''<code>ctypes.bool, short, unsigned_short, int, unsigned, unsigned_int, long, unsigned_long, float, double</code>''' - Types that behave like the corresponding C types. Some or all of these might be aliases for the primitive types listed above. As in C, <code>unsigned</code> is always an alias for <code>unsigned_int</code>.
:'''<code>ctypes.bool, short, unsigned_short, int, unsigned, unsigned_int, long, unsigned_long, float, double</code>''' - Types that behave like the corresponding C types. Some or all of these might be aliases for the primitive types listed above. As in C, <code>unsigned</code> is always an alias for <code>unsigned_int</code>.
:''(Open issue: Does <code>long</code> autoconvert to a JS number?)''


:'''<code>ctypes.char, ctypes.signed_char, ctypes.unsigned_char</code>''' - Character types that behave like the corresponding C types. (These are distinct from <code>int8_t</code> and <code>uint8_t</code> in details of conversion behavior. For example, js-ctypes autoconverts between C characters and one-character JavaScript strings.)
:'''<code>ctypes.char, ctypes.signed_char, ctypes.unsigned_char</code>''' - Character types that behave like the corresponding C types. (These are distinct from <code>int8_t</code> and <code>uint8_t</code> in details of conversion behavior. For example, js-ctypes autoconverts between C characters and one-character JavaScript strings.)
Line 182: Line 188:
Minutiae:
Minutiae:


:The <nowiki>[[Class]]</nowiki> of a ctypes type is <code>"Function"</code>. ''(Open issue: Subject to possible implementation difficulties.)''
:'''<code>ctypes.CType</code>''' is the abstract-base-class constructor of all js-ctypes types. If called, it throws a <code>TypeError</code>. (This is exposed in order to expose <code>ctypes.CType.prototype</code>.)
 
:The <nowiki>[[Class]]</nowiki> of a ctypes type is <code>"CType"</code>.
 
:The <nowiki>[[Class]]</nowiki> of the type constructors <code>ctypes.{C,Array,Struct,Pointer}Type</code> is <code>"Function"</code>.


:Every ctypes type has a read-only, permanent <code>.prototype</code> property.  The type-constructors <code>ctypes.{Pointer,Struct,Array,}Type</code> each have a read-only, permanent <code>.prototype</code> property as well.
:Every <code>CType</code> has a read-only, permanent <code>.prototype</code> property.  The type-constructors <code>ctypes.{C,Pointer,Struct,Array}Type</code> each have a read-only, permanent <code>.prototype</code> property as well.


:Types have a hierarchy of prototype objects. The prototype of <code>ctypes.Type.prototype</code> is <code>Function.prototype</code>. The prototype of <code>ctypes.{Array,Struct,Pointer}Type.prototype</code> and of all the builtin types except for the string types and <code>ctypes.voidptr_t</code> is <code>ctypes.Type.prototype</code>. The prototype of an array type is <code>ctypes.ArrayType.prototype</code>. The prototype of a struct type is <code>ctypes.StructType.prototype</code>. The prototype of a string type or pointer type is <code>ctypes.PointerType.prototype</code>.
:Types have a hierarchy of prototype objects. The prototype of <code>ctypes.CType.prototype</code> is <code>Function.prototype</code>. The prototype of <code>ctypes.{Array,Struct,Pointer}Type.prototype</code> and of all the builtin types except for the string types and <code>ctypes.voidptr_t</code> is <code>ctypes.CType.prototype</code>. The prototype of an array type is <code>ctypes.ArrayType.prototype</code>. The prototype of a struct type is <code>ctypes.StructType.prototype</code>. The prototype of a string type or pointer type is <code>ctypes.PointerType.prototype</code>.


:Every ctypes type ''t'' has <code>''t''.prototype.constructor === ''t''</code>; that is, its <code>.prototype</code> has a read-only, permanent, own <code>.constructor</code> property that refers to the type. Also:
:Every <code>CType</code> ''t'' has <code>''t''.prototype.constructor === ''t''</code>; that is, its <code>.prototype</code> has a read-only, permanent, own <code>.constructor</code> property that refers to the type. The same is true of the four type constructors <code>ctypes.{C,Array,Struct,Pointer}Type</code>.
:<code>ctypes.Type.prototype.constructor === ctypes.Type</code>
:<code>ctypes.ArrayType.prototype.constructor === ctypes.ArrayType</code>
:<code>ctypes.StructType.prototype.constructor === ctypes.StructType</code>
:<code>ctypes.PointerType.prototype.constructor === ctypes.PointerType</code>


=== Calling types ===
=== Calling types ===


js-ctypes types are JavaScript constructors. That is, they are functions, and they can be called in various different ways.  (js-ctypes buffers and references are to be described in later sections.)
<code>CType</code>s are JavaScript constructors. That is, they are functions, and they can be called in various different ways.  (<code>CData</code> objects are described in a separate section, below.)
 
:'''<code>new ''t''</code>''' or '''<code>new ''t''()</code>''' or '''<code>''t''()</code>''' - Create a new <code>CData</code> object of type ''t''.


:'''<code>new ''t''</code>''' or '''<code>new ''t''()</code>''' - Without arguments, these allocate a new buffer of <code>''t''.size</code> bytes, populate it with zeroes, and return a new ctypes reference to the complete object in that buffer.
:Without arguments, these allocate a new buffer of <code>''t''.size</code> bytes, populate it with zeroes, and return a new <code>CData</code> object referring to the complete object in that buffer.


:If <code>''t''.size</code> is <code>undefined</code>, this throws a <code>TypeError</code>.
:If <code>''t''.size</code> is <code>undefined</code>, this throws a <code>TypeError</code>.


:'''<code>''t''()</code>''' - Return <code>ConvertToJS(new t)</code>. (<code>ConvertToJS</code> is defined below. The result is that <code>ctypes.bool() === false</code>, for number types <code>''t''() === 0</code>, for character types <code>''t''() === '\0'</code>, and for string and pointer types <code>''t''() === null</code> on platforms where the null pointer is all zeroes. For all other types the result is the same as <code>new ''t''</code>.)
:'''<code>new ''t''(''val'')</code>''' or '''<code>''t''(''val'')</code> - Convert ''val'' to type ''t'' according to the explicit conversion rules below, throwing a <code>TypeError</code> if the conversion is impossible. Allocate a new buffer of <code>''t''.size</code> bytes, populated with the converted value. Return a new <code>CData</code> object of type ''t'' referring to the complete object in that buffer. (When ''val'' is a <code>CData</code> object of type ''t'', the behavior is like <code>malloc</code> followed by <code>memcpy</code>.)


:'''<code>new ''t''(''val'')</code>''' - Convert ''val'' to type ''t'' according to the explicit conversion rules below, throwing a <code>TypeError</code> if the conversion is impossible. Create a new buffer and reference as above, populating the new buffer with the converted value instead of zeroing it out. (When ''val'' is a reference of type ''t'', the behavior is like <code>malloc</code> followed by <code>memcpy</code>.)
:As a special case, if ''t'' is an array type of unspecified length and <code>typeof ''val''</code> is <code>'number'</code> and ''val'' is a nonnegative integer, allocate a new buffer of size <code>''val'' * ''t''.elementType.size</code>. Populate it with zeroes. Return a <code>CData</code> object of type ''t'' referring to the new array.


:As a special case, if ''t'' is an array type of unspecified length and ''val'' is a nonnegative integer, allocate a new buffer of size <code>''val'' * ''t''.elementType.size</code>. Populate it with zeroes. Return a reference to the new array.
== CData objects ==


:'''<code>''t''(''val'')</code>''' - Return <code>ConvertToJS(new ''t''(''val''))</code>.
A <code>CData</code> object represents a C/C++ value located in memory. The address of the C/C++ value can be taken, and it can be assigned to.


== References ==
It is possible for multiple <code>CData</code> objects to refer to the same memory. (In this way they are sort of like C++ references, but the syntax is quite different.)
 
js-ctypes references are like C++ references: they have a type, they refer to a C++ value, their address can be taken, and they can be assigned to. However, the JavaScript syntax is very different from the C++ syntax.


''(TODO)''
''(TODO)''


:'''<code>''ref''.assign(''val'')</code>''' - Convert ''val'' to the type of ''ref'' using the implicit conversion rules. Store the converted value in the buffer location referred to by ''ref''.
:'''<code>''cdata''.assign(''val'')</code>''' - Convert ''val'' to the type of ''cdata'' using the implicit conversion rules. Store the converted value in the buffer location referred to by ''cdata''.


:'''<code>''ref''.constructor</code>''' - Read-only. The type of the reference. ''(Implementation note: The prototype of ''ref'' is an object that has a read-only <code>constructor</code> property, as detailed under "minutiae".)''
:'''<code>''cdata''.constructor</code>''' - Read-only. The type of ''cdata''. ''(Implementation note: The prototype of ''cdata'' is an object that has a read-only <code>constructor</code> property, as detailed under "minutiae".)''


Struct references have getters and setters for each struct member:
<code>CData</code> objects of struct types have getters and setters for each struct member:


:'''<code>''cstruct''.''member''</code>''' - Let ''R'' be a reference to the struct member. Return <code>ConvertToJS(''R'')</code>.
:'''<code>''cstruct''.''member''</code>''' - Let ''F'' be a <code>CData</code> object referring to the struct member. Return <code>ConvertToJS(''F'')</code>.


:'''<code>''cstruct''.''member'' = ''value''</code>''' - The value is converted to the type of the member using the implicit conversion rules. The converted value is stored in the buffer.
:'''<code>''cstruct''.''member'' = ''value''</code>''' - The value is converted to the type of the member using the implicit conversion rules. The converted value is stored in the buffer.


These getters and setters can shadow the properties and methods described above.
These getters and setters can shadow the properties and methods described above. ''(Open issue: Can they really shadow <code>.constructor</code>? Maybe <code>StructType</code> should shoot you down if you try that one.)''


Likewise, array references have getters and setters for each element. Arrays additionally have a <code>length</code> property.
Likewise, <code>CData</code> objects of array types have getters and setters for each element. Arrays additionally have a <code>length</code> property.


Note that these getters and setters are only present for integers ''i'' in the range 0 &le; i &lt; <code>''carray''.length</code>.  ''(Open issue: can we arrange to throw an exception if ''i'' is out of range?)''
Note that these getters and setters are only present for integers ''i'' in the range 0 &le; i &lt; <code>''carray''.length</code>.  ''(Open issue: can we arrange to throw an exception if ''i'' is out of range?)''


:'''<code>''carray''[''i'']</code>''' - Let ''R'' be a reference to the element at index ''i''. Return <code>ConvertToJS(''R'')</code>.
:'''<code>''carray''[''i'']</code>''' - Let ''E'' be a <code>CData</code> object referring to the element at index ''i''. Return <code>ConvertToJS(''R'')</code>.


:'''<code>''carray''[''i''] = ''val''</code>''' - Convert ''val'' to the type of the array element using the implicit conversion rules and store the result in the buffer.
:'''<code>''carray''[''i''] = ''val''</code>''' - Convert ''val'' to the type of the array element using the implicit conversion rules and store the result in the buffer.


:'''<code>''carray''.length</code>''' - Read-only. The length of the array.
:'''<code>''carray''.length</code>''' - Read-only. The length of the array.
''(Open issue: Do we care about arrays eventually having a length longer than 2<sup>53</sup>, i.e. not representable as a JS number? It's currently impossible even on 64-bit platforms.)''


''(TODO: Figure out if the type of <code>new FooArray(30)</code> is <code>FooArray</code> or <code>ArrayType(Foo, 30)</code>.)''
''(TODO: Figure out if the type of <code>new FooArray(30)</code> is <code>FooArray</code> or <code>ArrayType(Foo, 30)</code>.)''


''(TODO: Possibly, a way to get a reference that acts like a view on a window of an array. E.g. ''carray''.slice(start, stop). Then you could <code>.assign</code> one region of memory to another, effectively memcpy-ing.)''
''(TODO: Possibly, a way to get a <code>CData</code> object that acts like a view on a window of an array. E.g. ''carray''.slice(start, stop). Then you could <code>.assign</code> one region of memory to another, effectively memcpy-ing.)''
 
''(TODO: Pointer types might need some properties of their own.)''


Minutiae:
Minutiae:


:The <nowiki>[[Class]]</nowiki> of a ctypes reference is <code>"Reference"</code>.
:The <nowiki>[[Class]]</nowiki> of a <code>CData</code> object is <code>"CData"</code>.


:The prototype of a reference is the same as its type's <code>.prototype</code> property.
:The prototype of a <code>CData</code> object is the same as its type's <code>.prototype</code> property.


''(Implementation notes: A ctypes reference is a JSObject; it has a reserved slot that points to its type, a reserved slot that points to the backing buffer, and a pointer to the actual referenced location within the buffer. Since the data pointer might not be aligned to 2 bytes, PRIVATE_TO_JSVAL is insufficient; a custom JSClass.trace hook will be needed. A ctypes buffer is a separate JSObject that has a pointer to a malloc'd buffer where the C++ data is stored. It doesn't have a pointer to a ctypes type. It has a finalizer that frees the buffer; references that point into the buffer keep the buffer alive, thanks to the reserved slot.)''
''(Implementation notes: A <code>CData</code> object has a reserved slot that points to its type; a reserved slot that points to the base <code>CData</code> object that owns the backing buffer where the data is stored, or <code>null</code> if the object owns its own buffer; and a pointer to the actual referenced location within the buffer. Since the data pointer might not be aligned to 2 bytes, PRIVATE_TO_JSVAL is insufficient; a custom JSClass.trace hook will be needed. If the object owns its own buffer, its finalizer frees it; other <code>CData</code> objects that point into the buffer keep the buffer alive, thanks to the reserved slot.)''


== Pointers ==
== Pointers ==
''(TODO - this needs an overhaul! please disregard it for now!)''


js-ctypes pointers are very simple JavaScript objects that represent C/C++ pointers.  Like C/C++ pointers, js-ctypes pointers represent a memory address. They may point to valid memory, but they may also point off the end of an array, to memory that has been freed, to uninitialized or unmapped memory, or to data of a different type.
js-ctypes pointers are very simple JavaScript objects that represent C/C++ pointers.  Like C/C++ pointers, js-ctypes pointers represent a memory address. They may point to valid memory, but they may also point off the end of an array, to memory that has been freed, to uninitialized or unmapped memory, or to data of a different type.
638

edits

Navigation menu