Confirmed users
3,339
edits
(Bug 1063962 renamed ctypes.jschar to ctypes.char16_t and, to maintain backwards compatibility, bug 1064935 added an alias for ctypes.jschar to ctypes.char16_t.) |
|||
| (28 intermediate revisions by 4 users not shown) | |||
| Line 9: | Line 9: | ||
<code>Library</code> objects have the following methods: | <code>Library</code> objects have the following methods: | ||
:'''<code>''lib''.declare(''name'', ''abi'', ''rtype'', ''<nowiki>[argtype1, ...]</nowiki>'')</code>''' - Declare a function. ''(TODO: all the details)'' This always returns a new function | :'''<code>''lib''.declare(''name'', ''abi'', ''rtype'', ''<nowiki>[argtype1, ...]</nowiki>'')</code>''' - Declare a function. ''(TODO: all the details)'' This always returns a new callable <code>CData</code> object representing a function pointer to ''name'', or throws an exception. | ||
:If ''rtype'' is an array type, this throws a <code>TypeError</code>. | :If ''rtype'' is an array type, this throws a <code>TypeError</code>. | ||
:If any ''argtypeN'' is an array type, the result is the same as if it had been the corresponding pointer type, <code>''argtypeN''.elementType.ptr</code>. ''(Rationale: This is how C and C++ treat array types in function declarations.)'' | :If any ''argtypeN'' is an array type, the result is the same as if it had been the corresponding pointer type, <code>''argtypeN''.elementType.ptr</code>. ''(Rationale: This is how C and C++ treat array types in function declarations.)'' | ||
''(TODO: Explain what happens when you call a declared function. In brief: It uses <code>ImplicitConvert</code> to convert the JavaScript arguments to C and <code>ConvertToJS</code> to convert the return value to JS.)'' | |||
= Types = | = Types = | ||
| Line 35: | Line 37: | ||
:''(<code>ctypes.long</code> and <code>ctypes.unsigned_long</code> autoconvert to 64-bit integer objects on all platforms. The rest autoconvert to JavaScript numbers. Rationale: Some platforms have 64-bit <code>long</code> and some do not.)'' | :''(<code>ctypes.long</code> and <code>ctypes.unsigned_long</code> autoconvert to 64-bit integer objects on all platforms. The rest autoconvert to JavaScript numbers. Rationale: Some platforms have 64-bit <code>long</code> and some do not.)'' | ||
:'''<code>ctypes.char, ctypes.signed_char, ctypes.unsigned_char</code>''' - Character types that behave like the corresponding C types. (These are | :'''<code>ctypes.char, ctypes.signed_char, ctypes.unsigned_char</code>''' - Character types that behave like the corresponding C types. (These are very much like <code>int8_t</code> and <code>uint8_t</code>, but they differ in some details of conversion. For example, <code>ctypes.char.array(30)(str)</code> converts the string ''str'' to UTF-8 and returns a new <code>CData</code> object of array type.) | ||
:'''<code>ctypes. | :'''<code>ctypes.char16_t</code>''' - A 16-bit unsigned character type representing a UTF-16 code unit. (This is distinct from <code>uint16_t</code> in details of conversion behavior. js-ctypes autoconverts C <code>char16_t</code>s to JavaScript strings of length 1.) For backwards compatibility, <code>ctypes.jschar</code> is an alias for <code>char16_t</code>. | ||
:'''<code>ctypes.void_t</code>''' - The special C type <code>void</code>. This can be used as a return value type. (<code>void</code> is a keyword in JavaScript.) | :'''<code>ctypes.void_t</code>''' - The special C type <code>void</code>. This can be used as a return value type. (<code>void</code> is a keyword in JavaScript.) | ||
| Line 50: | Line 52: | ||
:'''<code>new ctypes.PointerType(''t'')</code>''' - If ''t'' is a <code>CType</code>, return the type "pointer to ''t''". The result is cached so that future requests for this pointer type produce the same <code>CType</code> object. If ''t'' is a string, instead return a new opaque pointer type named ''t''. Otherwise throw a <code>TypeError</code>. | :'''<code>new ctypes.PointerType(''t'')</code>''' - If ''t'' is a <code>CType</code>, return the type "pointer to ''t''". The result is cached so that future requests for this pointer type produce the same <code>CType</code> object. If ''t'' is a string, instead return a new opaque pointer type named ''t''. Otherwise throw a <code>TypeError</code>. | ||
:'''<code>new ctypes.FunctionType(''abi'', ''rt'', [ ''at1'', ... ])</code>''' - Return a function pointer <code>CType</code> corresponding to the C type <code>rt (*) (at1, ...)</code>, where ''abi'' is a ctypes ABI type and ''rt'' and ''at1'', ... are <code>CType</code>s. Otherwise throw a <code>TypeError</code>. | |||
:'''<code>new ctypes.ArrayType(''t'')</code>''' - Return an array type with unspecified length and element type ''t''. If ''t'' is not a type or <code>''t''.size</code> is <code>undefined</code>, throw a <code>TypeError</code>. | :'''<code>new ctypes.ArrayType(''t'')</code>''' - Return an array type with unspecified length and element type ''t''. If ''t'' is not a type or <code>''t''.size</code> is <code>undefined</code>, throw a <code>TypeError</code>. | ||
| Line 74: | Line 78: | ||
const HANDLE = new ctypes.PointerType("HANDLE"); | const HANDLE = new ctypes.PointerType("HANDLE"); | ||
const HANDLES = new ctypes.ArrayType(HANDLE); | const HANDLES = new ctypes.ArrayType(HANDLE); | ||
const FILE = new ctypes. | const FILE = new ctypes.StructType("FILE").ptr; | ||
const IOBuf = new ctypes.ArrayType(ctypes.uint8_t, 4096); | const IOBuf = new ctypes.ArrayType(ctypes.uint8_t, 4096); | ||
const struct_tm = new ctypes.StructType('tm', [{'tm_sec': ctypes.int}, ...]); | const struct_tm = new ctypes.StructType('tm', [{'tm_sec': ctypes.int}, ...]); | ||
const comparator_t = new ctypes.FunctionType(ctypes.default_abi, ctypes.int, [ ctypes.voidptr_t, ctypes.voidptr_t ]); | |||
== Properties of types == | == Properties of types == | ||
| Line 95: | Line 101: | ||
:For primitive types this is just the name of the corresponding C/C++ type. | :For primitive types this is just the name of the corresponding C/C++ type. | ||
:For struct types and opaque pointer types, this is simply the string that was passed to the constructor. For other pointer | :For struct types and opaque pointer types, this is simply the string that was passed to the constructor. For other function, pointer, and array types this should try to generate valid C/C++ type expressions, which isn't exactly trivial. | ||
:''(Open issue: This conflicts with the usual meaning of .name for functions, and types are callable like functions.)'' | :''(Open issue: This conflicts with the usual meaning of .name for functions, and types are callable like functions.)'' | ||
| Line 103: | Line 109: | ||
ctypes.void_t.name | ctypes.void_t.name | ||
===> "void" | ===> "void" | ||
ctypes. | ctypes.char16_t.ptr.name | ||
===> " | ===> "char16_t *" | ||
const FILE = new ctypes. | const FILE = new ctypes.StructType("FILE").ptr; | ||
FILE.name | FILE.name | ||
===> "FILE *" | ===> "FILE*" | ||
const fn_t = new ctypes.FunctionType(ctypes.stdcall, ctypes.int, [ ctypes.voidptr_t, ctypes.voidptr_t ]); | |||
fn_t.name | |||
===> "int (__stdcall *)(void*, void*)" | |||
const struct_tm = new ctypes.StructType("tm", {tm_sec: ctypes.int, ... | const struct_tm = new ctypes.StructType("tm", [{tm_sec: ctypes.int}, ...]); | ||
struct_tm.name | struct_tm.name | ||
===> "tm" | ===> "tm" | ||
| Line 149: | Line 159: | ||
const Point = new ctypes.StructType( | const Point = new ctypes.StructType( | ||
"Point", {x: ctypes.int32_t, y: ctypes.int32_t}); | "Point", [{x: ctypes.int32_t}, {y: ctypes.int32_t}]); | ||
Point.toSource() | Point.toSource() | ||
===> "ctypes.StructType("Point", {x: ctypes.int32_t, y: ctypes.int23_t})" | ===> "ctypes.StructType("Point", [{x: ctypes.int32_t}, {y: ctypes.int23_t}])" | ||
Pointer types also have: | Pointer types also have: | ||
:'''<code>''t''.targetType</code>''' - Read-only. The pointed-to type, or <code>null</code> if ''t'' is an opaque pointer type. | :'''<code>''t''.targetType</code>''' - Read-only. The pointed-to type, or <code>null</code> if ''t'' is an opaque pointer type. | ||
Function types also have: | |||
:'''<code>''t''.abi</code>''' - Read-only. The ABI of the function; one of the ctypes ABI objects. | |||
:'''<code>''t''.returnType</code>''' - Read-only. The return type. | |||
:'''<code>''t''.argTypes</code>''' - Read-only. A sealed array of argument types. | |||
Struct types also have: | Struct types also have: | ||
| Line 177: | Line 195: | ||
: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. | :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.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 <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 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,Function}Type.prototype</code> and of all the builtin types except <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 pointer type is <code>ctypes.PointerType.prototype</code>. The prototype of a function type is <code>ctypes.FunctionType.prototype</code>. | ||
: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 | :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 five type constructors <code>ctypes.{C,Array,Struct,Pointer,Function}Type</code>. | ||
== Calling types == | == Calling types == | ||
| Line 199: | Line 217: | ||
::* If ''val'' is a size value (defined above): Let ''u'' = <code>ArrayType(''t''.elementType, ''val'')</code> and return <code>new ''u''</code>. | ::* If ''val'' is a size value (defined above): Let ''u'' = <code>ArrayType(''t''.elementType, ''val'')</code> and return <code>new ''u''</code>. | ||
::* If <code>''t''.elementType</code> is <code> | ::* If <code>''t''.elementType</code> is <code>char16_t</code> and ''val'' is a string: Return a new <code>CData</code> object of type <code>ArrayType(ctypes.char16_t, ''val''.length + 1)</code> containing the contents of ''val'' followed by a null character. | ||
::* If <code>''t''.elementType</code> is an 8-bit character type and ''val'' is a string: If ''val'' is not a well-formed UTF-16 string, throw a <code>TypeError</code>. Otherwise, let ''s'' = a sequence of bytes, the result of converting ''val'' from UTF-16 to UTF-8, and let ''n'' = the number of bytes in ''s''. Return a new <code>CData</code> object of type <code>ArrayType(''t''.elementType, ''n'' + 1)</code> containing the bytes in ''s'' followed by a null character. | ::* If <code>''t''.elementType</code> is an 8-bit character type and ''val'' is a string: If ''val'' is not a well-formed UTF-16 string, throw a <code>TypeError</code>. Otherwise, let ''s'' = a sequence of bytes, the result of converting ''val'' from UTF-16 to UTF-8, and let ''n'' = the number of bytes in ''s''. Return a new <code>CData</code> object of type <code>ArrayType(''t''.elementType, ''n'' + 1)</code> containing the bytes in ''s'' followed by a null character. | ||
| Line 263: | Line 281: | ||
These getters and setters can shadow the properties and methods described above. | These getters and setters can shadow the properties and methods described above. | ||
== Pointers == | |||
<code>CData</code> objects of pointer types also have this property: | |||
:'''<code>''cptr''.''contents''</code>''' - Let ''C'' be a <code>CData</code> object referring to the pointed-to contents of ''cptr''. Return <code>ConvertToJS(''C'')</code>. | |||
:'''<code>''cptr''.''contents'' = ''val''</code>''' - Let ''cval'' = <code>ImplicitConvert(''val'', the base type of the pointer)</code>. If conversion fails, throw a <code>TypeError</code>. Otherwise store ''cval'' in the pointed-to contents of ''cptr''. | |||
== Functions == | |||
<code>CData</code> objects of function types are callable: | |||
:'''<code>''let result = cfn(arg''1'', ...)''</code>''' - Let ''(carg''1'', ...)'' be <code>CData</code> objects representing the arguments to the C function ''cfn'', and ''cresult'' be a <code>CData</code> object representing its return value. Let ''carg''n = <code>ImplicitConvert(''arg''n, the type of the argument)</code>, and let ''result'' = <code>ConvertToJS(''cresult'')</code>. Call the C function with arguments represented by ''(carg''1'', ...)'', and store the result in ''cresult''. If conversion fails, throw a <code>TypeError</code>. | |||
== Arrays == | == Arrays == | ||
| Line 314: | Line 346: | ||
== Casting == | == Casting == | ||
:'''<code>ctypes.cast(''cdata'', ''t'')</code>''' - Return a new <code>CData</code> object which points to the same memory block as ''cdata'', but with type ''t''. If <code>''t''.size</code> is undefined or | :'''<code>ctypes.cast(''cdata'', ''t'')</code>''' - Return a new <code>CData</code> object which points to the same memory block as ''cdata'', but with type ''t''. If <code>''t''.size</code> is undefined or larger than <code>''cdata''.constructor.size</code>, throw a <code>TypeError</code>. This is like a C cast or a C++ <code>reinterpret_cast</code>. | ||
== Equality == | == Equality == | ||
| Line 351: | Line 383: | ||
== Int64 == | == Int64 == | ||
:'''<code>ctypes.Int64(''n'')</code>''' or '''<code>new ctypes.Int64(''n'')</code>''' - If ''n'' is an integer-valued number such that -2<sup>63</sup> ≤ ''n'' < 2<sup>63</sup>, return a sealed <code>Int64</code> object with that value. Otherwise if ''n'' is a decimal or hexadecimal | :'''<code>ctypes.Int64(''n'')</code>''' or '''<code>new ctypes.Int64(''n'')</code>''' - If ''n'' is an integer-valued number such that -2<sup>63</sup> ≤ ''n'' < 2<sup>63</sup>, return a sealed <code>Int64</code> object with that value. Otherwise if ''n'' is a string consisting of an optional minus sign followed by either decimal digits or <code>"0x"</code> or <code>"0X"</code> and hexadecimal digits, and the string represents a number within range, convert the string to an integer and construct an <code>Int64</code> object as above. Otherwise if ''n'' is an <code>Int64</code> or <code>UInt64</code> object, and represents a number within range, use the value to construct an <code>Int64</code> object as above. Otherwise throw a <code>TypeError</code>. | ||
<code>Int64</code> objects have the following methods: | <code>Int64</code> objects have the following methods: | ||
| Line 377: | Line 409: | ||
These functions are not exactly JS functions or C/C++ functions. They're algorithms used elsewhere in the spec. | These functions are not exactly JS functions or C/C++ functions. They're algorithms used elsewhere in the spec. | ||
'''<code>ConvertToJS(''x'')</code>''' - This function is used to convert a <code>CData</code> object or a C/C++ return value to a JavaScript value. The intent is to return a simple JavaScript value whenever possible, and a <code>CData</code> object otherwise. The precise rules are: | '''<code>ConvertToJS(''x'')</code>''' - This function is used to convert a <code>CData</code> object or a C/C++ return value to a JavaScript value. The intent is to return a simple JavaScript value whenever possible without loss of data or different behavior on different platforms, and a <code>CData</code> object otherwise. The precise rules are: | ||
* If the type of ''x'' is <code>void</code>, return <code>undefined</code>. | * If the type of ''x'' is <code>void</code>, return <code>undefined</code>. | ||
| Line 389: | Line 421: | ||
* If ''x'' is an unsigned wrapped integer type (<code>unsigned long</code>, <code>uint64_t</code>, <code>size_t</code>, or <code>uintptr_t</code>), return a <code>ctypes.UInt64</code> object with value ''x''. | * If ''x'' is an unsigned wrapped integer type (<code>unsigned long</code>, <code>uint64_t</code>, <code>size_t</code>, or <code>uintptr_t</code>), return a <code>ctypes.UInt64</code> object with value ''x''. | ||
* If ''x'' is of type <code> | * If ''x'' is of type <code>char16_t</code>, return a JavaScript string of length 1 containing the value of ''x'' (like <code>String.fromCharCode(x)</code>). | ||
* If ''x'' is of any other character type, | * If ''x'' is of any other character type, return the JavaScript number equal to its integer value. (This is sensitive to the signedness of the character type. Also, we assume no character types are so wide that they don't fit into a JavaScript number.) | ||
* Otherwise ''x'' is of an array, struct, or pointer type. If the argument ''x'' is already a <code>CData</code> object, return it. Otherwise allocate a buffer containing a copy of the C/C++ value ''x'', and return a <code>CData</code> object of the appropriate type referring to the object in the new buffer. | * Otherwise ''x'' is of an array, struct, or pointer type. If the argument ''x'' is already a <code>CData</code> object, return it. Otherwise allocate a buffer containing a copy of the C/C++ value ''x'', and return a <code>CData</code> object of the appropriate type referring to the object in the new buffer. | ||
| Line 399: | Line 431: | ||
''(Arrays of characters do not convert to JavaScript strings. Rationale: Suppose <code>x</code> is a <code>CData</code> object of a struct type with a member <code>a</code> of type <code>char[10]</code>. Then <code>x.a[1]</code> should return the character in element 1 of the array, even if <code>x.a[0]</code> is a null character. Likewise, <code>x.a[0] = '\0';</code> should modify the contents of the array. Both are possible only if <code>x.a</code> is a <code>CData</code> object of array type, not a JavaScript string.)'' | ''(Arrays of characters do not convert to JavaScript strings. Rationale: Suppose <code>x</code> is a <code>CData</code> object of a struct type with a member <code>a</code> of type <code>char[10]</code>. Then <code>x.a[1]</code> should return the character in element 1 of the array, even if <code>x.a[0]</code> is a null character. Likewise, <code>x.a[0] = '\0';</code> should modify the contents of the array. Both are possible only if <code>x.a</code> is a <code>CData</code> object of array type, not a JavaScript string.)'' | ||
<code>'''ImplicitConvert(''val'', ''t'')'''</code> - Convert the JavaScript value ''val'' to a C/C++ value of type ''t''. This is called whenever a JavaScript value of any kind is passed to a parameter of a ctypes-declared function, passed to <code>''cdata''.value = ''val''</code>, or assigned to an array element or struct member, as in <code>''carray''[''i''] = ''val''</code> or <code>''cstruct''.''member'' = ''val''</code>. This function is intended to lose precision only when there is no reasonable alternative. It generally does not coerce values of one type to another type. | <code>'''ImplicitConvert(''val'', ''t'')'''</code> - Convert the JavaScript value ''val'' to a C/C++ value of type ''t''. This is called whenever a JavaScript value of any kind is passed to a parameter of a ctypes-declared function, passed to <code>''cdata''.value = ''val''</code>, or assigned to an array element or struct member, as in <code>''carray''[''i''] = ''val''</code> or <code>''cstruct''.''member'' = ''val''</code>. | ||
This function is intended to lose precision only when there is no reasonable alternative. It generally does not coerce values of one type to another type. | |||
C/C++ values of all supported types round trip through <code>ConvertToJS</code> and <code>ImplicitConvert</code> without any loss of data. That is, for any C/C++ value ''v'' of type ''t'', <code>ImplicitConvert(ConvertToJS(''v''), ''t'') </code> produces a copy of ''v''. ''(Note that not all JavaScript can round-trip to C/C++ and back in an analogous way. JavaScript primitive numbers can round-trip to <code>double</code> on all current platforms, <code>Int64</code> objects to <code>int64_t</code>, JavaScript booleans to <code>bool</code>, and so on. But some JavaScript values, such as functions, cannot be <code>ImplicitConvert</code>ed to any C/C++ type without loss of data.)'' | |||
''t'' must not be <code>void</code> or an array type with unspecified length. ''(Rationale: C/C++ variables and parameters cannot have such types. The parameter of a function declared <code>int f(int x[])</code> is <code>int *</code>, not <code>int[]</code>.)'' | ''t'' must not be <code>void</code> or an array type with unspecified length. ''(Rationale: C/C++ variables and parameters cannot have such types. The parameter of a function declared <code>int f(int x[])</code> is <code>int *</code>, not <code>int[]</code>.)'' | ||
| Line 419: | Line 455: | ||
:* Otherwise fail. | :* Otherwise fail. | ||
* If ''t'' is <code>ctypes. | * If ''t'' is <code>ctypes.char16_t</code>: | ||
:* If ''val'' is a string of length 1, the result is the 16-bit unsigned value of the code unit in the string. <code>''val''.charCodeAt(0)</code>. | :* If ''val'' is a string of length 1, the result is the 16-bit unsigned value of the code unit in the string. <code>''val''.charCodeAt(0)</code>. | ||
:* If ''val'' is a number that can be exactly represented as a value of type <code> | :* If ''val'' is a number that can be exactly represented as a value of type <code>char16_t</code> (that is, an integer in the range 0 ≤ ''val'' < 2<sup>16</sup>), the result is that value. | ||
:* Otherwise fail. | :* Otherwise fail. | ||
| Line 440: | Line 476: | ||
* If ''t'' is an array type: | * If ''t'' is an array type: | ||
:* If ''val'' is a JavaScript string: | :* If ''val'' is a JavaScript string: | ||
::* If <code>''t''.elementType</code> is <code> | ::* If <code>''t''.elementType</code> is <code>char16_t</code> and <code>''t''.length >= ''val''.length</code>, the result is an array of type ''t'' whose first <code>''val''.length</code> elements are the 16-bit elements of ''val''. If <code>''t''.length > ''val''.length</code>, then element <code>''val''.length</code> of the result is a null character. The values of the rest of the array elements are unspecified. | ||
::* If <code>''t''.elementType</code> is an 8-bit character type: | ::* If <code>''t''.elementType</code> is an 8-bit character type: | ||
:::* If ''t'' is not well-formed UTF-16, fail. | :::* If ''t'' is not well-formed UTF-16, fail. | ||
| Line 448: | Line 484: | ||
:::* The result is an array of type ''t'' whose first ''n'' elements are the 8-bit values in ''s''. If <code>''t''.length > ''n''</code>, then element ''n'' of the result is 0. The values of the rest of the array elements are unspecified. | :::* The result is an array of type ''t'' whose first ''n'' elements are the 8-bit values in ''s''. If <code>''t''.length > ''n''</code>, then element ''n'' of the result is 0. The values of the rest of the array elements are unspecified. | ||
::* Otherwise fail. | ::* Otherwise fail. | ||
:* If ''val'' is a JavaScript array object: | :* If ''val'' is a JavaScript array object: | ||
::* If <code>''val''.length</code> is not a nonnegative integer, fail. | ::* If <code>''val''.length</code> is not a nonnegative integer, fail. | ||
::* If <code>''val''.length !== ''t''.length</code>, fail. | ::* If <code>''val''.length !== ''t''.length</code>, fail. | ||
::* Otherwise, the result is a C/C++ array of <code>''val''.length</code> elements of type <code>''t''.elementType</code>. Element ''i'' of the result is <code>ImplicitConvert(''val''[''i''], ''t''.elementType)</code>. | ::* Otherwise, the result is a C/C++ array of <code>''val''.length</code> elements of type <code>''t''.elementType</code>. Element ''i'' of the result is <code>ImplicitConvert(''val''[''i''], ''t''.elementType)</code>. | ||
:* Otherwise fail. | :* Otherwise fail. ''(Rationale: The clause "If ''val'' is a JavaScript array object" requires some justification. If we allowed arbitrary JavaScript objects that resemble arrays, that would include CData objects of array type. Consequently, <code>arr1.value = arr2</code> where <code>arr1</code> is of type <code>ctypes.uint8_t.array(30)</code> and <code>arr2</code> is of type <code>ctypes.int.array(30)</code> would work as long as the values in <code>arr2</code> are small enough. We considered this conversion too astonishing and too error-prone.)'' | ||
* Otherwise ''t'' is a struct type. | * Otherwise ''t'' is a struct type. | ||
| Line 476: | Line 513: | ||
* If ''t'' is a pointer type and ''val'' is a number, <code>Int64</code> object, or <code>UInt64</code> object that can be exactly represented as an <code>intptr_t</code> or <code>uintptr_t</code>, the result is the same as casting that <code>intptr_t</code> or <code>uintptr_t</code> value to type ''t'' with a C-style cast. | * If ''t'' is a pointer type and ''val'' is a number, <code>Int64</code> object, or <code>UInt64</code> object that can be exactly represented as an <code>intptr_t</code> or <code>uintptr_t</code>, the result is the same as casting that <code>intptr_t</code> or <code>uintptr_t</code> value to type ''t'' with a C-style cast. | ||
* If ''t'' is a | * If ''t'' is an integer type (not a character type) and ''val'' is a string consisting entirely of an optional minus sign, followed by either one or more decimal digits or the characters "0x" or "0X" and one or more hexadecimal digits, then the result is the same as casting the integer named by ''val'' to type ''t'' with a C-style cast. | ||
* Otherwise fail. | * Otherwise fail. | ||
| Line 483: | Line 520: | ||
*If ''t'' and ''u'' represent the same built-in type, even <code>void</code>, return true. | *If ''t'' and ''u'' represent the same built-in type, even <code>void</code>, return true. | ||
*If they are both pointer types, return <code>SameType(''t''.targetType, ''u''.targetType)</code>. | *If they are both pointer types, return <code>SameType(''t''.targetType, ''u''.targetType)</code>. | ||
*If they are both array types, return <code>SameType(''t''.elementType, ''u''. | *If they are both array types, return <code>SameType(''t''.elementType, ''u''.elementType) && ''t''.length === ''u''.length</code>. | ||
*If they are both struct types, return <code>''t'' === ''u''</code>. | *If they are both struct types, return <code>''t'' === ''u''</code>. | ||
*Otherwise return false. | *Otherwise return false. | ||
| Line 511: | Line 548: | ||
This allocates a new C++ object of type <code>int32_t</code> (4 bytes of memory), zeroes it out, and returns a JS object that manages the allocated memory. Whenever the JS object is garbage-collected, the allocated memory will be automatically freed. | This allocates a new C++ object of type <code>int32_t</code> (4 bytes of memory), zeroes it out, and returns a JS object that manages the allocated memory. Whenever the JS object is garbage-collected, the allocated memory will be automatically freed. | ||
Of course you don't normally need to do this, as js-ctypes will autoconvert JS numbers to various C/C++ types for you: | |||
let myfunc = mylib.declare("myfunc", ctypes.default_abi, | let myfunc = mylib.declare("myfunc", ctypes.default_abi, | ||
| Line 521: | Line 558: | ||
<code>ctypes.int32_t</code> is a <code>CType</code>. Like all other CTypes, it can be used for type specification when passed as an object, as above. (This will work for user-defined <code>CTypes</code> such as structs and pointers also - see later.) | <code>ctypes.int32_t</code> is a <code>CType</code>. Like all other CTypes, it can be used for type specification when passed as an object, as above. (This will work for user-defined <code>CTypes</code> such as structs and pointers also - see later.) | ||
The object created by <code>new ctypes.int32_t</code> is called a <code>CData</code> object, and they are described in detail in the "<code>CData</code> objects" section above. | |||
Opaque pointers: | Opaque pointers: | ||
// A new opaque pointer type. | // A new opaque pointer type. | ||
FILE_ptr = new ctypes. | FILE_ptr = new ctypes.StructType("FILE").ptr; | ||
let fopen = mylib.declare("fopen", ctypes.default_abi, | let fopen = mylib.declare("fopen", ctypes.default_abi, | ||
| Line 579: | Line 616: | ||
// cast from (uint32_t *) to (uint8_t *) | // cast from (uint32_t *) to (uint8_t *) | ||
let q = ctypes.cast(ctypes.uint8_t.ptr | let q = ctypes.cast(p, ctypes.uint8_t.ptr); | ||
// first byte of buffer | // first byte of buffer | ||
| Line 694: | Line 731: | ||
'''<code>''cdata''.writeString(''s'', ''[encoding[, length]]'')</code>''' - Determine the starting pointer ''p'' as above. If ''s'' is not a well-formed UTF-16 string, throw a <code>TypeError</code>. ''(Open issue: Error handling.)'' Otherwise convert ''s'' to bytes in the specified ''encoding'' (default: UTF-8) and write at most ''length'' - 1 bytes, or all the converted bytes, if ''length'' is <code>undefined</code> or omitted, to memory starting at ''p''. Write a converted null character after the data. Return the number of bytes of data written, not counting the terminating null character. | '''<code>''cdata''.writeString(''s'', ''[encoding[, length]]'')</code>''' - Determine the starting pointer ''p'' as above. If ''s'' is not a well-formed UTF-16 string, throw a <code>TypeError</code>. ''(Open issue: Error handling.)'' Otherwise convert ''s'' to bytes in the specified ''encoding'' (default: UTF-8) and write at most ''length'' - 1 bytes, or all the converted bytes, if ''length'' is <code>undefined</code> or omitted, to memory starting at ''p''. Write a converted null character after the data. Return the number of bytes of data written, not counting the terminating null character. | ||
''(Open issue: ''<code>''cdata''.writeString(...)</code>'' is awkward for the case where you want an autosized <code>ctypes.char.array()</code> to hold the converted data. If <code>''cdata''</code> happens to be too small for the resulting string, and you don't supply ''length'', you crash; and if you do supply ''length'', you don't know whether conversion was halted because the target array was of insufficient length.)'' | |||
''(Open issue: As proposed, these are not suitable for working with encodings where a zero byte might not indicate the end of text. For example, a string encoded in UTF-16 will typically contain a lot of zero bytes. Unfortunately, in the case of readString, the underlying library demands the length up front.)'' | ''(Open issue: As proposed, these are not suitable for working with encodings where a zero byte might not indicate the end of text. For example, a string encoded in UTF-16 will typically contain a lot of zero bytes. Unfortunately, in the case of readString, the underlying library demands the length up front.)'' | ||
| Line 725: | Line 764: | ||
In C/C++, the type <code>char *</code> effectively promises nothing about the pointed-to data. Autoconverting would make it hard to use APIs that return non-null-terminated strings (or structs containing <code>char *</code> pointers that aren't logically strings). The workaround would be to declare them as a different type. | In C/C++, the type <code>char *</code> effectively promises nothing about the pointed-to data. Autoconverting would make it hard to use APIs that return non-null-terminated strings (or structs containing <code>char *</code> pointers that aren't logically strings). The workaround would be to declare them as a different type. | ||
'''Unicode.''' This problem does not apply to conversions between JS strings and <code> | '''Unicode.''' This problem does not apply to conversions between JS strings and <code>char16_t</code> arrays or pointers; only <code>char</code> arrays or pointers. | ||
Converting both ways raises issues about what encoding should be assumed. We assume JS strings are UTF-16 and <code>char</code> strings are UTF-8, which is not the right thing on Windows. However Windows offers a lot of APIs that accept 16-bit strings and, for those, <code>char16_t</code> is the right thing. | |||
'''Casting away const.''' This problem arises only when converting from a JS string to a C/C++ pointer type. The string data must not be modified, but the C/C++ types <code>char *</code> and <code>char16_t *</code> suggest that the referent might be modified. | |||