Skip to content

Commit

Permalink
implement external strings (#68)
Browse files Browse the repository at this point in the history
  • Loading branch information
toyobayashi authored Jun 14, 2023
1 parent ed02fc9 commit 8452af7
Show file tree
Hide file tree
Showing 7 changed files with 486 additions and 231 deletions.
18 changes: 18 additions & 0 deletions packages/emnapi/include/js_native_api.h
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,24 @@ NAPI_EXTERN napi_status NAPI_CDECL napi_create_string_utf16(napi_env env,
const char16_t* str,
size_t length,
napi_value* result);
#ifdef NAPI_EXPERIMENTAL
NAPI_EXTERN napi_status NAPI_CDECL
node_api_create_external_string_latin1(napi_env env,
char* str,
size_t length,
napi_finalize finalize_callback,
void* finalize_hint,
napi_value* result,
bool* copied);
NAPI_EXTERN napi_status NAPI_CDECL
node_api_create_external_string_utf16(napi_env env,
char16_t* str,
size_t length,
napi_finalize finalize_callback,
void* finalize_hint,
napi_value* result,
bool* copied);
#endif // NAPI_EXPERIMENTAL
NAPI_EXTERN napi_status NAPI_CDECL napi_create_symbol(napi_env env,
napi_value description,
napi_value* result);
Expand Down
50 changes: 50 additions & 0 deletions packages/emnapi/src/string.ts
Original file line number Diff line number Diff line change
Expand Up @@ -232,6 +232,56 @@ var emnapiString = {
}
$makeSetValue('outPtr', 0, '0', 'i16')
return outPtr - startPtr
},
newString (env: napi_env,
str: number,
length: size_t,
result: Pointer<napi_value>,
stringMaker: (autoLength: boolean, sizeLength: number) => string
) {
$CHECK_ENV!(env)
const envObject = emnapiCtx.envStore.get(env)!
$from64('length')
const autoLength = length === -1
const sizelength = length >>> 0
if (length !== 0) {
$CHECK_ARG!(envObject, str)
}
$CHECK_ARG!(envObject, result)
$from64('str')

if (!(autoLength || (sizelength <= 2147483647))) {
return envObject.setLastError(napi_status.napi_invalid_arg)
}
const strValue = stringMaker(autoLength, sizelength)
$from64('result')
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const value = emnapiCtx.addToCurrentScope(strValue).id
$makeSetValue('result', 0, 'value', '*')
return envObject.clearLastError()
},
newExternalString (
env: napi_env,
str: number,
length: size_t,
finalize_callback: napi_finalize,
finalize_hint: void_p,
result: Pointer<napi_value>,
copied: Pointer<bool>,
createApi: (env: napi_env, str: number, length: size_t, result: Pointer<napi_value>) => napi_status,
stringMaker: (autoLength: boolean, sizeLength: number) => string
) {
const status = createApi(env, str, length, result)
if (status === napi_status.napi_ok) {
if (copied) {
$makeSetValue('copied', 0, '1', 'i8')
}
if (finalize_callback) {
const envObject = emnapiCtx.envStore.get(env)!
envObject.callFinalizer(finalize_callback, str, finalize_hint)
}
}
return status
}
}

Expand Down
157 changes: 75 additions & 82 deletions packages/emnapi/src/value/convert2napi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,91 +57,84 @@ function napi_create_double (env: napi_env, value: double, result: Pointer<napi_
return envObject.clearLastError()
}

