napi_derive_backend_ohos/codegen/
enum.rs1use proc_macro2::{Ident, Literal, Span, TokenStream};
2use quote::ToTokens;
3
4use crate::{codegen::js_mod_to_token_stream, BindgenResult, NapiEnum, TryToTokens};
5
6impl TryToTokens for NapiEnum {
7 fn try_to_tokens(&self, tokens: &mut TokenStream) -> BindgenResult<()> {
8 let register = self.gen_module_register();
9 let napi_value_conversion = self.gen_napi_value_map_impl();
10
11 (quote! {
12 #napi_value_conversion
13 #register
14 })
15 .to_tokens(tokens);
16
17 Ok(())
18 }
19}
20
21impl NapiEnum {
22 fn gen_napi_value_map_impl(&self) -> TokenStream {
23 let name = &self.name;
24 let name_str = self.name.to_string();
25 let mut from_napi_branches = vec![];
26 let mut to_napi_branches = vec![];
27
28 self.variants.iter().for_each(|v| {
29 let val: Literal = (&v.val).into();
30 let v_name = &v.name;
31
32 from_napi_branches.push(quote! { #val => Ok(#name::#v_name) });
33 to_napi_branches.push(quote! { #name::#v_name => #val });
34 });
35
36 let validate_type = if self.is_string_enum {
37 quote! { napi_ohos::bindgen_prelude::ValueType::String }
38 } else {
39 quote! { napi_ohos::bindgen_prelude::ValueType::Number }
40 };
41
42 let from_napi_value = self.gen_from_napi_value(name, from_napi_branches);
43 let to_napi_value = self.gen_to_napi_value(name, to_napi_branches);
44 quote! {
45 impl napi_ohos::bindgen_prelude::TypeName for #name {
46 fn type_name() -> &'static str {
47 #name_str
48 }
49
50 fn value_type() -> napi_ohos::ValueType {
51 napi_ohos::ValueType::Object
52 }
53 }
54
55 impl napi_ohos::bindgen_prelude::ValidateNapiValue for #name {
56 unsafe fn validate(
57 env: napi_ohos::bindgen_prelude::sys::napi_env,
58 napi_val: napi_ohos::bindgen_prelude::sys::napi_value
59 ) -> napi_ohos::bindgen_prelude::Result<napi_ohos::sys::napi_value> {
60 napi_ohos::bindgen_prelude::assert_type_of!(env, napi_val, #validate_type)?;
61 Ok(std::ptr::null_mut())
62 }
63 }
64
65 #from_napi_value
66
67 #to_napi_value
68 }
69 }
70
71 fn gen_from_napi_value(&self, name: &Ident, from_napi_branches: Vec<TokenStream>) -> TokenStream {
72 if !self.object_from_js {
73 return quote! {};
74 }
75
76 let name_str = self.name.to_string();
77 if self.variants.is_empty() {
78 return quote! {
79 impl napi_ohos::bindgen_prelude::FromNapiValue for #name {
80 unsafe fn from_napi_value(
81 env: napi_ohos::bindgen_prelude::sys::napi_env,
82 napi_val: napi_ohos::bindgen_prelude::sys::napi_value
83 ) -> napi_ohos::bindgen_prelude::Result<Self> {
84 Err(napi_ohos::bindgen_prelude::error!(
85 napi_ohos::bindgen_prelude::Status::InvalidArg,
86 "enum `{}` has no variants",
87 #name_str
88 ))
89 }
90 }
91 };
92 }
93
94 let from_napi_value = if self.is_string_enum {
95 quote! {
96 let val: String = napi_ohos::bindgen_prelude::FromNapiValue::from_napi_value(env, napi_val)
97 }
98 } else {
99 quote! {
100 let val = napi_ohos::bindgen_prelude::FromNapiValue::from_napi_value(env, napi_val)
101 }
102 };
103 let match_val = if self.is_string_enum {
104 quote! { val.as_str() }
105 } else {
106 quote! { val }
107 };
108 quote! {
109 impl napi_ohos::bindgen_prelude::FromNapiValue for #name {
110 unsafe fn from_napi_value(
111 env: napi_ohos::bindgen_prelude::sys::napi_env,
112 napi_val: napi_ohos::bindgen_prelude::sys::napi_value
113 ) -> napi_ohos::bindgen_prelude::Result<Self> {
114 #from_napi_value.map_err(|e| {
115 napi_ohos::bindgen_prelude::error!(
116 e.status,
117 "Failed to convert napi value into enum `{}`. {}",
118 #name_str,
119 e,
120 )
121 })?;
122
123 match #match_val {
124 #(#from_napi_branches,)*
125 _ => {
126 Err(napi_ohos::bindgen_prelude::error!(
127 napi_ohos::bindgen_prelude::Status::InvalidArg,
128 "value `{:?}` does not match any variant of enum `{}`",
129 val,
130 #name_str
131 ))
132 }
133 }
134 }
135 }
136 }
137 }
138
139 fn gen_to_napi_value(&self, name: &Ident, to_napi_branches: Vec<TokenStream>) -> TokenStream {
140 if !self.object_to_js {
141 return quote! {};
142 }
143
144 if self.variants.is_empty() {
145 return quote! {
146 impl napi_ohos::bindgen_prelude::ToNapiValue for #name {
147 unsafe fn to_napi_value(
148 env: napi_ohos::bindgen_prelude::sys::napi_env,
149 val: Self
150 ) -> napi_ohos::bindgen_prelude::Result<napi_ohos::bindgen_prelude::sys::napi_value> {
151 napi_ohos::bindgen_prelude::ToNapiValue::to_napi_value(env, ())
152 }
153 }
154
155 impl napi_ohos::bindgen_prelude::ToNapiValue for &#name {
156 unsafe fn to_napi_value(
157 env: napi_ohos::bindgen_prelude::sys::napi_env,
158 val: Self
159 ) -> napi_ohos::bindgen_prelude::Result<napi_ohos::bindgen_prelude::sys::napi_value> {
160 napi_ohos::bindgen_prelude::ToNapiValue::to_napi_value(env, ())
161 }
162 }
163
164 impl napi_ohos::bindgen_prelude::ToNapiValue for &mut #name {
165 unsafe fn to_napi_value(
166 env: napi_ohos::bindgen_prelude::sys::napi_env,
167 val: Self
168 ) -> napi_ohos::bindgen_prelude::Result<napi_ohos::bindgen_prelude::sys::napi_value> {
169 napi_ohos::bindgen_prelude::ToNapiValue::to_napi_value(env, ())
170 }
171 }
172 };
173 }
174
175 quote! {
176 impl napi_ohos::bindgen_prelude::ToNapiValue for #name {
177 unsafe fn to_napi_value(
178 env: napi_ohos::bindgen_prelude::sys::napi_env,
179 val: Self
180 ) -> napi_ohos::bindgen_prelude::Result<napi_ohos::bindgen_prelude::sys::napi_value> {
181 let val = match val {
182 #(#to_napi_branches,)*
183 };
184
185 napi_ohos::bindgen_prelude::ToNapiValue::to_napi_value(env, val)
186 }
187 }
188
189 impl napi_ohos::bindgen_prelude::ToNapiValue for &#name {
190 unsafe fn to_napi_value(
191 env: napi_ohos::bindgen_prelude::sys::napi_env,
192 val: Self
193 ) -> napi_ohos::bindgen_prelude::Result<napi_ohos::bindgen_prelude::sys::napi_value> {
194 let val = match val {
195 #(#to_napi_branches,)*
196 };
197
198 napi_ohos::bindgen_prelude::ToNapiValue::to_napi_value(env, val)
199 }
200 }
201
202 impl napi_ohos::bindgen_prelude::ToNapiValue for &mut #name {
203 unsafe fn to_napi_value(
204 env: napi_ohos::bindgen_prelude::sys::napi_env,
205 val: Self
206 ) -> napi_ohos::bindgen_prelude::Result<napi_ohos::bindgen_prelude::sys::napi_value> {
207 let val = match val {
208 #(#to_napi_branches,)*
209 };
210
211 napi_ohos::bindgen_prelude::ToNapiValue::to_napi_value(env, val)
212 }
213 }
214 }
215 }
216
217 fn gen_module_register(&self) -> TokenStream {
218 let name_str = self.name.to_string();
219 let js_name_lit = Literal::string(&format!("{}\0", &self.js_name));
220 let register_name = &self.register_name;
221
222 let mut define_properties = vec![];
223
224 for variant in self.variants.iter() {
225 let name_lit = Literal::string(&format!("{}\0", variant.name));
226 let val_lit: Literal = (&variant.val).into();
227
228 define_properties.push(quote! {
229 {
230 let name = std::ffi::CStr::from_bytes_with_nul_unchecked(#name_lit.as_bytes());
231 napi_ohos::bindgen_prelude::check_status!(
232 napi_ohos::bindgen_prelude::sys::napi_set_named_property(
233 env,
234 obj_ptr, name.as_ptr(),
235 napi_ohos::bindgen_prelude::ToNapiValue::to_napi_value(env, #val_lit)?
236 ),
237 "Failed to defined enum `{}`",
238 #js_name_lit
239 )?;
240 };
241 })
242 }
243
244 let callback_name = Ident::new(
245 &format!("__register__enum__{name_str}_callback__"),
246 Span::call_site(),
247 );
248
249 let js_mod_ident = js_mod_to_token_stream(self.js_mod.as_ref());
250
251 quote! {
252 #[allow(non_snake_case)]
253 #[allow(clippy::all)]
254 unsafe fn #callback_name(env: napi_ohos::bindgen_prelude::sys::napi_env) -> napi_ohos::bindgen_prelude::Result<napi_ohos::bindgen_prelude::sys::napi_value> {
255 use std::ffi::CString;
256 use std::ptr;
257
258 let mut obj_ptr = ptr::null_mut();
259
260 napi_ohos::bindgen_prelude::check_status!(
261 napi_ohos::bindgen_prelude::sys::napi_create_object(env, &mut obj_ptr),
262 "Failed to create napi object"
263 )?;
264
265 #(#define_properties)*
266
267 Ok(obj_ptr)
268 }
269 #[allow(non_snake_case)]
270 #[allow(clippy::all)]
271 #[cfg(all(not(test), not(target_family = "wasm")))]
272 #[napi_ohos::ctor::ctor(crate_path=napi_ohos::ctor)]
273 fn #register_name() {
274 napi_ohos::bindgen_prelude::register_module_export(#js_mod_ident, #js_name_lit, #callback_name);
275 }
276 #[allow(non_snake_case)]
277 #[allow(clippy::all)]
278 #[cfg(all(not(test), target_family = "wasm"))]
279 #[no_mangle]
280 extern "C" fn #register_name() {
281 napi_ohos::bindgen_prelude::register_module_export(#js_mod_ident, #js_name_lit, #callback_name);
282 }
283 }
284 }
285}