koffi 1.3.6 → 1.3.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (77) hide show
  1. package/ChangeLog.md +13 -0
  2. package/benchmark/atoi_koffi.js +1 -1
  3. package/benchmark/raylib_koffi.js +4 -4
  4. package/build/qemu/1.3.7/koffi_darwin_arm64.tar.gz +0 -0
  5. package/build/qemu/1.3.7/koffi_darwin_x64.tar.gz +0 -0
  6. package/build/qemu/1.3.7/koffi_freebsd_arm64.tar.gz +0 -0
  7. package/build/qemu/1.3.7/koffi_freebsd_ia32.tar.gz +0 -0
  8. package/build/qemu/1.3.7/koffi_freebsd_x64.tar.gz +0 -0
  9. package/build/qemu/1.3.7/koffi_linux_arm32hf.tar.gz +0 -0
  10. package/build/qemu/1.3.7/koffi_linux_arm64.tar.gz +0 -0
  11. package/build/qemu/1.3.7/koffi_linux_ia32.tar.gz +0 -0
  12. package/build/qemu/1.3.7/koffi_linux_riscv64hf64.tar.gz +0 -0
  13. package/build/qemu/1.3.7/koffi_linux_x64.tar.gz +0 -0
  14. package/build/qemu/1.3.7/koffi_openbsd_ia32.tar.gz +0 -0
  15. package/build/qemu/1.3.7/koffi_openbsd_x64.tar.gz +0 -0
  16. package/build/qemu/1.3.7/koffi_win32_arm64.tar.gz +0 -0
  17. package/build/qemu/1.3.7/koffi_win32_ia32.tar.gz +0 -0
  18. package/build/qemu/1.3.7/koffi_win32_x64.tar.gz +0 -0
  19. package/doc/_static/perf_linux_20220628.png +0 -0
  20. package/doc/benchmarks.xlsx +0 -0
  21. package/doc/contribute.md +3 -6
  22. package/doc/dist/doctrees/changes.doctree +0 -0
  23. package/doc/dist/doctrees/contribute.doctree +0 -0
  24. package/doc/dist/doctrees/environment.pickle +0 -0
  25. package/doc/dist/doctrees/functions.doctree +0 -0
  26. package/doc/dist/doctrees/index.doctree +0 -0
  27. package/doc/dist/doctrees/start.doctree +0 -0
  28. package/doc/dist/doctrees/types.doctree +0 -0
  29. package/doc/dist/html/_sources/contribute.md.txt +3 -6
  30. package/doc/dist/html/_sources/functions.md.txt +9 -8
  31. package/doc/dist/html/_sources/start.md.txt +2 -2
  32. package/doc/dist/html/_sources/types.md.txt +15 -11
  33. package/doc/dist/html/_static/basic.css +12 -14
  34. package/doc/dist/html/_static/perf_linux_20220628.png +0 -0
  35. package/doc/dist/html/benchmarks.html +1 -1
  36. package/doc/dist/html/changes.html +16 -1
  37. package/doc/dist/html/contribute.html +4 -7
  38. package/doc/dist/html/functions.html +18 -17
  39. package/doc/dist/html/genindex.html +1 -1
  40. package/doc/dist/html/index.html +4 -3
  41. package/doc/dist/html/memory.html +1 -1
  42. package/doc/dist/html/objects.inv +0 -0
  43. package/doc/dist/html/platforms.html +2 -2
  44. package/doc/dist/html/search.html +1 -1
  45. package/doc/dist/html/searchindex.js +1 -1
  46. package/doc/dist/html/start.html +3 -3
  47. package/doc/dist/html/types.html +30 -10
  48. package/doc/functions.md +9 -8
  49. package/doc/start.md +2 -2
  50. package/doc/types.md +15 -11
  51. package/package.json +1 -1
  52. package/qemu/qemu.js +12 -2
  53. package/src/call.cc +17 -9
  54. package/src/ffi.cc +14 -5
  55. package/src/ffi.hh +0 -1
  56. package/src/util.cc +1 -1
  57. package/test/async.js +1 -1
  58. package/test/callbacks.js +25 -2
  59. package/test/misc.c +52 -2
  60. package/test/raylib.js +4 -4
  61. package/test/sqlite.js +5 -5
  62. package/test/sync.js +22 -7
  63. package/build/qemu/1.3.6/koffi_darwin_arm64.tar.gz +0 -0
  64. package/build/qemu/1.3.6/koffi_darwin_x64.tar.gz +0 -0
  65. package/build/qemu/1.3.6/koffi_freebsd_arm64.tar.gz +0 -0
  66. package/build/qemu/1.3.6/koffi_freebsd_ia32.tar.gz +0 -0
  67. package/build/qemu/1.3.6/koffi_freebsd_x64.tar.gz +0 -0
  68. package/build/qemu/1.3.6/koffi_linux_arm32hf.tar.gz +0 -0
  69. package/build/qemu/1.3.6/koffi_linux_arm64.tar.gz +0 -0
  70. package/build/qemu/1.3.6/koffi_linux_ia32.tar.gz +0 -0
  71. package/build/qemu/1.3.6/koffi_linux_riscv64hf64.tar.gz +0 -0
  72. package/build/qemu/1.3.6/koffi_linux_x64.tar.gz +0 -0
  73. package/build/qemu/1.3.6/koffi_openbsd_ia32.tar.gz +0 -0
  74. package/build/qemu/1.3.6/koffi_openbsd_x64.tar.gz +0 -0
  75. package/build/qemu/1.3.6/koffi_win32_arm64.tar.gz +0 -0
  76. package/build/qemu/1.3.6/koffi_win32_ia32.tar.gz +0 -0
  77. package/build/qemu/1.3.6/koffi_win32_x64.tar.gz +0 -0