function napi_create_string_latin1 (env: napi_env, str: const_char_p, length: size_t, result: Pointer<napi_value>): napi_status {
$CHECK_ENV!(env)
const envObject = emnapiCtx.envStore.get(env)!
$from64('length')
const autoLength = length === -1
length = length >>> 0
if (length !== 0) {
$CHECK_ARG!(envObject, str)
}
$CHECK_ARG!(envObject, result)
$from64('str')
if (!(autoLength || (length <= 2147483647))) {
return envObject.setLastError(napi_status.napi_invalid_arg)
}

let latin1String = ''
let len = 0
if (autoLength) {
while (true) {
const ch = $makeGetValue('str', 0, 'u8') as number
if (!ch) break
latin1String += String.fromCharCode(ch)
str++
}
} else {
while (len < length) {
const ch = $makeGetValue('str', 0, 'u8') as number
if (!ch) break
latin1String += String.fromCharCode(ch)
len++
str++
function _napi_create_string_latin1 (env: napi_env, str: const_char_p, length: size_t, result: Pointer<napi_value>): napi_status {
return emnapiString.newString(env, str, length, result, (autoLength, sizeLength) => {
let latin1String = ''
let len = 0
if (autoLength) {
while (true) {
const ch = $makeGetValue('str', 0, 'u8') as number
if (!ch) break
latin1String += String.fromCharCode(ch)
str++
}
} else {
while (len < sizeLength) {
const ch = $makeGetValue('str', 0, 'u8') as number
if (!ch) break
latin1String += String.fromCharCode(ch)
len++
str++
}
}
}
$from64('result')
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const value = emnapiCtx.addToCurrentScope(latin1String).id
$makeSetValue('result', 0, 'value', '*')
return envObject.clearLastError()
return latin1String
})
}

function napi_create_string_utf16 (env: napi_env, str: const_char16_t_p, length: size_t, result: Pointer<napi_value>): napi_status {
$CHECK_ENV!(env)
const envObject = emnapiCtx.envStore.get(env)!
$from64('length')
const autoLength = length === -1
const sizelength = length >>> 0
if (length !== 0) {
$CHECK_ARG!(envObject, str)
}
$CHECK_ARG!(envObject, result)
$from64('str')

if (!(autoLength || (sizelength <= 2147483647))) {
return envObject.setLastError(napi_status.napi_invalid_arg)
}

const utf16String = emnapiString.UTF16ToString(str, length)
$from64('result')
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const value = emnapiCtx.addToCurrentScope(utf16String).id
$makeSetValue('result', 0, 'value', '*')
return envObject.clearLastError()
function _napi_create_string_utf16 (env: napi_env, str: const_char16_t_p, length: size_t, result: Pointer<napi_value>): napi_status {
return emnapiString.newString(env, str, length, result, () => {
return emnapiString.UTF16ToString(str, length)
})
}

function napi_create_string_utf8 (env: napi_env, str: const_char_p, length: size_t, result: Pointer<napi_value>): napi_status {
$CHECK_ENV!(env)
const envObject = emnapiCtx.envStore.get(env)!
$from64('length')
const autoLength = length === -1
const sizelength = length >>> 0
if (length !== 0) {
$CHECK_ARG!(envObject, str)
}
$CHECK_ARG!(envObject, result)
$from64('str')
return emnapiString.newString(env, str, length, result, () => {
return emnapiString.UTF8ToString(str, length)
})
}

if (!(autoLength || (sizelength <= 2147483647))) {
return envObject.setLastError(napi_status.napi_invalid_arg)
}
const utf8String = emnapiString.UTF8ToString(str, length)
$from64('result')
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const value = emnapiCtx.addToCurrentScope(utf8String).id
$makeSetValue('result', 0, 'value', '*')
return envObject.clearLastError()
function node_api_create_external_string_latin1 (
env: napi_env,
str: number,
length: size_t,
finalize_callback: napi_finalize,
finalize_hint: void_p,
result: Pointer<napi_value>,
copied: Pointer<bool>
): napi_status {
return emnapiString.newExternalString(
env,
str,
length,
finalize_callback,
finalize_hint,
result,
copied,
_napi_create_string_latin1,
undefined!
)
}

function node_api_create_external_string_utf16 (
env: napi_env,
str: number,
length: size_t,
finalize_callback: napi_finalize,
finalize_hint: void_p,
result: Pointer<napi_value>,
copied: Pointer<bool>
): napi_status {
return emnapiString.newExternalString(
env,
str,
length,
finalize_callback,
finalize_hint,
result,
copied,
_napi_create_string_utf16,
undefined!
)
}

function napi_create_bigint_int64 (env: napi_env, low: int32_t, high: int32_t, result: Pointer<napi_value>): napi_status {
Expand Down Expand Up @@ -241,8 +234,8 @@ emnapiImplement('napi_create_double', 'ipdp', napi_create_double)
emnapiImplement('napi_create_bigint_int64', 'ipjp', napi_create_bigint_int64)
emnapiImplement('napi_create_bigint_uint64', 'ipjp', napi_create_bigint_uint64)
emnapiImplement('napi_create_bigint_words', 'ipippp', napi_create_bigint_words)
emnapiImplement('napi_create_string_latin1', 'ipppp', napi_create_string_latin1)

emnapiImplement('napi_create_string_utf16', 'ipppp', napi_create_string_utf16, ['$emnapiString'])

emnapiImplement('napi_create_string_latin1', 'ipppp', _napi_create_string_latin1, ['$emnapiString'])
emnapiImplement('napi_create_string_utf16', 'ipppp', _napi_create_string_utf16, ['$emnapiString'])
emnapiImplement('napi_create_string_utf8', 'ipppp', napi_create_string_utf8, ['$emnapiString'])
emnapiImplement('node_api_create_external_string_latin1', 'ippppppp', node_api_create_external_string_latin1, ['$emnapiString', 'napi_create_string_latin1'])
emnapiImplement('node_api_create_external_string_utf16', 'ippppppp', node_api_create_external_string_utf16, ['$emnapiString', 'napi_create_string_utf16'])
11 changes: 11 additions & 0 deletions packages/test/common.h
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,17 @@
#define NAPI_CALL_RETURN_VOID(env, the_call) \
NAPI_CALL_BASE(env, the_call, NAPI_RETVAL_NOTHING)

#define NAPI_CHECK_STATUS(the_call) \
do { \
napi_status status = (the_call); \
if (status != napi_ok) { \
return status; \
} \
} while (0)

#define NAPI_ASSERT_STATUS(env, assertion, message) \
NAPI_ASSERT_BASE(env, assertion, message, napi_generic_failure)

#define DECLARE_NAPI_PROPERTY(name, func) \
{ (name), NULL, (func), NULL, NULL, NULL, napi_default, NULL }

Expand Down
21 changes: 5 additions & 16 deletions packages/test/ref_by_node_api_version/binding.c
Original file line number Diff line number Diff line change
Expand Up @@ -7,17 +7,6 @@ void* malloc(size_t size);
void free(void* p);
#endif

#define NAPI_ASSERT_STATUS(env, assertion, message) \
NAPI_ASSERT_BASE(env, assertion, message, napi_generic_failure)

#define NAPI_CHECK_STATUS(env, the_call) \
do { \
napi_status status = (the_call); \
if (status != napi_ok) { \
return status; \
} \
} while (0)

static uint32_t finalizeCount = 0;

static void FreeData(napi_env env, void* data, void* hint) {
Expand All @@ -34,7 +23,7 @@ static napi_status GetArgValue(napi_env env,
napi_value* argValue) {
size_t argc = 1;
NAPI_CHECK_STATUS(
env, napi_get_cb_info(env, info, &argc, argValue, NULL, NULL));
napi_get_cb_info(env, info, &argc, argValue, NULL, NULL));

NAPI_ASSERT_STATUS(env, argc == 1, "Expects one arg.");
return napi_ok;
Expand All @@ -44,10 +33,10 @@ static napi_status GetArgValueAsIndex(napi_env env,
napi_callback_info info,
uint32_t* index) {
napi_value argValue;
NAPI_CHECK_STATUS(env, GetArgValue(env, info, &argValue));
NAPI_CHECK_STATUS(GetArgValue(env, info, &argValue));

napi_valuetype valueType;
NAPI_CHECK_STATUS(env, napi_typeof(env, argValue, &valueType));
NAPI_CHECK_STATUS(napi_typeof(env, argValue, &valueType));
NAPI_ASSERT_STATUS(
env, valueType == napi_number, "Argument must be a number.");

Expand All @@ -58,10 +47,10 @@ static napi_status GetRef(napi_env env,
napi_callback_info info,
napi_ref* ref) {
uint32_t index;
NAPI_CHECK_STATUS(env, GetArgValueAsIndex(env, info, &index));
NAPI_CHECK_STATUS(GetArgValueAsIndex(env, info, &index));

napi_ref* refValues;
NAPI_CHECK_STATUS(env, napi_get_instance_data(env, (void**)&refValues));
NAPI_CHECK_STATUS(napi_get_instance_data(env, (void**)&refValues));
NAPI_ASSERT_STATUS(env, refValues != NULL, "Cannot get instance data.");

*ref = refValues[index];
Expand Down
Loading

0 comments on commit 8452af7

Please sign in to comment.