rclnodejs 1.5.1 → 1.6.0

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 (64) hide show
  1. package/README.md +25 -2
  2. package/binding.gyp +2 -0
  3. package/index.js +21 -4
  4. package/lib/action/client.js +1 -1
  5. package/lib/action/graph.js +1 -1
  6. package/lib/action/server.js +1 -1
  7. package/lib/action/server_goal_handle.js +1 -1
  8. package/lib/client.js +1 -1
  9. package/lib/clock.js +1 -1
  10. package/lib/context.js +1 -1
  11. package/lib/duration.js +1 -1
  12. package/lib/event_handler.js +1 -1
  13. package/lib/guard_condition.js +1 -1
  14. package/lib/lifecycle.js +1 -1
  15. package/lib/lifecycle_publisher.js +1 -1
  16. package/lib/logging.js +1 -1
  17. package/lib/message_serialization.js +171 -0
  18. package/lib/native_loader.js +173 -0
  19. package/lib/node.js +16 -1
  20. package/lib/parameter.js +4 -10
  21. package/lib/publisher.js +1 -1
  22. package/lib/serialization.js +1 -1
  23. package/lib/service.js +1 -1
  24. package/lib/subscription.js +17 -2
  25. package/lib/time.js +1 -1
  26. package/lib/time_source.js +1 -1
  27. package/lib/timer.js +1 -1
  28. package/lib/type_description_service.js +1 -1
  29. package/lib/utils.js +324 -0
  30. package/lib/validator.js +1 -1
  31. package/package.json +14 -18
  32. package/prebuilds/linux-arm64/humble-jammy-arm64-rclnodejs.node +0 -0
  33. package/prebuilds/linux-arm64/jazzy-noble-arm64-rclnodejs.node +0 -0
  34. package/prebuilds/linux-arm64/kilted-noble-arm64-rclnodejs.node +0 -0
  35. package/prebuilds/linux-x64/humble-jammy-x64-rclnodejs.node +0 -0
  36. package/prebuilds/linux-x64/jazzy-noble-x64-rclnodejs.node +0 -0
  37. package/prebuilds/linux-x64/kilted-noble-x64-rclnodejs.node +0 -0
  38. package/rosidl_convertor/idl_convertor.js +3 -2
  39. package/rosidl_gen/deallocator.js +1 -1
  40. package/rosidl_gen/generate_worker.js +1 -1
  41. package/rosidl_gen/generator.json +1 -1
  42. package/rosidl_gen/idl_generator.js +11 -24
  43. package/rosidl_gen/index.js +1 -1
  44. package/rosidl_gen/primitive_types.js +2 -2
  45. package/rosidl_gen/templates/action-template.js +68 -0
  46. package/rosidl_gen/templates/message-template.js +1113 -0
  47. package/rosidl_gen/templates/service-event-template.js +31 -0
  48. package/rosidl_gen/templates/service-template.js +44 -0
  49. package/rosidl_parser/rosidl_parser.js +2 -2
  50. package/scripts/install.js +113 -0
  51. package/scripts/tag_prebuilds.js +70 -0
  52. package/src/addon.cpp +3 -0
  53. package/third_party/ref-napi/index.js +15 -0
  54. package/third_party/ref-napi/lib/ref.js +1696 -0
  55. package/third_party/ref-napi/src/ref_napi_bindings.cpp +736 -0
  56. package/third_party/ref-napi/src/ref_napi_bindings.h +26 -0
  57. package/types/index.d.ts +17 -0
  58. package/types/node.d.ts +16 -1
  59. package/rosidl_gen/templates/CMakeLists.dot +0 -40
  60. package/rosidl_gen/templates/action.dot +0 -50
  61. package/rosidl_gen/templates/message.dot +0 -851
  62. package/rosidl_gen/templates/package.dot +0 -16
  63. package/rosidl_gen/templates/service.dot +0 -26
  64. package/rosidl_gen/templates/service_event.dot +0 -10