package/src/ffi.cc CHANGED
@@ -1075,9 +1075,12 @@ static void RegisterPrimitiveType(InstanceData *instance, const char *name, Prim
1075
1075
  instance->types_map.Set(type);
1076
1076
  }
1077
1077
 
1078
- static inline PrimitiveKind GetLongPrimitive(bool sign)
1078
+ template <typename T>
1079
+ static inline PrimitiveKind GetIntegerPrimitive(bool sign)
1079
1080
  {
1080
- switch (RG_SIZE(long)) {
1081
+ switch (RG_SIZE(T)) {
1082
+ case 1: return sign ? PrimitiveKind::Int8 : PrimitiveKind::UInt8;
1083
+ case 2: return sign ? PrimitiveKind::Int16 : PrimitiveKind::UInt16;
1081
1084
  case 4: return sign ? PrimitiveKind::Int32 : PrimitiveKind::UInt32;
1082
1085
  case 8: return sign ? PrimitiveKind::Int64 : PrimitiveKind::UInt64;
1083
1086
  }
@@ -1121,9 +1124,13 @@ static Napi::Object InitBaseTypes(Napi::Env env)
1121
1124
  RegisterPrimitiveType(instance, "int64_t", PrimitiveKind::Int64, 8, alignof(int64_t));
1122
1125
  RegisterPrimitiveType(instance, "uint64", PrimitiveKind::UInt64, 8, alignof(int64_t));
1123
1126
  RegisterPrimitiveType(instance, "uint64_t", PrimitiveKind::UInt64, 8, alignof(int64_t));
1124
- RegisterPrimitiveType(instance, "long", GetLongPrimitive(true), RG_SIZE(long), alignof(long));
1125
- RegisterPrimitiveType(instance, "ulong", GetLongPrimitive(false), RG_SIZE(long), alignof(long));
1126
- RegisterPrimitiveType(instance, "unsigned long", GetLongPrimitive(false), RG_SIZE(long), alignof(long));
1127
+ RegisterPrimitiveType(instance, "intptr", GetIntegerPrimitive<intptr_t>(true), RG_SIZE(intptr_t), alignof(intptr_t));
1128
+ RegisterPrimitiveType(instance, "intptr_t", GetIntegerPrimitive<intptr_t>(true), RG_SIZE(intptr_t), alignof(intptr_t));
1129
+ RegisterPrimitiveType(instance, "uintptr", GetIntegerPrimitive<intptr_t>(false), RG_SIZE(intptr_t), alignof(intptr_t));
1130
+ RegisterPrimitiveType(instance, "uintptr_t", GetIntegerPrimitive<intptr_t>(false), RG_SIZE(intptr_t), alignof(intptr_t));
1131
+ RegisterPrimitiveType(instance, "long", GetIntegerPrimitive<long>(true), RG_SIZE(long), alignof(long));
1132
+ RegisterPrimitiveType(instance, "ulong", GetIntegerPrimitive<long>(false), RG_SIZE(long), alignof(long));
1133
+ RegisterPrimitiveType(instance, "unsigned long", GetIntegerPrimitive<long>(false), RG_SIZE(long), alignof(long));
1127
1134
  RegisterPrimitiveType(instance, "longlong", PrimitiveKind::Int64, RG_SIZE(int64_t), alignof(int64_t));
1128
1135
  RegisterPrimitiveType(instance, "long long", PrimitiveKind::Int64, RG_SIZE(int64_t), alignof(int64_t));
1129
1136
  RegisterPrimitiveType(instance, "ulonglong", PrimitiveKind::UInt64, RG_SIZE(uint64_t), alignof(uint64_t));
@@ -1134,6 +1141,8 @@ static Napi::Object InitBaseTypes(Napi::Env env)
1134
1141
  RegisterPrimitiveType(instance, "double", PrimitiveKind::Float64, 8, alignof(double));
1135
1142
  RegisterPrimitiveType(instance, "string", PrimitiveKind::String, RG_SIZE(void *), alignof(void *));
1136
1143
  RegisterPrimitiveType(instance, "string16", PrimitiveKind::String16, RG_SIZE(void *), alignof(void *));
1144
+ RegisterPrimitiveType(instance, "str", PrimitiveKind::String, RG_SIZE(void *), alignof(void *));
1145
+ RegisterPrimitiveType(instance, "str16", PrimitiveKind::String16, RG_SIZE(void *), alignof(void *));
1137
1146
 
1138
1147
  Napi::Object types = Napi::Object::New(env);
1139
1148
  for (TypeInfo &type: instance->types) {
package/src/ffi.hh CHANGED
@@ -86,7 +86,6 @@ struct TypeInfo {
86
86
  };
87
87
 
88
88
  const char *name;
89
- napi_type_tag tag;
90
89
 
91
90
  Napi::ObjectReference defn;
92
91
 
package/src/util.cc CHANGED
@@ -28,7 +28,7 @@ const TypeInfo *ResolveType(const InstanceData *instance, Napi::Value value, int
28
28
  const TypeInfo *type = instance->types_map.FindValue(str.c_str(), nullptr);
29
29
 
30
30
  if (!type) {
31
- ThrowError<Napi::TypeError>(value.Env(), "Unknown type string '%1'", str.c_str());
31
+ ThrowError<Napi::TypeError>(value.Env(), "Unknown type name '%1'", str.c_str());
32
32
  return nullptr;
33
33
  }
34
34
 
package/test/async.js CHANGED
@@ -21,7 +21,7 @@ const PackedBFG = koffi.pack('PackedBFG', {
21
21
  a: 'int8_t',
22
22
  b: 'int64_t',
23
23
  c: 'char',
24
- d: 'string',
24
+ d: 'str',
25
25
  e: 'short',
26
26
  inner: koffi.pack({
27
27
  f: 'float',
package/test/callbacks.js CHANGED
@@ -21,7 +21,7 @@ const BFG = koffi.struct('BFG', {
21
21
  a: 'int8_t',
22
22
  b: 'int64_t',
23
23
  c: 'char',
24
- d: 'string',
24
+ d: 'str',
25
25
  e: 'short',
26
26
  inner: koffi.struct({
27
27
  f: 'float',
@@ -30,9 +30,16 @@ const BFG = koffi.struct('BFG', {
30
30
  });
31
31
 
32
32
  const SimpleCallback = koffi.callback('int SimpleCallback(const char *str)');
33
- const RecursiveCallback = koffi.callback('RecursiveCallback', 'float', ['int', 'string', 'double']);
33
+ const RecursiveCallback = koffi.callback('RecursiveCallback', 'float', ['int', 'str', 'double']);
34
34
  const BigCallback = koffi.callback('BFG BigCallback(BFG bfg)');
35
35
  const ApplyCallback = koffi.callback('int __stdcall ApplyCallback(int a, int b, int c)');
36
+ const IntCallback = koffi.callback('int IntCallback(int x)');
37
+
38
+ const StructCallbacks = koffi.struct('StructCallbacks', {
39
+ first: IntCallback,
40
+ second: IntCallback,
41
+ third: IntCallback
42
+ });
36
43
 
37
44
  main();
38
45
 
@@ -54,6 +61,8 @@ async function test() {
54
61
  const CallRecursiveJS = lib.func('float CallRecursiveJS(int i, RecursiveCallback func)');
55
62
  const ModifyBFG = lib.func('BFG ModifyBFG(int x, double y, const char *str, BigCallback func, _Out_ BFG *p)');
56
63
  const ApplyStd = lib.func('int ApplyStd(int a, int b, int c, ApplyCallback func)');
64
+ const ApplyMany = lib.func('int ApplyMany(int x, IntCallback *funcs, int length)');
65
+ const ApplyStruct = lib.func('int ApplyStruct(int x, StructCallbacks callbacks)');
57
66
 
58
67
  // Simple test similar to README example
59
68
  {
@@ -92,4 +101,18 @@ async function test() {
92
101
  let ret = ApplyStd(1, 5, 9, (a, b, c) => a + b * c);
93
102
  assert.equal(ret, 46);
94
103
  }
104
+
105
+ // Array of callbacks
106
+ {
107
+ let callbacks = [x => x * 5, x => x - 42, x => -x];
108
+ let ret = ApplyMany(27, callbacks, callbacks.length);
109
+ assert.equal(ret, -93);
110
+ }
111
+
112
+ // Struct of callbacks
113
+ {
114
+ let callbacks = { first: x => -x, second: x => x * 5, third: x => x - 42 };
115
+ let ret = ApplyStruct(27, callbacks);
116
+ assert.equal(ret, -177);
117
+ }
95
118
  }
package/test/misc.c CHANGED
@@ -129,6 +129,20 @@ typedef struct IntContainer {
129
129
  int len;
130
130
  } IntContainer;
131
131
 
132
+ typedef struct StrStruct {
133
+ const char *str;
134
+ const char16_t *str16;
135
+ } StrStruct;
136
+
137
+ typedef int STDCALL ApplyCallback(int a, int b, int c);
138
+ typedef int IntCallback(int x);
139
+
140
+ typedef struct StructCallbacks {
141
+ IntCallback *first;
142
+ IntCallback *second;
143
+ IntCallback *third;
144
+ } StructCallbacks;
145
+
132
146
  EXPORT int8_t GetMinusOne1(void)
133
147
  {
134
148
  return -1;
@@ -535,8 +549,6 @@ EXPORT BFG ModifyBFG(int x, double y, const char *str, BFG (*func)(BFG bfg), BFG
535
549
  return bfg;
536
550
  }
537
551
 
538
- typedef int STDCALL ApplyCallback(int a, int b, int c);
539
-
540
552
  EXPORT int ApplyStd(int a, int b, int c, ApplyCallback *func)
541
553
  {
542
554
  int ret = func(a, b, c);
@@ -568,3 +580,41 @@ EXPORT void MultiplyIntegers(int multiplier, int *values, int len)
568
580
  values[i] *= multiplier;
569
581
  }
570
582
  }
583
+
584
+ EXPORT const char *ThroughStr(StrStruct s)
585
+ {
586
+ return s.str;
587
+ }
588
+
589
+ EXPORT const char16_t *ThroughStr16(StrStruct s)
590
+ {
591
+ return s.str16;
592
+ }
593
+
594
+ EXPORT const char *ThroughStrStar(StrStruct *s)
595
+ {
596
+ return s->str;
597
+ }
598
+
599
+ EXPORT const char16_t *ThroughStrStar16(StrStruct *s)
600
+ {
601
+ return s->str16;
602
+ }
603
+
604
+ EXPORT int ApplyMany(int x, IntCallback **callbacks, int length)
605
+ {
606
+ for (int i = 0; i < length; i++) {
607
+ x = (callbacks[i])(x);
608
+ }
609
+
610
+ return x;
611
+ }
612
+
613
+ EXPORT int ApplyStruct(int x, StructCallbacks callbacks)
614
+ {
615
+ x = callbacks.first(x);
616
+ x = callbacks.second(x);
617
+ x = callbacks.third(x);
618
+
619
+ return x;
620
+ }
package/test/raylib.js CHANGED
@@ -86,14 +86,14 @@ async function test() {
86
86
  let lib_filename = path.dirname(__filename) + '/build/raylib' + koffi.extension;
87
87
  let lib = koffi.load(lib_filename);
88
88
 
89
- const InitWindow = lib.func('InitWindow', 'void', ['int', 'int', 'string']);
89
+ const InitWindow = lib.func('InitWindow', 'void', ['int', 'int', 'str']);
90
90
  const SetTraceLogLevel = lib.func('SetTraceLogLevel', 'void', ['int']);
91
91
  const SetWindowState = lib.func('SetWindowState', 'void', ['uint']);
92
92
  const GenImageColor = lib.func('GenImageColor', Image, ['int', 'int', Color]);
93
93
  const GetFontDefault = lib.func('GetFontDefault', Font, []);
94
- const MeasureTextEx = lib.func('MeasureTextEx', Vector2, [Font, 'string', 'float', 'float']);
95
- const ImageDrawTextEx = lib.func('ImageDrawTextEx', 'void', [koffi.pointer(Image), Font, 'string', Vector2, 'float', 'float', Color]);
96
- const ExportImage = lib.func('ExportImage', 'bool', [Image, 'string']);
94
+ const MeasureTextEx = lib.func('MeasureTextEx', Vector2, [Font, 'str', 'float', 'float']);
95
+ const ImageDrawTextEx = lib.func('ImageDrawTextEx', 'void', [koffi.pointer(Image), Font, 'str', Vector2, 'float', 'float', Color]);
96
+ const ExportImage = lib.func('ExportImage', 'bool', [Image, 'str']);
97
97
 
98
98
  // We need to call InitWindow before using anything else (such as fonts)
99
99
  SetTraceLogLevel(4); // Warnings
package/test/sqlite.js CHANGED
@@ -39,13 +39,13 @@ async function test() {
39
39
  let lib_filename = path.dirname(__filename) + '/build/sqlite3' + koffi.extension;
40
40
  let lib = koffi.load(lib_filename);
41
41
 
42
- const sqlite3_open_v2 = lib.func('sqlite3_open_v2', 'int', ['string', koffi.out(koffi.pointer(sqlite3_db)), 'int', 'string']);
43
- const sqlite3_exec = lib.func('sqlite3_exec', 'int', [sqlite3_db, 'string', 'void *', 'void *', 'void *']);
44
- const sqlite3_prepare_v2 = lib.func('sqlite3_prepare_v2', 'int', [sqlite3_db, 'string', 'int', koffi.out(koffi.pointer(sqlite3_stmt)), 'string']);
42
+ const sqlite3_open_v2 = lib.func('sqlite3_open_v2', 'int', ['str', koffi.out(koffi.pointer(sqlite3_db)), 'int', 'str']);
43
+ const sqlite3_exec = lib.func('sqlite3_exec', 'int', [sqlite3_db, 'str', 'void *', 'void *', 'void *']);
44
+ const sqlite3_prepare_v2 = lib.func('sqlite3_prepare_v2', 'int', [sqlite3_db, 'str', 'int', koffi.out(koffi.pointer(sqlite3_stmt)), 'string']);
45
45
  const sqlite3_reset = lib.func('sqlite3_reset', 'int', [sqlite3_stmt]);
46
- const sqlite3_bind_text = lib.func('sqlite3_bind_text', 'int', [sqlite3_stmt, 'int', 'string', 'int', 'void *']);
46
+ const sqlite3_bind_text = lib.func('sqlite3_bind_text', 'int', [sqlite3_stmt, 'int', 'str', 'int', 'void *']);
47
47
  const sqlite3_bind_int = lib.func('sqlite3_bind_int', 'int', [sqlite3_stmt, 'int', 'int']);
48
- const sqlite3_column_text = lib.func('sqlite3_column_text', 'string', [sqlite3_stmt, 'int']);
48
+ const sqlite3_column_text = lib.func('sqlite3_column_text', 'str', [sqlite3_stmt, 'int']);
49
49
  const sqlite3_column_int = lib.func('sqlite3_column_int', 'int', [sqlite3_stmt, 'int']);
50
50
  const sqlite3_step = lib.func('sqlite3_step', 'int', [sqlite3_stmt]);
51
51
  const sqlite3_finalize = lib.func('sqlite3_finalize', 'int', [sqlite3_stmt]);
package/test/sync.js CHANGED
@@ -64,7 +64,7 @@ const BFG = koffi.struct('BFG', {
64
64
  a: 'int8_t',
65
65
  b: 'int64_t',
66
66
  c: 'char',
67
- d: 'string',
67
+ d: 'str',
68
68
  e: 'short',
69
69
  inner: koffi.struct({
70
70
  f: 'float',
@@ -75,7 +75,7 @@ const PackedBFG = koffi.pack('PackedBFG', {
75
75
  a: 'int8_t',
76
76
  b: 'int64_t',
77
77
  c: 'char',
78
- d: 'string',
78
+ d: 'str',
79
79
  e: 'short',
80
80
  inner: koffi.pack({
81
81
  f: 'float',
@@ -106,6 +106,11 @@ const IntContainer = koffi.struct('IntContainer', {
106
106
  len: 'int'
107
107
  });
108
108
 
109
+ const StrStruct = koffi.struct('StrStruct', {
110
+ str: 'str',
111
+ str16: 'str16'
112
+ });
113
+
109
114
  main();
110
115
 
111
116
  async function main() {
@@ -146,13 +151,13 @@ async function test() {
146
151
  const ConcatenateToInt1 = lib.func('ConcatenateToInt1', 'int64_t', Array(12).fill('int8_t'));
147
152
  const ConcatenateToInt4 = lib.func('ConcatenateToInt4', 'int64_t', Array(12).fill('int32_t'));
148
153
  const ConcatenateToInt8 = lib.func('ConcatenateToInt8', 'int64_t', Array(12).fill('int64_t'));
149
- const ConcatenateToStr1 = lib.func('ConcatenateToStr1', 'string', [...Array(8).fill('int8_t'), koffi.struct('IJK1', {i: 'int8_t', j: 'int8_t', k: 'int8_t'}), 'int8_t']);
150
- const ConcatenateToStr4 = lib.func('ConcatenateToStr4', 'string', [...Array(8).fill('int32_t'), koffi.pointer(koffi.struct('IJK4', {i: 'int32_t', j: 'int32_t', k: 'int32_t'})), 'int32_t']);
151
- const ConcatenateToStr8 = lib.func('ConcatenateToStr8', 'string', [...Array(8).fill('int64_t'), koffi.struct('IJK8', {i: 'int64_t', j: 'int64_t', k: 'int64_t'}), 'int64_t']);
154
+ const ConcatenateToStr1 = lib.func('ConcatenateToStr1', 'str', [...Array(8).fill('int8_t'), koffi.struct('IJK1', {i: 'int8_t', j: 'int8_t', k: 'int8_t'}), 'int8_t']);
155
+ const ConcatenateToStr4 = lib.func('ConcatenateToStr4', 'str', [...Array(8).fill('int32_t'), koffi.pointer(koffi.struct('IJK4', {i: 'int32_t', j: 'int32_t', k: 'int32_t'})), 'int32_t']);
156
+ const ConcatenateToStr8 = lib.func('ConcatenateToStr8', 'str', [...Array(8).fill('int64_t'), koffi.struct('IJK8', {i: 'int64_t', j: 'int64_t', k: 'int64_t'}), 'int64_t']);
152
157
  const MakeBFG = lib.func('BFG __stdcall MakeBFG(_Out_ BFG *p, int x, double y, const char *str)');
153
158
  const MakePackedBFG = lib.func('PackedBFG __fastcall MakePackedBFG(int x, double y, _Out_ PackedBFG *p, const char *str)');
154
159
  const ReturnBigString = process.platform == 'win32' ?
155
- lib.stdcall(1, 'string', ['string']) :
160
+ lib.stdcall(1, 'str', ['str']) :
156
161
  lib.func('const char * __stdcall ReturnBigString(const char *str)');
157
162
  const PrintFmt = lib.func('const char *PrintFmt(const char *fmt, ...)');
158
163
  const Concat16 = lib.func('const char16_t *Concat16(const char16_t *str1, const char16_t *str2)')
@@ -175,6 +180,8 @@ async function test() {
175
180
  const ArrayToStruct = lib.func('IntContainer ArrayToStruct(int *ptr, int len)');
176
181
  const FillRange = lib.func('void FillRange(int init, int step, _Out_ int *out, int len)');
177
182
  const MultiplyIntegers = lib.func('void MultiplyIntegers(int multiplier, _Inout_ int *values, int len)');
183
+ const ThroughStr = lib.func('str ThroughStr(StrStruct s)');
184
+ const ThroughStr16 = lib.func('str16 ThroughStr16(StrStruct s)');
178
185
 
179
186
  // Simple signed value returns
180
187
  assert.equal(GetMinusOne1(), -1);
@@ -292,7 +299,7 @@ async function test() {
292
299
 
293
300
  // Variadic
294
301
  {
295
- let str = PrintFmt('foo %d %g %s', 'int', 200, 'double', 1.5, 'string', 'BAR');
302
+ let str = PrintFmt('foo %d %g %s', 'int', 200, 'double', 1.5, 'str', 'BAR');
296
303
  assert.equal(str, 'foo 200 1.5 BAR');
297
304
  }
298
305
 
@@ -367,4 +374,12 @@ async function test() {
367
374
  assert.deepEqual(out1, [-2, -9, -16, -23, -30, -37, -44, -51, 58, 65]);
368
375
  assert.deepEqual(out2, new Int32Array([3 * 13, 3 * 16, 3 * 19, 3 * 22, 3 * 25, 3 * 28, 3 * 31, 34, 37, 40]));
369
376
  }
377
+
378
+ // Test struct strings
379
+ {
380
+ assert.equal(ThroughStr({ str: 'Hello', str16: null }), 'Hello');
381
+ assert.equal(ThroughStr({ str: null, str16: 'Hello' }), null);
382
+ assert.equal(ThroughStr16({ str: null, str16: 'World!' }), 'World!');
383
+ assert.equal(ThroughStr16({ str: 'World!', str16: null }), null);
384
+ }
370
385
  }