napi/bindgen_runtime/js_values/
string.rs1use std::ffi::c_char;
2use std::fmt::Display;
3use std::ops::Deref;
4use std::ptr;
5
6use crate::{bindgen_prelude::*, check_status, check_status_and_type, sys};
7
8impl TypeName for String {
9 fn type_name() -> &'static str {
10 "String"
11 }
12
13 fn value_type() -> ValueType {
14 ValueType::String
15 }
16}
17
18impl ValidateNapiValue for String {}
19
20impl ToNapiValue for &String {
21 unsafe fn to_napi_value(env: sys::napi_env, val: Self) -> Result<sys::napi_value> {
22 let mut ptr = ptr::null_mut();
23
24 check_status!(
25 unsafe {
26 sys::napi_create_string_utf8(env, val.as_ptr().cast(), val.len() as isize, &mut ptr)
27 },
28 "Failed to convert rust `String` into napi `string`"
29 )?;
30
31 Ok(ptr)
32 }
33}
34
35impl ToNapiValue for &mut String {
36 unsafe fn to_napi_value(env: sys::napi_env, val: Self) -> Result<sys::napi_value> {
37 ToNapiValue::to_napi_value(env, &*val)
38 }
39}
40
41impl ToNapiValue for String {
42 #[inline]
43 unsafe fn to_napi_value(env: sys::napi_env, val: Self) -> Result<sys::napi_value> {
44 #[allow(clippy::needless_borrows_for_generic_args)]
45 unsafe {
46 ToNapiValue::to_napi_value(env, &val)
47 }
48 }
49}
50
51impl FromNapiValue for String {
52 unsafe fn from_napi_value(env: sys::napi_env, napi_val: sys::napi_value) -> Result<Self> {
53 let mut len = 0;
54
55 check_status_and_type!(
56 unsafe { sys::napi_get_value_string_utf8(env, napi_val, ptr::null_mut(), 0, &mut len) },
57 env,
58 napi_val,
59 "Failed to convert JavaScript value `{}` into rust type `String`"
60 )?;
61
62 len += 1;
64 let mut ret: Vec<u8> = vec![0; len];
65
66 let mut written_char_count = 0;
67
68 check_status_and_type!(
69 unsafe {
70 sys::napi_get_value_string_utf8(
71 env,
72 napi_val,
73 ret.as_mut_ptr().cast(),
74 len,
75 &mut written_char_count,
76 )
77 },
78 env,
79 napi_val,
80 "Failed to convert napi `{}` into rust type `String`"
81 )?;
82
83 ret.truncate(written_char_count);
84
85 Ok(unsafe { String::from_utf8_unchecked(ret) })
86 }
87}
88
89impl ToNapiValue for &str {
90 unsafe fn to_napi_value(env: sys::napi_env, val: Self) -> Result<sys::napi_value> {
91 let mut ptr = ptr::null_mut();
92
93 check_status!(
94 unsafe {
95 sys::napi_create_string_utf8(env, val.as_ptr().cast(), val.len() as isize, &mut ptr)
96 },
97 "Failed to convert rust `&str` into napi `string`"
98 )?;
99
100 Ok(ptr)
101 }
102}
103
104#[derive(Debug)]
105pub struct Utf16String(Vec<u16>);
106
107impl ValidateNapiValue for Utf16String {}
108
109impl From<String> for Utf16String {
110 fn from(s: String) -> Self {
111 Utf16String(s.encode_utf16().collect())
112 }
113}
114
115impl Display for Utf16String {
116 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
117 write!(f, "{}", String::from_utf16_lossy(self))
118 }
119}
120
121impl Deref for Utf16String {
122 type Target = [u16];
123
124 fn deref(&self) -> &Self::Target {
125 self.0.as_ref()
126 }
127}
128
129impl TypeName for Utf16String {
130 fn type_name() -> &'static str {
131 "String(utf16)"
132 }
133
134 fn value_type() -> ValueType {
135 ValueType::String
136 }
137}
138
139impl FromNapiValue for Utf16String {
140 unsafe fn from_napi_value(env: sys::napi_env, napi_val: sys::napi_value) -> Result<Self> {
141 let mut len = 0;
142
143 check_status!(
144 unsafe { sys::napi_get_value_string_utf16(env, napi_val, ptr::null_mut(), 0, &mut len) },
145 "Failed to convert napi `utf16 string` into rust type `String`",
146 )?;
147
148 len += 1;
150 let mut ret = vec![0; len];
151 let mut written_char_count = 0;
152
153 check_status!(
154 unsafe {
155 sys::napi_get_value_string_utf16(
156 env,
157 napi_val,
158 ret.as_mut_ptr(),
159 len,
160 &mut written_char_count,
161 )
162 },
163 "Failed to convert napi `utf16 string` into rust type `String`",
164 )?;
165
166 ret.truncate(written_char_count);
167
168 Ok(Utf16String(ret))
169 }
170}
171
172impl ToNapiValue for Utf16String {
173 unsafe fn to_napi_value(env: sys::napi_env, val: Utf16String) -> Result<sys::napi_value> {
174 let mut ptr = ptr::null_mut();
175
176 check_status!(
177 unsafe {
178 sys::napi_create_string_utf16(env, val.0.as_ptr().cast(), val.len() as isize, &mut ptr)
179 },
180 "Failed to convert napi `string` into rust type `String`"
181 )?;
182
183 Ok(ptr)
184 }
185}
186
187#[derive(Debug)]
188pub struct Latin1String(Vec<u8>);
189
190impl ValidateNapiValue for Latin1String {}
191
192impl From<String> for Latin1String {
193 fn from(s: String) -> Self {
194 Latin1String(s.into_bytes())
195 }
196}
197
198#[cfg(feature = "latin1")]
199impl Display for Latin1String {
200 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
201 let mut dst_slice = vec![0; self.0.len() * 2];
202 let written =
203 encoding_rs::mem::convert_latin1_to_utf8(self.0.as_slice(), dst_slice.as_mut_slice());
204 dst_slice.truncate(written);
205 write!(f, "{}", unsafe { String::from_utf8_unchecked(dst_slice) })
206 }
207}
208
209impl Deref for Latin1String {
210 type Target = [u8];
211
212 fn deref(&self) -> &Self::Target {
213 self.0.as_slice()
214 }
215}
216
217impl TypeName for Latin1String {
218 fn type_name() -> &'static str {
219 "String(latin1)"
220 }
221
222 fn value_type() -> ValueType {
223 ValueType::String
224 }
225}
226
227impl FromNapiValue for Latin1String {
228 unsafe fn from_napi_value(env: sys::napi_env, napi_val: sys::napi_value) -> Result<Self> {
229 let mut len = 0;
230
231 check_status!(
232 unsafe { sys::napi_get_value_string_latin1(env, napi_val, ptr::null_mut(), 0, &mut len) },
233 "Failed to convert napi `latin1 string` into rust type `String`",
234 )?;
235
236 len += 1;
238 let mut buf: Vec<u8> = vec![0; len];
239
240 let mut written_char_count = 0;
241
242 check_status!(
243 unsafe {
244 sys::napi_get_value_string_latin1(
245 env,
246 napi_val,
247 buf.as_mut_ptr().cast(),
248 len,
249 &mut written_char_count,
250 )
251 },
252 "Failed to convert napi `latin1 string` into rust type `String`"
253 )?;
254 buf.truncate(written_char_count);
255 Ok(Latin1String(buf))
256 }
257}
258
259impl ToNapiValue for Latin1String {
260 unsafe fn to_napi_value(env: sys::napi_env, val: Self) -> Result<sys::napi_value> {
261 let mut ptr = ptr::null_mut();
262
263 check_status!(
264 unsafe {
265 sys::napi_create_string_latin1(env, val.0.as_ptr().cast(), val.len() as isize, &mut ptr)
266 },
267 "Failed to convert rust type `String` into napi `latin1 string`"
268 )?;
269
270 Ok(ptr)
271 }
272}
273
274pub const NAPI_AUTO_LENGTH: isize = -1;
275
276#[derive(Debug)]
277pub struct RawCString {
283 length: isize,
284 inner: *const c_char,
285}
286
287impl RawCString {
288 pub fn new(inner: *const c_char, length: isize) -> Self {
292 Self { inner, length }
293 }
294}
295
296impl ToNapiValue for RawCString {
297 unsafe fn to_napi_value(env: napi_sys::napi_env, val: Self) -> Result<napi_sys::napi_value> {
298 let mut ptr = ptr::null_mut();
299
300 check_status!(
301 napi_sys::napi_create_string_utf8(env, val.inner, val.length, &mut ptr),
302 "Failed to convert rust `&str` into napi `string`"
303 )?;
304
305 Ok(ptr)
306 }
307}