diff --git a/crates/napi/src/js_values/string/mod.rs b/crates/napi/src/js_values/string/mod.rs index 6e9c1efb..7dd5c626 100644 --- a/crates/napi/src/js_values/string/mod.rs +++ b/crates/napi/src/js_values/string/mod.rs @@ -109,13 +109,11 @@ impl<'env> JsString<'env> { ) })?; - // respect '\0' with js string, for example: `let hello = [a,'\0',b,'\0',c].join('')` - let mut result = mem::ManuallyDrop::new(result); - let buf_ptr = result.as_mut_ptr(); - let bytes = unsafe { std::slice::from_raw_parts(buf_ptr.cast(), written_char_count) }; + mem::forget(result); + Ok(JsStringUtf8 { inner: self, - buf: bytes, + buf: unsafe { Vec::from_raw_parts(buf_ptr.cast(), written_char_count, written_char_count) }, }) } @@ -161,7 +159,9 @@ impl<'env> JsString<'env> { Ok(JsStringLatin1 { inner: self, buf: unsafe { std::slice::from_raw_parts(buf_ptr.cast(), written_char_count) }, - _inner_buf: vec![], + _inner_buf: unsafe { + Vec::from_raw_parts(buf_ptr.cast(), written_char_count, written_char_count) + }, }) } } diff --git a/crates/napi/src/js_values/string/utf8.rs b/crates/napi/src/js_values/string/utf8.rs index 26a623a9..fbc96011 100644 --- a/crates/napi/src/js_values/string/utf8.rs +++ b/crates/napi/src/js_values/string/utf8.rs @@ -1,20 +1,21 @@ use std::convert::TryFrom; use std::str; -use crate::{bindgen_prelude::ToNapiValue, sys, Error, JsString, Result}; +use crate::{bindgen_prelude::ToNapiValue, sys, Error, JsString, Result, Status}; pub struct JsStringUtf8<'env> { pub(crate) inner: JsString<'env>, - pub(crate) buf: &'env [u8], + pub(crate) buf: Vec, } impl<'env> JsStringUtf8<'env> { pub fn as_str(&self) -> Result<&str> { - Ok(unsafe { str::from_utf8_unchecked(self.buf) }) + str::from_utf8(self.buf.as_slice()) + .map_err(|err| Error::new(Status::InvalidArg, err.to_string())) } pub fn as_slice(&self) -> &[u8] { - self.buf + self.buf.as_slice() } pub fn len(&self) -> usize { diff --git a/examples/napi/__tests__/__snapshots__/values.spec.ts.md b/examples/napi/__tests__/__snapshots__/values.spec.ts.md index 7e64e51d..a4411e14 100644 --- a/examples/napi/__tests__/__snapshots__/values.spec.ts.md +++ b/examples/napi/__tests__/__snapshots__/values.spec.ts.md @@ -832,6 +832,8 @@ Generated by [AVA](https://avajs.dev). ␊ export declare function indexSetToRust(set: Set): void␊ ␊ + export declare function intoUtf8(s: string): string␊ + ␊ export declare function jsErrorCallback(value: unknown): Array␊ ␊ /** default enum values are continuos i32s start from 0 */␊ diff --git a/examples/napi/__tests__/__snapshots__/values.spec.ts.snap b/examples/napi/__tests__/__snapshots__/values.spec.ts.snap index 091348ad..e4f34ab8 100644 Binary files a/examples/napi/__tests__/__snapshots__/values.spec.ts.snap and b/examples/napi/__tests__/__snapshots__/values.spec.ts.snap differ diff --git a/examples/napi/__tests__/values.spec.ts b/examples/napi/__tests__/values.spec.ts index 083553d7..0b841cbb 100644 --- a/examples/napi/__tests__/values.spec.ts +++ b/examples/napi/__tests__/values.spec.ts @@ -286,6 +286,7 @@ import { arrayParams, indexSetToRust, indexSetToJs, + intoUtf8, } from '../index.cjs' // import other stuff in `#[napi(module_exports)]` import nativeAddon from '../index.cjs' @@ -337,6 +338,7 @@ test('string', (t) => { t.is(createExternalLatin1String(), 'External Latin1') t.is(createStaticLatin1String(), 'Static Latin1 string') t.is(createStaticUtf16String(), 'Static UTF16') + t.is(intoUtf8('Hello'), 'Hello') }) test('JsStringLatin1::from_external tests', (t) => { diff --git a/examples/napi/example.wasi-browser.js b/examples/napi/example.wasi-browser.js index e41a8511..86c43280 100644 --- a/examples/napi/example.wasi-browser.js +++ b/examples/napi/example.wasi-browser.js @@ -283,6 +283,7 @@ export const i8ArrayToArray = __napiModule.exports.i8ArrayToArray export const indexmapPassthrough = __napiModule.exports.indexmapPassthrough export const indexSetToJs = __napiModule.exports.indexSetToJs export const indexSetToRust = __napiModule.exports.indexSetToRust +export const intoUtf8 = __napiModule.exports.intoUtf8 export const jsErrorCallback = __napiModule.exports.jsErrorCallback export const Kind = __napiModule.exports.Kind export const KindInValidate = __napiModule.exports.KindInValidate diff --git a/examples/napi/example.wasi.cjs b/examples/napi/example.wasi.cjs index f43e40ae..56dfdaf1 100644 --- a/examples/napi/example.wasi.cjs +++ b/examples/napi/example.wasi.cjs @@ -328,6 +328,7 @@ module.exports.i8ArrayToArray = __napiModule.exports.i8ArrayToArray module.exports.indexmapPassthrough = __napiModule.exports.indexmapPassthrough module.exports.indexSetToJs = __napiModule.exports.indexSetToJs module.exports.indexSetToRust = __napiModule.exports.indexSetToRust +module.exports.intoUtf8 = __napiModule.exports.intoUtf8 module.exports.jsErrorCallback = __napiModule.exports.jsErrorCallback module.exports.Kind = __napiModule.exports.Kind module.exports.KindInValidate = __napiModule.exports.KindInValidate diff --git a/examples/napi/index.cjs b/examples/napi/index.cjs index e8835b3f..c01836b5 100644 --- a/examples/napi/index.cjs +++ b/examples/napi/index.cjs @@ -728,6 +728,7 @@ module.exports.i8ArrayToArray = nativeBinding.i8ArrayToArray module.exports.indexmapPassthrough = nativeBinding.indexmapPassthrough module.exports.indexSetToJs = nativeBinding.indexSetToJs module.exports.indexSetToRust = nativeBinding.indexSetToRust +module.exports.intoUtf8 = nativeBinding.intoUtf8 module.exports.jsErrorCallback = nativeBinding.jsErrorCallback module.exports.Kind = nativeBinding.Kind module.exports.KindInValidate = nativeBinding.KindInValidate diff --git a/examples/napi/index.d.cts b/examples/napi/index.d.cts index 62cb28f1..8b377030 100644 --- a/examples/napi/index.d.cts +++ b/examples/napi/index.d.cts @@ -793,6 +793,8 @@ export declare function indexSetToJs(): Set export declare function indexSetToRust(set: Set): void +export declare function intoUtf8(s: string): string + export declare function jsErrorCallback(value: unknown): Array /** default enum values are continuos i32s start from 0 */ diff --git a/examples/napi/src/string.rs b/examples/napi/src/string.rs index e24e4c66..c7daf5b9 100644 --- a/examples/napi/src/string.rs +++ b/examples/napi/src/string.rs @@ -1,4 +1,4 @@ -use napi::{bindgen_prelude::*, JsString, JsStringLatin1, JsStringUtf16}; +use napi::{bindgen_prelude::*, JsString, JsStringLatin1, JsStringUtf16, JsStringUtf8}; #[napi(object)] pub struct Latin1MethodsResult { @@ -40,6 +40,11 @@ pub fn return_c_string() -> RawCString { RawCString::new(mock_c_string_ptr, NAPI_AUTO_LENGTH) } +#[napi] +pub fn into_utf8(s: JsString) -> Result { + s.into_utf8() +} + #[napi] /// Function to test escaped quotes in comments. /// This comment contains escaped quotes: \\"g+sx\\" and should not break JSON parsing.