alef_codegen/conversions/
mod.rs1mod binding_to_core;
2mod core_to_binding;
3mod enums;
4pub(crate) mod helpers;
5
6use ahash::AHashSet;
7
8#[derive(Default, Clone)]
11pub struct ConversionConfig<'a> {
12 pub type_name_prefix: &'a str,
14 pub cast_large_ints_to_i64: bool,
16 pub enum_string_names: Option<&'a AHashSet<String>>,
19 pub map_uses_jsvalue: bool,
23 pub cast_f32_to_f64: bool,
25 pub optionalize_defaults: bool,
29 pub json_to_string: bool,
33 pub include_cfg_metadata: bool,
36 pub option_duration_on_defaults: bool,
42 pub binding_enums_have_data: bool,
45 pub exclude_types: &'a [String],
49 pub vec_named_to_string: bool,
54}
55
56pub use binding_to_core::{
58 field_conversion_to_core, field_conversion_to_core_cfg, gen_from_binding_to_core, gen_from_binding_to_core_cfg,
59};
60pub use core_to_binding::{
61 field_conversion_from_core, field_conversion_from_core_cfg, gen_from_core_to_binding, gen_from_core_to_binding_cfg,
62};
63pub use enums::{
64 gen_enum_from_binding_to_core, gen_enum_from_binding_to_core_cfg, gen_enum_from_core_to_binding,
65 gen_enum_from_core_to_binding_cfg,
66};
67pub use helpers::{
68 binding_to_core_match_arm, build_type_path_map, can_generate_conversion, can_generate_enum_conversion,
69 can_generate_enum_conversion_from_core, convertible_types, core_enum_path, core_to_binding_convertible_types,
70 core_to_binding_match_arm, core_type_path, field_references_excluded_type, has_sanitized_fields, input_type_names,
71 is_tuple_variant, resolve_named_path,
72};
73
74#[cfg(test)]
75mod tests {
76 use super::*;
77 use alef_core::ir::*;
78
79 fn simple_type() -> TypeDef {
80 TypeDef {
81 name: "Config".to_string(),
82 rust_path: "my_crate::Config".to_string(),
83 original_rust_path: String::new(),
84 fields: vec![
85 FieldDef {
86 name: "name".into(),
87 ty: TypeRef::String,
88 optional: false,
89 default: None,
90 doc: String::new(),
91 sanitized: false,
92 is_boxed: false,
93 type_rust_path: None,
94 cfg: None,
95 typed_default: None,
96 core_wrapper: CoreWrapper::None,
97 vec_inner_core_wrapper: CoreWrapper::None,
98 newtype_wrapper: None,
99 },
100 FieldDef {
101 name: "timeout".into(),
102 ty: TypeRef::Primitive(PrimitiveType::U64),
103 optional: true,
104 default: None,
105 doc: String::new(),
106 sanitized: false,
107 is_boxed: false,
108 type_rust_path: None,
109 cfg: None,
110 typed_default: None,
111 core_wrapper: CoreWrapper::None,
112 vec_inner_core_wrapper: CoreWrapper::None,
113 newtype_wrapper: None,
114 },
115 FieldDef {
116 name: "backend".into(),
117 ty: TypeRef::Named("Backend".into()),
118 optional: true,
119 default: None,
120 doc: String::new(),
121 sanitized: false,
122 is_boxed: false,
123 type_rust_path: None,
124 cfg: None,
125 typed_default: None,
126 core_wrapper: CoreWrapper::None,
127 vec_inner_core_wrapper: CoreWrapper::None,
128 newtype_wrapper: None,
129 },
130 ],
131 methods: vec![],
132 is_opaque: false,
133 is_clone: true,
134 is_trait: false,
135 has_default: false,
136 has_stripped_cfg_fields: false,
137 is_return_type: false,
138 serde_rename_all: None,
139 has_serde: false,
140 super_traits: vec![],
141 doc: String::new(),
142 cfg: None,
143 }
144 }
145
146 fn simple_enum() -> EnumDef {
147 EnumDef {
148 name: "Backend".to_string(),
149 rust_path: "my_crate::Backend".to_string(),
150 original_rust_path: String::new(),
151 variants: vec![
152 EnumVariant {
153 name: "Cpu".into(),
154 fields: vec![],
155 doc: String::new(),
156 is_default: false,
157 serde_rename: None,
158 },
159 EnumVariant {
160 name: "Gpu".into(),
161 fields: vec![],
162 doc: String::new(),
163 is_default: false,
164 serde_rename: None,
165 },
166 ],
167 doc: String::new(),
168 cfg: None,
169 serde_tag: None,
170 serde_rename_all: None,
171 }
172 }
173
174 #[test]
175 fn test_from_binding_to_core() {
176 let typ = simple_type();
177 let result = gen_from_binding_to_core(&typ, "my_crate");
178 assert!(result.contains("impl From<Config> for my_crate::Config"));
179 assert!(result.contains("name: val.name"));
180 assert!(result.contains("timeout: val.timeout"));
181 assert!(result.contains("backend: val.backend.map(Into::into)"));
182 }
183
184 #[test]
185 fn test_from_core_to_binding() {
186 let typ = simple_type();
187 let result = gen_from_core_to_binding(&typ, "my_crate", &AHashSet::new());
188 assert!(result.contains("impl From<my_crate::Config> for Config"));
189 }
190
191 #[test]
192 fn test_enum_from_binding_to_core() {
193 let enum_def = simple_enum();
194 let result = gen_enum_from_binding_to_core(&enum_def, "my_crate");
195 assert!(result.contains("impl From<Backend> for my_crate::Backend"));
196 assert!(result.contains("Backend::Cpu => Self::Cpu"));
197 assert!(result.contains("Backend::Gpu => Self::Gpu"));
198 }
199
200 #[test]
201 fn test_enum_from_core_to_binding() {
202 let enum_def = simple_enum();
203 let result = gen_enum_from_core_to_binding(&enum_def, "my_crate");
204 assert!(result.contains("impl From<my_crate::Backend> for Backend"));
205 assert!(result.contains("my_crate::Backend::Cpu => Self::Cpu"));
206 assert!(result.contains("my_crate::Backend::Gpu => Self::Gpu"));
207 }
208
209 #[test]
210 fn test_from_binding_to_core_with_cfg_gated_field() {
211 let mut typ = simple_type();
213 typ.has_stripped_cfg_fields = true;
214 typ.fields.push(FieldDef {
215 name: "layout".into(),
216 ty: TypeRef::String,
217 optional: false,
218 default: None,
219 doc: String::new(),
220 sanitized: false,
221 is_boxed: false,
222 type_rust_path: None,
223 cfg: Some("feature = \"layout-detection\"".into()),
224 typed_default: None,
225 core_wrapper: CoreWrapper::None,
226 vec_inner_core_wrapper: CoreWrapper::None,
227 newtype_wrapper: None,
228 });
229
230 let result = gen_from_binding_to_core(&typ, "my_crate");
231
232 assert!(result.contains("impl From<Config> for my_crate::Config"));
234 assert!(result.contains("name: val.name"));
236 assert!(result.contains("timeout: val.timeout"));
237 assert!(!result.contains("layout: val.layout"));
239 assert!(result.contains("..Default::default()"));
241 }
242
243 #[test]
244 fn test_from_core_to_binding_with_cfg_gated_field() {
245 let mut typ = simple_type();
247 typ.fields.push(FieldDef {
248 name: "layout".into(),
249 ty: TypeRef::String,
250 optional: false,
251 default: None,
252 doc: String::new(),
253 sanitized: false,
254 is_boxed: false,
255 type_rust_path: None,
256 cfg: Some("feature = \"layout-detection\"".into()),
257 typed_default: None,
258 core_wrapper: CoreWrapper::None,
259 vec_inner_core_wrapper: CoreWrapper::None,
260 newtype_wrapper: None,
261 });
262
263 let result = gen_from_core_to_binding(&typ, "my_crate", &AHashSet::new());
264
265 assert!(result.contains("impl From<my_crate::Config> for Config"));
267 assert!(result.contains("name: val.name"));
269 assert!(!result.contains("layout:"));
271 }
272}