use std::ffi::c_char;
use std::fmt::Display;
use std::ops::Deref;
use std::ptr;
use crate::{bindgen_prelude::*, check_status, check_status_and_type, sys};
impl TypeName for String {
fn type_name() -> &'static str {
"String"
}
fn value_type() -> ValueType {
ValueType::String
}
}
impl ValidateNapiValue for String {}
impl ToNapiValue for &String {
unsafe fn to_napi_value(env: sys::napi_env, val: Self) -> Result<sys::napi_value> {
let mut ptr = ptr::null_mut();
check_status!(
unsafe {
sys::napi_create_string_utf8(env, val.as_ptr().cast(), val.len() as isize, &mut ptr)
},
"Failed to convert rust `String` into napi `string`"
)?;
Ok(ptr)
}
}
impl ToNapiValue for String {
#[inline]
unsafe fn to_napi_value(env: sys::napi_env, val: Self) -> Result<sys::napi_value> {
#[allow(clippy::needless_borrows_for_generic_args)]
unsafe {
ToNapiValue::to_napi_value(env, &val)
}
}
}
impl FromNapiValue for String {
unsafe fn from_napi_value(env: sys::napi_env, napi_val: sys::napi_value) -> Result<Self> {
let mut len = 0;
check_status_and_type!(
unsafe { sys::napi_get_value_string_utf8(env, napi_val, ptr::null_mut(), 0, &mut len) },
env,
napi_val,
"Failed to convert JavaScript value `{}` into rust type `String`"
)?;
len += 1;
let mut ret: Vec<u8> = vec![0; len];
let mut written_char_count = 0;
check_status_and_type!(
unsafe {
sys::napi_get_value_string_utf8(
env,
napi_val,
ret.as_mut_ptr().cast(),
len,
&mut written_char_count,
)
},
env,
napi_val,
"Failed to convert napi `{}` into rust type `String`"
)?;
ret.truncate(written_char_count);
Ok(unsafe { String::from_utf8_unchecked(ret) })
}
}
impl ToNapiValue for &str {
unsafe fn to_napi_value(env: sys::napi_env, val: Self) -> Result<sys::napi_value> {
let mut ptr = ptr::null_mut();
check_status!(
unsafe {
sys::napi_create_string_utf8(env, val.as_ptr().cast(), val.len() as isize, &mut ptr)
},
"Failed to convert rust `&str` into napi `string`"
)?;
Ok(ptr)
}
}
#[derive(Debug)]
pub struct Utf16String(Vec<u16>);
impl ValidateNapiValue for Utf16String {}
impl From<String> for Utf16String {
fn from(s: String) -> Self {
Utf16String(s.encode_utf16().collect())
}
}
impl Display for Utf16String {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", String::from_utf16_lossy(self))
}
}
impl Deref for Utf16String {
type Target = [u16];
fn deref(&self) -> &Self::Target {
self.0.as_ref()
}
}
impl TypeName for Utf16String {
fn type_name() -> &'static str {
"String(utf16)"
}
fn value_type() -> ValueType {
ValueType::String
}
}
impl FromNapiValue for Utf16String {
unsafe fn from_napi_value(env: sys::napi_env, napi_val: sys::napi_value) -> Result<Self> {
let mut len = 0;
check_status!(
unsafe { sys::napi_get_value_string_utf16(env, napi_val, ptr::null_mut(), 0, &mut len) },
"Failed to convert napi `utf16 string` into rust type `String`",
)?;
len += 1;
let mut ret = vec![0; len];
let mut written_char_count = 0;
check_status!(
unsafe {
sys::napi_get_value_string_utf16(
env,
napi_val,
ret.as_mut_ptr(),
len,
&mut written_char_count,
)
},
"Failed to convert napi `utf16 string` into rust type `String`",
)?;
ret.truncate(written_char_count);
Ok(Utf16String(ret))
}
}
impl ToNapiValue for Utf16String {
unsafe fn to_napi_value(env: sys::napi_env, val: Utf16String) -> Result<sys::napi_value> {
let mut ptr = ptr::null_mut();
check_status!(
unsafe {
sys::napi_create_string_utf16(env, val.0.as_ptr().cast(), val.len() as isize, &mut ptr)
},
"Failed to convert napi `string` into rust type `String`"
)?;
Ok(ptr)
}
}
#[derive(Debug)]
pub struct Latin1String(Vec<u8>);
impl ValidateNapiValue for Latin1String {}
impl From<String> for Latin1String {
fn from(s: String) -> Self {
Latin1String(s.into_bytes())
}
}
#[cfg(feature = "latin1")]
impl Display for Latin1String {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let mut dst_slice = vec![0; self.0.len() * 2];
let written =
encoding_rs::mem::convert_latin1_to_utf8(self.0.as_slice(), dst_slice.as_mut_slice());
dst_slice.truncate(written);
write!(f, "{}", unsafe { String::from_utf8_unchecked(dst_slice) })
}
}
impl Deref for Latin1String {
type Target = [u8];
fn deref(&self) -> &Self::Target {
self.0.as_slice()
}
}
impl TypeName for Latin1String {
fn type_name() -> &'static str {
"String(latin1)"
}
fn value_type() -> ValueType {
ValueType::String
}
}
impl FromNapiValue for Latin1String {
unsafe fn from_napi_value(env: sys::napi_env, napi_val: sys::napi_value) -> Result<Self> {
let mut len = 0;
check_status!(
unsafe { sys::napi_get_value_string_latin1(env, napi_val, ptr::null_mut(), 0, &mut len) },
"Failed to convert napi `latin1 string` into rust type `String`",
)?;
len += 1;
let mut buf: Vec<u8> = vec![0; len];
let mut written_char_count = 0;
check_status!(
unsafe {
sys::napi_get_value_string_latin1(
env,
napi_val,
buf.as_mut_ptr().cast(),
len,
&mut written_char_count,
)
},
"Failed to convert napi `latin1 string` into rust type `String`"
)?;
buf.truncate(written_char_count);
Ok(Latin1String(buf))
}
}
impl ToNapiValue for Latin1String {
unsafe fn to_napi_value(env: sys::napi_env, val: Self) -> Result<sys::napi_value> {
let mut ptr = ptr::null_mut();
check_status!(
unsafe {
sys::napi_create_string_latin1(env, val.0.as_ptr().cast(), val.len() as isize, &mut ptr)
},
"Failed to convert rust type `String` into napi `latin1 string`"
)?;
Ok(ptr)
}
}
pub const NAPI_AUTO_LENGTH: isize = -1;
#[derive(Debug)]
pub struct RawCString {
length: isize,
inner: *const c_char,
}
impl RawCString {
pub fn new(inner: *const c_char, length: isize) -> Self {
Self { inner, length }
}
}
impl ToNapiValue for RawCString {
unsafe fn to_napi_value(env: napi_sys::napi_env, val: Self) -> Result<napi_sys::napi_value> {
let mut ptr = ptr::null_mut();
check_status!(
napi_sys::napi_create_string_utf8(env, val.inner, val.length, &mut ptr),
"Failed to convert rust `&str` into napi `string`"
)?;
Ok(ptr)
}
}