Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Buffer support #13

Merged
merged 7 commits into from
Jan 6, 2023
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
230 changes: 115 additions & 115 deletions packages/emnapi/include/napi-inl.h
Original file line number Diff line number Diff line change
Expand Up @@ -731,16 +731,16 @@ inline bool Value::IsDataView() const {
return result;
}

// inline bool Value::IsBuffer() const {
// if (IsEmpty()) {
// return false;
// }
inline bool Value::IsBuffer() const {
if (IsEmpty()) {
return false;
}

// bool result;
// napi_status status = napi_is_buffer(_env, _value, &result);
// NAPI_THROW_IF_FAILED(_env, status, false);
// return result;
// }
bool result;
napi_status status = napi_is_buffer(_env, _value, &result);
NAPI_THROW_IF_FAILED(_env, status, false);
return result;
}

inline bool Value::IsExternal() const {
return Type() == napi_external;
Expand Down Expand Up @@ -2427,122 +2427,122 @@ inline Promise::Promise(napi_env env, napi_value value) : Object(env, value) {
// Buffer<T> class
////////////////////////////////////////////////////////////////////////////////

// template <typename T>
// inline Buffer<T> Buffer<T>::New(napi_env env, size_t length) {
// napi_value value;
// void* data;
// napi_status status = napi_create_buffer(env, length * sizeof (T), &data, &value);
// NAPI_THROW_IF_FAILED(env, status, Buffer<T>());
// return Buffer(env, value, length, static_cast<T*>(data));
// }
template <typename T>
inline Buffer<T> Buffer<T>::New(napi_env env, size_t length) {
napi_value value;
void* data;
napi_status status = napi_create_buffer(env, length * sizeof (T), &data, &value);
NAPI_THROW_IF_FAILED(env, status, Buffer<T>());
return Buffer(env, value, length, static_cast<T*>(data));
}

// template <typename T>
// inline Buffer<T> Buffer<T>::New(napi_env env, T* data, size_t length) {
// napi_value value;
// napi_status status = napi_create_external_buffer(
// env, length * sizeof (T), data, nullptr, nullptr, &value);
// NAPI_THROW_IF_FAILED(env, status, Buffer<T>());
// return Buffer(env, value, length, data);
// }
template <typename T>
inline Buffer<T> Buffer<T>::New(napi_env env, T* data, size_t length) {
napi_value value;
napi_status status = napi_create_external_buffer(
env, length * sizeof (T), data, nullptr, nullptr, &value);
NAPI_THROW_IF_FAILED(env, status, Buffer<T>());
return Buffer(env, value, length, data);
}

// template <typename T>
// template <typename Finalizer>
// inline Buffer<T> Buffer<T>::New(napi_env env,
// T* data,
// size_t length,
// Finalizer finalizeCallback) {
// napi_value value;
// details::FinalizeData<T, Finalizer>* finalizeData =
// new details::FinalizeData<T, Finalizer>(
// {std::move(finalizeCallback), nullptr});
// napi_status status = napi_create_external_buffer(
// env,
// length * sizeof (T),
// data,
// details::FinalizeData<T, Finalizer>::Wrapper,
// finalizeData,
// &value);
// if (status != napi_ok) {
// delete finalizeData;
// NAPI_THROW_IF_FAILED(env, status, Buffer());
// }
// return Buffer(env, value, length, data);
// }
template <typename T>
template <typename Finalizer>
inline Buffer<T> Buffer<T>::New(napi_env env,
T* data,
size_t length,
Finalizer finalizeCallback) {
napi_value value;
details::FinalizeData<T, Finalizer>* finalizeData =
new details::FinalizeData<T, Finalizer>(
{std::move(finalizeCallback), nullptr});
napi_status status = napi_create_external_buffer(
env,
length * sizeof (T),
data,
details::FinalizeData<T, Finalizer>::Wrapper,
finalizeData,
&value);
if (status != napi_ok) {
delete finalizeData;
NAPI_THROW_IF_FAILED(env, status, Buffer());
}
return Buffer(env, value, length, data);
}

// template <typename T>
// template <typename Finalizer, typename Hint>
// inline Buffer<T> Buffer<T>::New(napi_env env,
// T* data,
// size_t length,
// Finalizer finalizeCallback,
// Hint* finalizeHint) {
// napi_value value;
// details::FinalizeData<T, Finalizer, Hint>* finalizeData =
// new details::FinalizeData<T, Finalizer, Hint>(
// {std::move(finalizeCallback), finalizeHint});
// napi_status status = napi_create_external_buffer(
// env,
// length * sizeof (T),
// data,
// details::FinalizeData<T, Finalizer, Hint>::WrapperWithHint,
// finalizeData,
// &value);
// if (status != napi_ok) {
// delete finalizeData;
// NAPI_THROW_IF_FAILED(env, status, Buffer());
// }
// return Buffer(env, value, length, data);
// }
template <typename T>
template <typename Finalizer, typename Hint>
inline Buffer<T> Buffer<T>::New(napi_env env,
T* data,
size_t length,
Finalizer finalizeCallback,
Hint* finalizeHint) {
napi_value value;
details::FinalizeData<T, Finalizer, Hint>* finalizeData =
new details::FinalizeData<T, Finalizer, Hint>(
{std::move(finalizeCallback), finalizeHint});
napi_status status = napi_create_external_buffer(
env,
length * sizeof (T),
data,
details::FinalizeData<T, Finalizer, Hint>::WrapperWithHint,
finalizeData,
&value);
if (status != napi_ok) {
delete finalizeData;
NAPI_THROW_IF_FAILED(env, status, Buffer());
}
return Buffer(env, value, length, data);
}

// template <typename T>
// inline Buffer<T> Buffer<T>::Copy(napi_env env, const T* data, size_t length) {
// napi_value value;
// napi_status status = napi_create_buffer_copy(
// env, length * sizeof (T), data, nullptr, &value);
// NAPI_THROW_IF_FAILED(env, status, Buffer<T>());
// return Buffer<T>(env, value);
// }
template <typename T>
inline Buffer<T> Buffer<T>::Copy(napi_env env, const T* data, size_t length) {
napi_value value;
napi_status status = napi_create_buffer_copy(
env, length * sizeof (T), data, nullptr, &value);
NAPI_THROW_IF_FAILED(env, status, Buffer<T>());
return Buffer<T>(env, value);
}

// template <typename T>
// inline Buffer<T>::Buffer() : Uint8Array(), _length(0), _data(nullptr) {
// }
template <typename T>
inline Buffer<T>::Buffer() : Uint8Array(), _length(0), _data(nullptr) {
}

// template <typename T>
// inline Buffer<T>::Buffer(napi_env env, napi_value value)
// : Uint8Array(env, value), _length(0), _data(nullptr) {
// }
template <typename T>
inline Buffer<T>::Buffer(napi_env env, napi_value value)
: Uint8Array(env, value), _length(0), _data(nullptr) {
}

// template <typename T>
// inline Buffer<T>::Buffer(napi_env env, napi_value value, size_t length, T* data)
// : Uint8Array(env, value), _length(length), _data(data) {
// }
template <typename T>
inline Buffer<T>::Buffer(napi_env env, napi_value value, size_t length, T* data)
: Uint8Array(env, value), _length(length), _data(data) {
}

// template <typename T>
// inline size_t Buffer<T>::Length() const {
// EnsureInfo();
// return _length;
// }
template <typename T>
inline size_t Buffer<T>::Length() const {
EnsureInfo();
return _length;
}

// template <typename T>
// inline T* Buffer<T>::Data() const {
// EnsureInfo();
// return _data;
// }
template <typename T>
inline T* Buffer<T>::Data() const {
EnsureInfo();
return _data;
}

// template <typename T>
// inline void Buffer<T>::EnsureInfo() const {
// // The Buffer instance may have been constructed from a napi_value whose
// // length/data are not yet known. Fetch and cache these values just once,
// // since they can never change during the lifetime of the Buffer.
// if (_data == nullptr) {
// size_t byteLength;
// void* voidData;
// napi_status status = napi_get_buffer_info(_env, _value, &voidData, &byteLength);
// NAPI_THROW_IF_FAILED_VOID(_env, status);
// _length = byteLength / sizeof (T);
// _data = static_cast<T*>(voidData);
// }
// }
template <typename T>
inline void Buffer<T>::EnsureInfo() const {
// The Buffer instance may have been constructed from a napi_value whose
// length/data are not yet known. Fetch and cache these values just once,
// since they can never change during the lifetime of the Buffer.
if (_data == nullptr) {
size_t byteLength;
void* voidData;
napi_status status = napi_get_buffer_info(_env, _value, &voidData, &byteLength);
NAPI_THROW_IF_FAILED_VOID(_env, status);
_length = byteLength / sizeof (T);
_data = static_cast<T*>(voidData);
}
}

////////////////////////////////////////////////////////////////////////////////
// Error class
Expand Down
61 changes: 31 additions & 30 deletions packages/emnapi/include/napi.h
Original file line number Diff line number Diff line change
Expand Up @@ -434,6 +434,7 @@ namespace NAPI_CPP_CUSTOM_NAMESPACE {
bool IsArray() const; ///< Tests if a value is a JavaScript array.
bool IsArrayBuffer() const; ///< Tests if a value is a JavaScript array buffer.
bool IsTypedArray() const; ///< Tests if a value is a JavaScript typed array.
bool IsBuffer() const; ///< Tests if a value is a Node buffer.
bool IsObject() const; ///< Tests if a value is a JavaScript object.
bool IsFunction() const; ///< Tests if a value is a JavaScript function.
bool IsPromise() const; ///< Tests if a value is a JavaScript promise.
Expand Down Expand Up @@ -1414,38 +1415,38 @@ namespace NAPI_CPP_CUSTOM_NAMESPACE {
Promise(napi_env env, napi_value value);
};

// template <typename T>
// class Buffer : public Uint8Array {
// public:
// static Buffer<T> New(napi_env env, size_t length);
// static Buffer<T> New(napi_env env, T* data, size_t length);

// // Finalizer must implement `void operator()(Env env, T* data)`.
// template <typename Finalizer>
// static Buffer<T> New(napi_env env, T* data,
// size_t length,
// Finalizer finalizeCallback);
// // Finalizer must implement `void operator()(Env env, T* data, Hint* hint)`.
// template <typename Finalizer, typename Hint>
// static Buffer<T> New(napi_env env, T* data,
// size_t length,
// Finalizer finalizeCallback,
// Hint* finalizeHint);

// static Buffer<T> Copy(napi_env env, const T* data, size_t length);

// Buffer();
// Buffer(napi_env env, napi_value value);
// size_t Length() const;
// T* Data() const;
template <typename T>
class Buffer : public Uint8Array {
public:
static Buffer<T> New(napi_env env, size_t length);
static Buffer<T> New(napi_env env, T* data, size_t length);

// Finalizer must implement `void operator()(Env env, T* data)`.
template <typename Finalizer>
static Buffer<T> New(napi_env env, T* data,
size_t length,
Finalizer finalizeCallback);
// Finalizer must implement `void operator()(Env env, T* data, Hint* hint)`.
template <typename Finalizer, typename Hint>
static Buffer<T> New(napi_env env, T* data,
size_t length,
Finalizer finalizeCallback,
Hint* finalizeHint);

static Buffer<T> Copy(napi_env env, const T* data, size_t length);

Buffer();
Buffer(napi_env env, napi_value value);
size_t Length() const;
T* Data() const;

// private:
// mutable size_t _length;
// mutable T* _data;
private:
mutable size_t _length;
mutable T* _data;

// Buffer(napi_env env, napi_value value, size_t length, T* data);
// void EnsureInfo() const;
// };
Buffer(napi_env env, napi_value value, size_t length, T* data);
void EnsureInfo() const;
};

/// Holds a counted reference to a value; initially a weak reference unless otherwise specified,
/// may be changed to/from a strong reference by adjusting the refcount.
Expand Down
35 changes: 35 additions & 0 deletions packages/emnapi/include/node_api.h
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,41 @@ napi_ref_threadsafe_function(napi_env env, napi_threadsafe_function func);

#endif

// Methods to provide node::Buffer functionality with napi types
NAPI_EXTERN napi_status
napi_create_buffer(napi_env env,
size_t length,
void** data,
napi_value* result);

#ifndef NODE_API_NO_EXTERNAL_BUFFERS_ALLOWED
NAPI_EXTERN napi_status
napi_create_external_buffer(napi_env env,
size_t length,
void* data,
napi_finalize finalize_cb,
void* finalize_hint,
napi_value* result);
#endif // NODE_API_NO_EXTERNAL_BUFFERS_ALLOWED

NAPI_EXTERN napi_status
napi_create_buffer_copy(napi_env env,
size_t length,
const void* data,
void** result_data,
napi_value* result);

NAPI_EXTERN napi_status
napi_is_buffer(napi_env env,
napi_value value,
bool* result);

NAPI_EXTERN napi_status
napi_get_buffer_info(napi_env env,
napi_value value,
void** data,
size_t* length);

#endif

EXTERN_C_END
Expand Down
12 changes: 12 additions & 0 deletions packages/emnapi/src/value-operation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -188,6 +188,17 @@ function napi_is_typedarray (env: napi_env, value: napi_value, result: Pointer<b
return envObject.clearLastError()
}

function napi_is_buffer(env: napi_env, value: napi_value, result: Pointer<bool>): napi_status {
$CHECK_ENV!(env)
const envObject = emnapiCtx.envStore.get(env)!
$CHECK_ARG!(envObject, value)
$CHECK_ARG!(envObject, result)
const h = emnapiCtx.handleStore.get(value)!
$from64('result')
HEAPU8[result] = h.isBuffer() ? 1 : 0
return envObject.clearLastError()
}

function napi_is_dataview (env: napi_env, value: napi_value, result: Pointer<bool>): napi_status {
$CHECK_ENV!(env)
const envObject = emnapiCtx.envStore.get(env)!
Expand Down Expand Up @@ -267,6 +278,7 @@ emnapiImplement('napi_is_arraybuffer', 'ippp', napi_is_arraybuffer)
emnapiImplement('napi_is_date', 'ippp', napi_is_date)
emnapiImplement('napi_is_error', 'ippp', napi_is_error)
emnapiImplement('napi_is_typedarray', 'ippp', napi_is_typedarray)
emnapiImplement('napi_is_buffer', 'ippp', napi_is_buffer)
emnapiImplement('napi_is_dataview', 'ippp', napi_is_dataview)
emnapiImplement('napi_strict_equals', 'ipppp', napi_strict_equals)
emnapiImplement('napi_detach_arraybuffer', 'ipp', napi_detach_arraybuffer, ['napi_set_last_error'])
Expand Down
Loading