use std::marker::PhantomData;
use std::mem;
use std::ptr;
use crate::{
bindgen_runtime::{FromNapiValue, ToNapiValue, TypeName, ValidateNapiValue},
check_status, sys, Result, Value, ValueType,
};
pub use latin1::JsStringLatin1;
pub use utf16::JsStringUtf16;
pub use utf8::JsStringUtf8;
use super::JsValue;
mod latin1;
mod utf16;
mod utf8;
#[derive(Clone, Copy)]
pub struct JsString<'env>(pub(crate) Value, pub(crate) PhantomData<&'env ()>);
impl TypeName for JsString<'_> {
fn type_name() -> &'static str {
"String"
}
fn value_type() -> crate::ValueType {
ValueType::String
}
}
impl ValidateNapiValue for JsString<'_> {}
impl<'env> JsValue<'env> for JsString<'env> {
fn value(&self) -> Value {
self.0
}
}
impl FromNapiValue for JsString<'_> {
unsafe fn from_napi_value(env: sys::napi_env, napi_val: sys::napi_value) -> Result<Self> {
Ok(JsString(
Value {
env,
value: napi_val,
value_type: ValueType::String,
},
PhantomData,
))
}
}
impl ToNapiValue for &JsString<'_> {
unsafe fn to_napi_value(_env: sys::napi_env, val: Self) -> Result<sys::napi_value> {
Ok(val.raw())
}
}
impl<'env> JsString<'env> {
#[cfg(feature = "serde-json")]
pub(crate) fn from_raw(env: sys::napi_env, value: sys::napi_value) -> Self {
JsString(
Value {
env,
value,
value_type: ValueType::String,
},
PhantomData,
)
}
pub fn utf8_len(&self) -> Result<usize> {
let mut length = 0;
check_status!(unsafe {
sys::napi_get_value_string_utf8(self.0.env, self.0.value, ptr::null_mut(), 0, &mut length)
})?;
Ok(length)
}
pub fn utf16_len(&self) -> Result<usize> {
let mut length = 0;
check_status!(unsafe {
sys::napi_get_value_string_utf16(self.0.env, self.0.value, ptr::null_mut(), 0, &mut length)
})?;
Ok(length)
}
pub fn latin1_len(&self) -> Result<usize> {
let mut length = 0;
check_status!(unsafe {
sys::napi_get_value_string_latin1(self.0.env, self.0.value, ptr::null_mut(), 0, &mut length)
})?;
Ok(length)
}
pub fn into_utf8(self) -> Result<JsStringUtf8<'env>> {
let mut written_char_count = 0;
let len = self.utf8_len()? + 1;
let mut result = vec![0; len];
let buf_ptr = result.as_mut_ptr();
check_status!(unsafe {
sys::napi_get_value_string_utf8(
self.0.env,
self.0.value,
buf_ptr,
len,
&mut written_char_count,
)
})?;
mem::forget(result);
Ok(JsStringUtf8 {
inner: self,
buf: unsafe { Vec::from_raw_parts(buf_ptr.cast(), written_char_count, len) },
})
}
pub fn into_utf16(self) -> Result<JsStringUtf16<'env>> {
let mut written_char_count = 0usize;
let len = self.utf16_len()? + 1;
let mut result = vec![0; len];
let buf_ptr = result.as_mut_ptr();
check_status!(unsafe {
sys::napi_get_value_string_utf16(
self.0.env,
self.0.value,
buf_ptr,
len,
&mut written_char_count,
)
})?;
Ok(JsStringUtf16 {
inner: self,
buf: unsafe { std::slice::from_raw_parts(buf_ptr.cast(), len) },
_inner_buf: result,
})
}
pub fn into_latin1(self) -> Result<JsStringLatin1<'env>> {
let mut written_char_count = 0usize;
let len = self.latin1_len()? + 1;
let mut result = vec![0; len];
let buf_ptr = result.as_mut_ptr();
check_status!(unsafe {
sys::napi_get_value_string_latin1(
self.0.env,
self.0.value,
buf_ptr,
len,
&mut written_char_count,
)
})?;
mem::forget(result);
Ok(JsStringLatin1 {
inner: self,
buf: unsafe { std::slice::from_raw_parts(buf_ptr.cast(), written_char_count) },
_inner_buf: unsafe { Vec::from_raw_parts(buf_ptr.cast(), written_char_count, len) },
})
}
}