@@ -0,0 +1,736 @@
1
+ // Copyright (c) 2025, The Robot Web Tools Contributors
2
+ //
3
+ // Licensed under the Apache License, Version 2.0 (the "License");
4
+ // you may not use this file except in compliance with the License.
5
+ // You may obtain a copy of the License at
6
+ //
7
+ // http://www.apache.org/licenses/LICENSE-2.0
8
+ //
9
+ // Unless required by applicable law or agreed to in writing, software
10
+ // distributed under the License is distributed on an "AS IS" BASIS,
11
+ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ // See the License for the specific language governing permissions and
13
+ // limitations under the License.
14
+
15
+ #include "ref_napi_bindings.h"
16
+
17
+ #include <errno.h>
18
+ #include <stdint.h>
19
+ #include <stdlib.h>
20
+ #include <string.h>
21
+
22
+ #include <string>
23
+ #include <unordered_map>
24
+
25
+ #if !defined(NAPI_VERSION) || NAPI_VERSION < 6
26
+ #include <get-symbol-from-current-process.h>
27
+ #endif
28
+
29
+ namespace RefNapi {
30
+
31
+ class Instance {
32
+ public:
33
+ virtual napi_value WrapPointer(char* ptr, size_t length) = 0;
34
+ virtual char* GetBufferData(napi_value val) = 0;
35
+ };
36
+
37
+ } // namespace RefNapi
38
+
39
+ #ifndef _WIN32
40
+ #ifndef __STDC_FORMAT_MACROS
41
+ #define __STDC_FORMAT_MACROS
42
+ #endif
43
+ #include <inttypes.h>
44
+ #else
45
+ #define __alignof__ __alignof
46
+ #define snprintf(buf, bufSize, format, arg) \
47
+ _snprintf_s(buf, bufSize, _TRUNCATE, format, arg)
48
+ #define strtoll _strtoi64
49
+ #define strtoull _strtoui64
50
+ #define PRId64 "lld"
51
+ #define PRIu64 "llu"
52
+ #endif
53
+
54
+ namespace rclnodejs {
55
+
56
+ using namespace Napi;
57
+
58
+ namespace {
59
+
60
+ // used by the Int64 functions to determine whether to return a Number
61
+ // or String based on whether or not a Number will lose precision.
62
+ // http://stackoverflow.com/q/307179/376773
63
+ #define JS_MAX_INT +9007199254740992LL
64
+ #define JS_MIN_INT -9007199254740992LL
65
+
66
+ // mirrors deps/v8/src/objects.h.
67
+ // we could use `node::Buffer::kMaxLength`, but it's not defined on node v0.6.x
68
+ static const size_t kMaxLength = 0x3fffffff;
69
+
70
+ // Since Node.js v14.0.0, we have to keep a global list of all ArrayBuffer
71
+ // instances that we work with, in order not to create any duplicates.
72
+ // Luckily, N-API instance data is available on v14.x and above.
73
+ class InstanceData final : public RefNapi::Instance {
74
+ public:
75
+ explicit InstanceData(Env env) : env(env) {}
76
+ Env env;
77
+ FunctionReference pointer_ctor;
78
+
79
+ napi_value WrapPointer(char* ptr, size_t length) override;
80
+ char* GetBufferData(napi_value val) override;
81
+
82
+ static InstanceData* Get(Env env) {
83
+ return env.GetInstanceData<InstanceData>();
84
+ }
85
+ };
86
+
87
+ class PointerBuffer : public ObjectWrap<PointerBuffer> {
88
+ public:
89
+ static Object Init(Napi::Env env, Object exports);
90
+ explicit PointerBuffer(Napi::CallbackInfo& info);
91
+ Napi::Value IsNull(const Napi::CallbackInfo& info);
92
+ Napi::Value Address(const Napi::CallbackInfo& info);
93
+ Napi::Value Length(const Napi::CallbackInfo& info);
94
+ Napi::Value Get(const Napi::CallbackInfo& info);
95
+ Napi::Value ToString(const Napi::CallbackInfo& info);
96
+ Napi::Value Copy(const Napi::CallbackInfo& info);
97
+ Napi::Value Slice(const Napi::CallbackInfo& info);
98
+ char* ptr_;
99
+ int length_;
100
+ };
101
+
102
+ Object PointerBuffer::Init(Napi::Env env, Object exports) {
103
+ Function func =
104
+ DefineClass(env, "PointerBuffer",
105
+ {InstanceMethod("isNull", &PointerBuffer::IsNull),
106
+ InstanceMethod("get", &PointerBuffer::Get),
107
+ InstanceMethod("address", &PointerBuffer::Address),
108
+ InstanceMethod("toString", &PointerBuffer::ToString),
109
+ InstanceMethod("copy", &PointerBuffer::Copy),
110
+ InstanceMethod("slice", &PointerBuffer::Slice),
111
+ InstanceAccessor<&PointerBuffer::Length>("length")});
112
+
113
+ exports.Set("PointerBuffer", func);
114
+ InstanceData* data = InstanceData::Get(env);
115
+ data->pointer_ctor = Persistent(func);
116
+ return exports;
117
+ }
118
+
119
+ PointerBuffer::PointerBuffer(Napi::CallbackInfo& info)
120
+ : Napi::ObjectWrap<PointerBuffer>(info) {
121
+ Napi::Env env = info.Env();
122
+ int length = info.Length();
123
+ if (length <= 0 || !info[0].IsNumber()) {
124
+ Napi::TypeError::New(env, "Number expected").ThrowAsJavaScriptException();
125
+ return;
126
+ }
127
+ Napi::Number value = info[0].As<Napi::Number>();
128
+ ptr_ = reinterpret_cast<char*>(value.Int64Value());
129
+ length_ = (ptr_ == nullptr ? 0 : info[1].As<Number>().Int32Value());
130
+ }
131
+
132
+ Napi::Value PointerBuffer::IsNull(const Napi::CallbackInfo& info) {
133
+ return Boolean::New(info.Env(), ptr_ == nullptr);
134
+ }
135
+
136
+ Napi::Value PointerBuffer::Address(const Napi::CallbackInfo& info) {
137
+ return Number::New(info.Env(), reinterpret_cast<int64_t>(ptr_));
138
+ }
139
+
140
+ Napi::Value PointerBuffer::Length(const Napi::CallbackInfo& info) {
141
+ return Number::New(info.Env(), length_);
142
+ }
143
+
144
+ Napi::Value PointerBuffer::Get(const Napi::CallbackInfo& info) {
145
+ int32_t offset = info[0].As<Number>().Int32Value();
146
+ return Number::New(info.Env(), ptr_[offset]);
147
+ }
148
+
149
+ Napi::Value PointerBuffer::ToString(const Napi::CallbackInfo& info) {
150
+ Napi::Env env = info.Env();
151
+ int length = info.Length();
152
+ if (length == 1 || info[0].IsString()) {
153
+ std::string encoding = info[0].As<String>();
154
+ if (encoding == "utf-8") {
155
+ return String::New(info.Env(), ptr_, length_);
156
+ } else if (encoding == "ucs2") {
157
+ return String::New(info.Env(), reinterpret_cast<char16_t*>(ptr_),
158
+ length_ / 2);
159
+ } else {
160
+ Napi::TypeError::New(env, "Unknown encoding argument: " + encoding)
161
+ .ThrowAsJavaScriptException();
162
+ }
163
+ }
164
+
165
+ return String::New(info.Env(), ptr_, length_);
166
+ }
167
+
168
+ char* ExtractBufferData(Value val);
169
+
170
+ Napi::Value PointerBuffer::Copy(const Napi::CallbackInfo& info) {
171
+ char* dest =
172
+ ExtractBufferData(info[0]) + info[1].As<Napi::Number>().Int64Value();
173
+ uint64_t length =
174
+ info[3].As<Number>().Int64Value() - info[2].As<Number>().Int64Value();
175
+ std::memcpy(dest, ptr_, length);
176
+ return Number::New(info.Env(), length);
177
+ }
178
+
179
+ Value CreatePointerBuffer(Env env, char* ptr, size_t length);
180
+
181
+ Napi::Value PointerBuffer::Slice(const Napi::CallbackInfo& info) {
182
+ int64_t offset = info[0].As<Napi::Number>().Int64Value();
183
+ return CreatePointerBuffer(info.Env(), ptr_ + offset, length_ - offset);
184
+ }
185
+
186
+ Value CreatePointerBuffer(Env env, char* ptr, size_t length) {
187
+ InstanceData* data = InstanceData::Get(env);
188
+ return data->pointer_ctor.New(
189
+ {Number::New(env, reinterpret_cast<int64_t>(ptr)),
190
+ Number::New(env, length)});
191
+ }
192
+
193
+ char* ExtractBufferData(Value val) {
194
+ if (!val.IsBuffer() && val.IsObject()) {
195
+ auto p = PointerBuffer::Unwrap(val.As<Object>());
196
+ return p->ptr_;
197
+ }
198
+
199
+ Buffer<char> buf = val.As<Buffer<char>>();
200
+ return buf.Data();
201
+ }
202
+
203
+ napi_value InstanceData::WrapPointer(char* ptr, size_t length) {
204
+ return CreatePointerBuffer(env, ptr, length);
205
+ }
206
+
207
+ char* InstanceData::GetBufferData(napi_value val) {
208
+ return ExtractBufferData(Value(env, val));
209
+ }
210
+
211
+ char* AddressForArgs(const CallbackInfo& args, size_t offset_index = 1) {
212
+ Value buf = args[0];
213
+ if (!(buf.IsBuffer() || buf.IsObject())) {
214
+ throw TypeError::New(args.Env(),
215
+ "Buffer or PointerBuffer instance expected");
216
+ }
217
+
218
+ int64_t offset = args[offset_index].ToNumber();
219
+ return ExtractBufferData(buf) + offset;
220
+ }
221
+
222
+ Value Address(const CallbackInfo& args) {
223
+ char* ptr = AddressForArgs(args);
224
+ uintptr_t intptr = reinterpret_cast<uintptr_t>(ptr);
225
+
226
+ return Number::New(args.Env(), static_cast<double>(intptr));
227
+ }
228
+
229
+ Value HexAddress(const CallbackInfo& args) {
230
+ char* ptr = AddressForArgs(args);
231
+ char strbuf[30];
232
+ snprintf(strbuf, 30, "%p", ptr);
233
+
234
+ if (strbuf[0] == '0' && strbuf[1] == 'x') {
235
+ ptr = strbuf + 2;
236
+ } else {
237
+ ptr = strbuf;
238
+ }
239
+
240
+ return String::New(args.Env(), ptr);
241
+ }
242
+
243
+ Value IsNull(const CallbackInfo& args) {
244
+ Value buf = args[0];
245
+ if (!(buf.IsBuffer() || buf.IsObject())) {
246
+ return Boolean::New(args.Env(), false);
247
+ }
248
+
249
+ char* ptr = AddressForArgs(args);
250
+ return Boolean::New(args.Env(), ptr == nullptr);
251
+ }
252
+
253
+ Value IsAddress(const CallbackInfo& args) {
254
+ Value buf = args[0];
255
+ if (!(buf.IsBuffer() || buf.IsObject())) {
256
+ return Boolean::New(args.Env(), false);
257
+ }
258
+ return Boolean::New(args.Env(), true);
259
+ }
260
+
261
+ Value ReadObject(const CallbackInfo& args) {
262
+ char* ptr = AddressForArgs(args);
263
+
264
+ if (ptr == nullptr) {
265
+ throw Error::New(args.Env(),
266
+ "readObject: Cannot read from nullptr pointer");
267
+ }
268
+
269
+ Reference<Object>* rptr = reinterpret_cast<Reference<Object>*>(ptr);
270
+ return rptr->Value();
271
+ }
272
+
273
+ void WriteObject(const CallbackInfo& args) {
274
+ Env env = args.Env();
275
+ char* ptr = AddressForArgs(args);
276
+
277
+ if (ptr == nullptr) {
278
+ throw Error::New(env, "readObject: Cannot write to nullptr pointer");
279
+ }
280
+
281
+ Reference<Object>* rptr = reinterpret_cast<Reference<Object>*>(ptr);
282
+ if (args[2].IsObject()) {
283
+ Object val = args[2].As<Object>();
284
+ *rptr = std::move(Reference<Object>::New(val));
285
+ } else if (args[2].IsNull()) {
286
+ rptr->Reset();
287
+ } else {
288
+ throw TypeError::New(env,
289
+ "WriteObject's 3rd argument needs to be an object");
290
+ }
291
+ }
292
+
293
+ Value ReadPointer(const CallbackInfo& args) {
294
+ Env env = args.Env();
295
+ char* ptr = AddressForArgs(args);
296
+
297
+ if (ptr == nullptr) {
298
+ throw Error::New(env, "readPointer: Cannot read from nullptr pointer");
299
+ }
300
+
301
+ int64_t size = args[2].ToNumber();
302
+
303
+ char* val = *reinterpret_cast<char**>(ptr);
304
+ return CreatePointerBuffer(env, val, size);
305
+ }
306
+
307
+ void WritePointer(const CallbackInfo& args) {
308
+ Env env = args.Env();
309
+ char* ptr = AddressForArgs(args);
310
+ Value input = args[2];
311
+
312
+ if (!input.IsNull() && !input.IsBuffer() && !input.IsObject()) {
313
+ throw TypeError::New(
314
+ env, "writePointer: Buffer instance expected as third argument");
315
+ }
316
+
317
+ if (input.IsNull()) {
318
+ *reinterpret_cast<char**>(ptr) = nullptr;
319
+ } else {
320
+ char* input_ptr = ExtractBufferData(input);
321
+ *reinterpret_cast<char**>(ptr) = input_ptr;
322
+ }
323
+ }
324
+
325
+ Value ReadInt64(const CallbackInfo& args) {
326
+ Env env = args.Env();
327
+ char* ptr = AddressForArgs(args);
328
+
329
+ if (ptr == nullptr) {
330
+ throw TypeError::New(env, "readInt64: Cannot read from nullptr pointer");
331
+ }
332
+
333
+ int64_t val = *reinterpret_cast<int64_t*>(ptr);
334
+
335
+ if (val < JS_MIN_INT || val > JS_MAX_INT) {
336
+ char strbuf[128];
337
+ snprintf(strbuf, 128, "%" PRId64, val);
338
+ return String::New(env, strbuf);
339
+ } else {
340
+ return Number::New(env, val);
341
+ }
342
+ }
343
+
344
+ Value ReadInt32(const CallbackInfo& args) {
345
+ Env env = args.Env();
346
+ char* ptr = AddressForArgs(args);
347
+
348
+ if (ptr == nullptr) {
349
+ throw TypeError::New(env, "readInt64: Cannot read from nullptr pointer");
350
+ }
351
+
352
+ int32_t val = *reinterpret_cast<int32_t*>(ptr);
353
+ return Number::New(env, val);
354
+ }
355
+
356
+ void WriteInt64(const CallbackInfo& args) {
357
+ Env env = args.Env();
358
+ char* ptr = AddressForArgs(args);
359
+
360
+ Value in = args[2];
361
+ int64_t val;
362
+ if (in.IsNumber()) {
363
+ val = in.As<Number>();
364
+ } else if (in.IsString()) {
365
+ char* endptr;
366
+ char* str;
367
+ int base = 0;
368
+ std::string _str = in.As<String>();
369
+ str = &_str[0];
370
+
371
+ errno = 0;
372
+ val = strtoll(str, &endptr, base);
373
+
374
+ if (endptr == str) {
375
+ throw TypeError::New(env,
376
+ "writeInt64: no digits we found in input String");
377
+ } else if (errno == ERANGE && (val == INT64_MAX || val == INT64_MIN)) {
378
+ throw TypeError::New(
379
+ env, "writeInt64: input String numerical value out of range");
380
+ } else if (errno != 0 && val == 0) {
381
+ char errmsg[200];
382
+ snprintf(errmsg, sizeof(errmsg), "writeInt64: %s", strerror(errno));
383
+ throw TypeError::New(env, errmsg);
384
+ }
385
+ } else {
386
+ throw TypeError::New(env,
387
+ "writeInt64: Number/String 64-bit value required");
388
+ }
389
+
390
+ *reinterpret_cast<int64_t*>(ptr) = val;
391
+ }
392
+
393
+ void WriteInt32(const CallbackInfo& args) {
394
+ Env env = args.Env();
395
+ char* ptr = AddressForArgs(args);
396
+
397
+ Value in = args[2];
398
+ int64_t val;
399
+ if (in.IsNumber()) {
400
+ val = in.As<Number>();
401
+ } else if (in.IsString()) {
402
+ char* endptr;
403
+ char* str;
404
+ int base = 0;
405
+ std::string _str = in.As<String>();
406
+ str = &_str[0];
407
+
408
+ errno = 0;
409
+ val = strtoll(str, &endptr, base);
410
+
411
+ if (endptr == str) {
412
+ throw TypeError::New(env,
413
+ "writeInt32: no digits we found in input String");
414
+ } else if (errno == ERANGE && (val == INT32_MAX || val == INT32_MIN)) {
415
+ throw TypeError::New(
416
+ env, "writeInt32: input String numerical value out of range");
417
+ } else if (errno != 0 && val == 0) {
418
+ char errmsg[200];
419
+ snprintf(errmsg, sizeof(errmsg), "writeInt32: %s", strerror(errno));
420
+ throw TypeError::New(env, errmsg);
421
+ }
422
+ } else {
423
+ throw TypeError::New(env,
424
+ "writeInt32: Number/String 32-bit value required");
425
+ }
426
+
427
+ if (val < INT32_MIN || val > INT32_MAX) {
428
+ throw TypeError::New(env, "writeInt32: value out of range");
429
+ }
430
+
431
+ *reinterpret_cast<int32_t*>(ptr) = static_cast<int32_t>(val);
432
+ }
433
+
434
+ Value ReadUInt32(const CallbackInfo& args) {
435
+ Env env = args.Env();
436
+ char* ptr = AddressForArgs(args);
437
+
438
+ if (ptr == nullptr) {
439
+ throw TypeError::New(env, "readUInt32: Cannot read from nullptr pointer");
440
+ }
441
+
442
+ uint32_t val = *reinterpret_cast<uint32_t*>(ptr);
443
+ return Number::New(env, val);
444
+ }
445
+
446
+ Value ReadInt8(const CallbackInfo& args) {
447
+ Env env = args.Env();
448
+ char* ptr = AddressForArgs(args);
449
+
450
+ if (ptr == nullptr) {
451
+ throw TypeError::New(env, "readInt8: Cannot read from nullptr pointer");
452
+ }
453
+
454
+ int8_t val = *reinterpret_cast<int8_t*>(ptr);
455
+ return Number::New(env, val);
456
+ }
457
+
458
+ Value ReadUInt8(const CallbackInfo& args) {
459
+ Env env = args.Env();
460
+ char* ptr = AddressForArgs(args);
461
+
462
+ if (ptr == nullptr) {
463
+ throw TypeError::New(env, "readUInt8: Cannot read from nullptr pointer");
464
+ }
465
+
466
+ uint8_t val = *reinterpret_cast<uint8_t*>(ptr);
467
+ return Number::New(env, val);
468
+ }
469
+
470
+ Value ReadFloat(const CallbackInfo& args) {
471
+ Env env = args.Env();
472
+ char* ptr = AddressForArgs(args);
473
+
474
+ if (ptr == nullptr) {
475
+ throw TypeError::New(env, "readFloat: Cannot read from nullptr pointer");
476
+ }
477
+
478
+ float val = *reinterpret_cast<float*>(ptr);
479
+ return Number::New(env, val);
480
+ }
481
+
482
+ Value ReadDouble(const CallbackInfo& args) {
483
+ Env env = args.Env();
484
+ char* ptr = AddressForArgs(args);
485
+
486
+ if (ptr == nullptr) {
487
+ throw TypeError::New(env, "readDouble: Cannot read from nullptr pointer");
488
+ }
489
+
490
+ double val = *reinterpret_cast<double*>(ptr);
491
+ return Number::New(env, val);
492
+ }
493
+
494
+ Value ReadInt16(const CallbackInfo& args) {
495
+ Env env = args.Env();
496
+ char* ptr = AddressForArgs(args);
497
+
498
+ if (ptr == nullptr) {
499
+ throw TypeError::New(env, "readInt16: Cannot read from nullptr pointer");
500
+ }
501
+
502
+ int16_t val = *reinterpret_cast<int16_t*>(ptr);
503
+ return Number::New(env, val);
504
+ }
505
+
506
+ Value ReadUInt16(const CallbackInfo& args) {
507
+ Env env = args.Env();
508
+ char* ptr = AddressForArgs(args);
509
+
510
+ if (ptr == nullptr) {
511
+ throw TypeError::New(env, "readUInt16: Cannot read from nullptr pointer");
512
+ }
513
+
514
+ uint16_t val = *reinterpret_cast<uint16_t*>(ptr);
515
+ return Number::New(env, val);
516
+ }
517
+
518
+ Value ReadUInt64(const CallbackInfo& args) {
519
+ Env env = args.Env();
520
+ char* ptr = AddressForArgs(args);
521
+
522
+ if (ptr == nullptr) {
523
+ throw TypeError::New(env, "readUInt64: Cannot read from nullptr pointer");
524
+ }
525
+
526
+ uint64_t val = *reinterpret_cast<uint64_t*>(ptr);
527
+
528
+ if (val > JS_MAX_INT) {
529
+ char strbuf[128];
530
+ snprintf(strbuf, 128, "%" PRIu64, val);
531
+ return String::New(env, strbuf);
532
+ } else {
533
+ return Number::New(env, val);
534
+ }
535
+ }
536
+
537
+ void WriteUInt64(const CallbackInfo& args) {
538
+ Env env = args.Env();
539
+ char* ptr = AddressForArgs(args);
540
+
541
+ Value in = args[2];
542
+ uint64_t val;
543
+ if (in.IsNumber()) {
544
+ val = static_cast<int64_t>(in.As<Number>());
545
+ } else if (in.IsString()) {
546
+ char* endptr;
547
+ char* str;
548
+ int base = 0;
549
+ std::string _str = in.As<String>();
550
+ str = &_str[0];
551
+
552
+ errno = 0;
553
+ val = strtoull(str, &endptr, base);
554
+
555
+ if (endptr == str) {
556
+ throw TypeError::New(env,
557
+ "writeUInt64: no digits we found in input String");
558
+ } else if (errno == ERANGE && (val == UINT64_MAX)) {
559
+ throw TypeError::New(
560
+ env, "writeUInt64: input String numerical value out of range");
561
+ } else if (errno != 0 && val == 0) {
562
+ char errmsg[200];
563
+ snprintf(errmsg, sizeof(errmsg), "writeUInt64: %s", strerror(errno));
564
+ throw TypeError::New(env, errmsg);
565
+ }
566
+ } else {
567
+ throw TypeError::New(env,
568
+ "writeUInt64: Number/String 64-bit value required");
569
+ }
570
+
571
+ *reinterpret_cast<uint64_t*>(ptr) = val;
572
+ }
573
+
574
+ Value ReadCString(const CallbackInfo& args) {
575
+ Env env = args.Env();
576
+ char* ptr = AddressForArgs(args);
577
+
578
+ if (ptr == nullptr) {
579
+ throw Error::New(env, "readCString: Cannot read from nullptr pointer");
580
+ }
581
+
582
+ return String::New(env, ptr);
583
+ }
584
+
585
+ Value ReinterpretBuffer(const CallbackInfo& args) {
586
+ Env env = args.Env();
587
+ char* ptr = AddressForArgs(args, 2);
588
+
589
+ if (ptr == nullptr) {
590
+ throw Error::New(env,
591
+ "reinterpret: Cannot reinterpret from nullptr pointer");
592
+ }
593
+
594
+ int64_t size = args[1].ToNumber();
595
+
596
+ return CreatePointerBuffer(env, ptr, size);
597
+ }
598
+
599
+ Value ReinterpretBufferUntilZeros(const CallbackInfo& args) {
600
+ Env env = args.Env();
601
+ char* ptr = AddressForArgs(args, 2);
602
+
603
+ if (ptr == nullptr) {
604
+ throw Error::New(
605
+ env, "reinterpretUntilZeros: Cannot reinterpret from nullptr pointer");
606
+ }
607
+
608
+ uint32_t numZeros = args[1].ToNumber();
609
+ uint32_t i = 0;
610
+ size_t size = 0;
611
+ bool end = false;
612
+
613
+ while (!end && size < kMaxLength) {
614
+ end = true;
615
+ for (i = 0; i < numZeros; i++) {
616
+ if (ptr[size + i] != 0) {
617
+ end = false;
618
+ break;
619
+ }
620
+ }
621
+ if (!end) {
622
+ size += numZeros;
623
+ }
624
+ }
625
+
626
+ return CreatePointerBuffer(env, ptr, size);
627
+ }
628
+
629
+ } // namespace
630
+
631
+ Napi::Object InitRefNapi(Napi::Env env) {
632
+ Object exports = Object::New(env);
633
+ InstanceData* data = new InstanceData(env);
634
+ env.SetInstanceData<InstanceData>(data);
635
+
636
+ exports["instance"] = External<RefNapi::Instance>::New(env, data);
637
+
638
+ PointerBuffer::Init(env, exports);
639
+
640
+ Object smap = Object::New(env);
641
+ #define SET_SIZEOF(name, type) smap[#name] = Number::New(env, sizeof(type));
642
+ SET_SIZEOF(int8, int8_t);
643
+ SET_SIZEOF(uint8, uint8_t);
644
+ SET_SIZEOF(int16, int16_t);
645
+ SET_SIZEOF(uint16, uint16_t);
646
+ SET_SIZEOF(int32, int32_t);
647
+ SET_SIZEOF(uint32, uint32_t);
648
+ SET_SIZEOF(int64, int64_t);
649
+ SET_SIZEOF(uint64, uint64_t);
650
+ SET_SIZEOF(float, float);
651
+ SET_SIZEOF(double, double);
652
+ SET_SIZEOF(bool, bool);
653
+ SET_SIZEOF(byte, unsigned char);
654
+ SET_SIZEOF(char, char);
655
+ SET_SIZEOF(uchar, unsigned char);
656
+ SET_SIZEOF(short, short);
657
+ SET_SIZEOF(ushort, unsigned short);
658
+ SET_SIZEOF(int, int);
659
+ SET_SIZEOF(uint, unsigned int);
660
+ SET_SIZEOF(long, long);
661
+ SET_SIZEOF(ulong, unsigned long);
662
+ SET_SIZEOF(longlong, long long);
663
+ SET_SIZEOF(ulonglong, unsigned long long);
664
+ SET_SIZEOF(pointer, char*);
665
+ SET_SIZEOF(size_t, size_t);
666
+ SET_SIZEOF(Object, Reference<Object>);
667
+ #undef SET_SIZEOF
668
+
669
+ Object amap = Object::New(env);
670
+ #define SET_ALIGNOF(name, type) \
671
+ struct s_##name { \
672
+ type a; \
673
+ }; \
674
+ amap[#name] = Number::New(env, alignof(struct s_##name));
675
+ SET_ALIGNOF(int8, int8_t);
676
+ SET_ALIGNOF(uint8, uint8_t);
677
+ SET_ALIGNOF(int16, int16_t);
678
+ SET_ALIGNOF(uint16, uint16_t);
679
+ SET_ALIGNOF(int32, int32_t);
680
+ SET_ALIGNOF(uint32, uint32_t);
681
+ SET_ALIGNOF(int64, int64_t);
682
+ SET_ALIGNOF(uint64, uint64_t);
683
+ SET_ALIGNOF(float, float);
684
+ SET_ALIGNOF(double, double);
685
+ SET_ALIGNOF(bool, bool);
686
+ SET_ALIGNOF(char, char);
687
+ SET_ALIGNOF(uchar, unsigned char);
688
+ SET_ALIGNOF(short, short);
689
+ SET_ALIGNOF(ushort, unsigned short);
690
+ SET_ALIGNOF(int, int);
691
+ SET_ALIGNOF(uint, unsigned int);
692
+ SET_ALIGNOF(long, long);
693
+ SET_ALIGNOF(ulong, unsigned long);
694
+ SET_ALIGNOF(longlong, long long);
695
+ SET_ALIGNOF(ulonglong, unsigned long long);
696
+ SET_ALIGNOF(pointer, char*);
697
+ SET_ALIGNOF(size_t, size_t);
698
+ SET_ALIGNOF(Object, Reference<Object>);
699
+ #undef SET_ALIGNOF
700
+
701
+ exports["sizeof"] = smap;
702
+ exports["alignof"] = amap;
703
+ exports["nullptr"] = exports["NULL"] = CreatePointerBuffer(env, nullptr, 0);
704
+ exports["address"] = Function::New(env, Address);
705
+ exports["hexAddress"] = Function::New(env, HexAddress);
706
+ exports["isNull"] = Function::New(env, IsNull);
707
+ exports["isAddress"] = Function::New(env, IsAddress);
708
+ exports["readObject"] = Function::New(env, ReadObject);
709
+ exports["_writeObject"] = Function::New(env, WriteObject);
710
+ exports["readPointer"] = Function::New(env, ReadPointer);
711
+ exports["_writePointer"] = Function::New(env, WritePointer);
712
+ exports["readInt64"] = Function::New(env, ReadInt64);
713
+ exports["writeInt64"] = Function::New(env, WriteInt64);
714
+ exports["readUInt64"] = Function::New(env, ReadUInt64);
715
+ exports["writeUInt64"] = Function::New(env, WriteUInt64);
716
+
717
+ exports["readInt32"] = Function::New(env, ReadInt32);
718
+ exports["writeInt32"] = Function::New(env, WriteInt32);
719
+
720
+ exports["readUInt32"] = Function::New(env, ReadUInt32);
721
+ exports["readInt8"] = Function::New(env, ReadInt8);
722
+ exports["readUInt8"] = Function::New(env, ReadUInt8);
723
+ exports["readFloat"] = Function::New(env, ReadFloat);
724
+ exports["readDouble"] = Function::New(env, ReadDouble);
725
+ exports["readInt16"] = Function::New(env, ReadInt16);
726
+ exports["readUInt16"] = Function::New(env, ReadUInt16);
727
+
728
+ exports["readCString"] = Function::New(env, ReadCString);
729
+ exports["_reinterpret"] = Function::New(env, ReinterpretBuffer);
730
+ exports["_reinterpretUntilZeros"] =
731
+ Function::New(env, ReinterpretBufferUntilZeros);
732
+
733
+ return exports;
734
+ }
735
+
736
+ } // namespace rclnodejs