nodejs / node-addon-api

Module for using Node-API from C++
MIT License
2.15k stars 460 forks source link

Differentiate an instance of Uint8Array versus Buffer #1522

Closed sudarshan12s closed 3 months ago

sudarshan12s commented 3 months ago

Hi , I had a question on finding the constructor name for an value.

I need to identify if the value passed from JS is an instance of typed array, Uint8Array or Buffer.

napi_instanceof API returns true even for Uint8Array instance and Buffer instance or instance of any class inheriting Uint8Array. Can you help me if there is an equivalent of JS value.constructor.name in napi API's.

Thanks.

NickNaso commented 3 months ago

Hi @sudarshan12s, I think that you can use the following methods:

Hope this will help you.

sudarshan12s commented 3 months ago

Thanks @NickNaso .

I tried these calls by passingnew Uint8Array([23,24]) andBuffer.from("test") from js to napi layer. They return same values . correct me if i missed something.

napi_is_buffer -> true
napi_instanceof("Uint8Array") -> true
napi_get_typedarray_info -> gives type as 1(napi_uint8_array)
napi_is_typedarray -> true
KevinEady commented 3 months ago

@sudarshan12s,

A Buffer will be an instance of Uint8Array, but a Uint8Array will not be an instance of Buffer.

> Buffer.from("test") instanceof Uint8Array
true
> new Uint8Array([23,24]) instanceof Buffer
false

Does using this logic instead help?

You could also do something like:

> Object.getPrototypeOf(new Uint8Array([1,2,3])) === Uint8Array.prototype
true
> Object.getPrototypeOf(new Uint8Array([1,2,3])) === Buffer.prototype
false

Looking at the docs, napi_is_buffer ...

This API checks if the Object passed in is a buffer or Uint8Array. napi_is_typedarray should be preferred if the caller needs to check if the value is a Uint8Array.

... will be true for both Buffers and Uint8Arrays, so I believe your result there is expected.

However, I'm not so sure why napi_is_typedarray is true for a Buffer. From my interpretation of the docs, you would want to use this function to distinguish explicitly between a Uint8Array and something else. I'll try to bring this up at the next Node-API weekly team meeting for some discussion.

sudarshan12s commented 3 months ago

Thanks @KevinEady . I had few more custom instances inheriting Uint8Array. Hence i checked for all such instances (Buffer, custom instances.. ) first and at end i check for Uint8Array. This logic keeps changing though but works.

The getPrototypeOf seems to help me . I tried the following in C layer,

napi_get_named_property(env, global, "Uint8Array",
            &u8val));
 napi_get_prototype(env, invalue, &inpproto) // invalue  is new Uint8Array([1,2,3])
 napi_get_prototype(env, u8val, &u8proto)
napi_strict_equals(env, u8proto, inpproto, &isequal))

but isequal value comes as false..

KevinEady commented 3 months ago

@sudarshan12s ,

Your Node-API snippet is roughly equivalent to:

Object.getPrototypeOf(invalue) === Uint8Array

You need to compare the prototype to Uint8Array.prototype, not Uint8Array:

  napi_value u8val, u8prototypeval, inpproto;
  bool isequal;
  napi_get_named_property(env, global, "Uint8Array", &u8val);
  napi_get_named_property(env, u8val, "prototype", &u8prototypeval);
  napi_get_prototype(env, invalue, &inpproto);
  napi_strict_equals(env, u8prototypeval, inpproto, &isequal);

PS: Make sure you're checking error values returned by the Node-API calls if using the underlying Node-API methods. Using this node-addon-api wrapper will do a lot of that lifting for you.

sudarshan12s commented 3 months ago

Thanks all so much . With the suggested correction . napi_get_prototype works for me..
Yes @KevinEady , I do check for errors. node-addon-api seems for C++ modules . I will make a note of it..

Closing the issue for now..