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