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 From<Vec<u16>> for Utf16String {
116 fn from(data: Vec<u16>) -> Self {
117 Utf16String(data)
118 }
119}
120
121impl Display for Utf16String {
122 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
123 write!(f, "{}", String::from_utf16_lossy(self))
124 }
125}
126
127impl Deref for Utf16String {
128 type Target = [u16];
129
130 fn deref(&self) -> &Self::Target {
131 self.0.as_ref()
132 }
133}
134
135impl TypeName for Utf16String {
136 fn type_name() -> &'static str {
137 "String(utf16)"
138 }
139
140 fn value_type() -> ValueType {
141 ValueType::String
142 }
143}
144
145impl FromNapiValue for Utf16String {
146 unsafe fn from_napi_value(env: sys::napi_env, napi_val: sys::napi_value) -> Result<Self> {
147 let mut len = 0;
148
149 check_status!(
150 unsafe { sys::napi_get_value_string_utf16(env, napi_val, ptr::null_mut(), 0, &mut len) },
151 "Failed to convert napi `utf16 string` into rust type `String`",
152 )?;
153
154 len += 1;
156 let mut ret = vec![0; len];
157 let mut written_char_count = 0;
158
159 check_status!(
160 unsafe {
161 sys::napi_get_value_string_utf16(
162 env,
163 napi_val,
164 ret.as_mut_ptr(),
165 len,
166 &mut written_char_count,
167 )
168 },
169 "Failed to convert napi `utf16 string` into rust type `String`",
170 )?;
171
172 ret.truncate(written_char_count);
173
174 Ok(Utf16String(ret))
175 }
176}
177
178impl ToNapiValue for Utf16String {
179 unsafe fn to_napi_value(env: sys::napi_env, val: Utf16String) -> Result<sys::napi_value> {
180 let mut ptr = ptr::null_mut();
181
182 check_status!(
183 unsafe {
184 sys::napi_create_string_utf16(env, val.0.as_ptr().cast(), val.len() as isize, &mut ptr)
185 },
186 "Failed to convert napi `string` into rust type `String`"
187 )?;
188
189 Ok(ptr)
190 }
191}
192
193#[derive(Debug)]
194pub struct Latin1String(Vec<u8>);
195
196impl ValidateNapiValue for Latin1String {}
197
198impl From<String> for Latin1String {
199 fn from(s: String) -> Self {
200 Latin1String(s.into_bytes())
201 }
202}
203
204#[cfg(feature = "latin1")]
205impl Display for Latin1String {
206 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
207 let mut dst_slice = vec![0; self.0.len() * 2];
208 let written =
209 encoding_rs::mem::convert_latin1_to_utf8(self.0.as_slice(), dst_slice.as_mut_slice());
210 dst_slice.truncate(written);
211 write!(f, "{}", unsafe { String::from_utf8_unchecked(dst_slice) })
212 }
213}
214
215impl Deref for Latin1String {
216 type Target = [u8];
217
218 fn deref(&self) -> &Self::Target {
219 self.0.as_slice()
220 }
221}
222
223impl TypeName for Latin1String {
224 fn type_name() -> &'static str {
225 "String(latin1)"
226 }
227
228 fn value_type() -> ValueType {
229 ValueType::String
230 }
231}
232
233impl FromNapiValue for Latin1String {
234 unsafe fn from_napi_value(env: sys::napi_env, napi_val: sys::napi_value) -> Result<Self> {
235 let mut len = 0;
236
237 check_status!(
238 unsafe { sys::napi_get_value_string_latin1(env, napi_val, ptr::null_mut(), 0, &mut len) },
239 "Failed to convert napi `latin1 string` into rust type `String`",
240 )?;
241
242 len += 1;
244 let mut buf: Vec<u8> = vec![0; len];
245
246 let mut written_char_count = 0;
247
248 check_status!(
249 unsafe {
250 sys::napi_get_value_string_latin1(
251 env,
252 napi_val,
253 buf.as_mut_ptr().cast(),
254 len,
255 &mut written_char_count,
256 )
257 },
258 "Failed to convert napi `latin1 string` into rust type `String`"
259 )?;
260 buf.truncate(written_char_count);
261 Ok(Latin1String(buf))
262 }
263}
264
265impl ToNapiValue for Latin1String {
266 unsafe fn to_napi_value(env: sys::napi_env, val: Self) -> Result<sys::napi_value> {
267 let mut ptr = ptr::null_mut();
268
269 check_status!(
270 unsafe {
271 sys::napi_create_string_latin1(env, val.0.as_ptr().cast(), val.len() as isize, &mut ptr)
272 },
273 "Failed to convert rust type `String` into napi `latin1 string`"
274 )?;
275
276 Ok(ptr)
277 }
278}
279
280pub const NAPI_AUTO_LENGTH: isize = -1;
281
282#[derive(Debug)]
283pub struct RawCString {
289 length: isize,
290 inner: *const c_char,
291}
292
293impl RawCString {
294 pub fn new(inner: *const c_char, length: isize) -> Self {
298 Self { inner, length }
299 }
300}
301
302impl ToNapiValue for RawCString {
303 unsafe fn to_napi_value(env: napi_sys::napi_env, val: Self) -> Result<napi_sys::napi_value> {
304 let mut ptr = ptr::null_mut();
305
306 check_status!(
307 napi_sys::napi_create_string_utf8(env, val.inner, val.length, &mut ptr),
308 "Failed to convert rust `&str` into napi `string`"
309 )?;
310
311 Ok(ptr)
312 }
313}