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 fields: vec![
84 FieldDef {
85 name: "name".into(),
86 ty: TypeRef::String,
87 optional: false,
88 default: None,
89 doc: String::new(),
90 sanitized: false,
91 is_boxed: false,
92 type_rust_path: None,
93 cfg: None,
94 typed_default: None,
95 core_wrapper: CoreWrapper::None,
96 vec_inner_core_wrapper: CoreWrapper::None,
97 newtype_wrapper: None,
98 },
99 FieldDef {
100 name: "timeout".into(),
101 ty: TypeRef::Primitive(PrimitiveType::U64),
102 optional: true,
103 default: None,
104 doc: String::new(),
105 sanitized: false,
106 is_boxed: false,
107 type_rust_path: None,
108 cfg: None,
109 typed_default: None,
110 core_wrapper: CoreWrapper::None,
111 vec_inner_core_wrapper: CoreWrapper::None,
112 newtype_wrapper: None,
113 },
114 FieldDef {
115 name: "backend".into(),
116 ty: TypeRef::Named("Backend".into()),
117 optional: true,
118 default: None,
119 doc: String::new(),
120 sanitized: false,
121 is_boxed: false,
122 type_rust_path: None,
123 cfg: None,
124 typed_default: None,
125 core_wrapper: CoreWrapper::None,
126 vec_inner_core_wrapper: CoreWrapper::None,
127 newtype_wrapper: None,
128 },
129 ],
130 methods: vec![],
131 is_opaque: false,
132 is_clone: true,
133 is_trait: false,
134 has_default: false,
135 has_stripped_cfg_fields: false,
136 is_return_type: false,
137 serde_rename_all: None,
138 has_serde: false,
139 super_traits: vec![],
140 doc: String::new(),
141 cfg: None,
142 }
143 }
144
145 fn simple_enum() -> EnumDef {
146 EnumDef {
147 name: "Backend".to_string(),
148 rust_path: "my_crate::Backend".to_string(),
149 variants: vec![
150 EnumVariant {
151 name: "Cpu".into(),
152 fields: vec![],
153 doc: String::new(),
154 is_default: false,
155 serde_rename: None,
156 },
157 EnumVariant {
158 name: "Gpu".into(),
159 fields: vec![],
160 doc: String::new(),
161 is_default: false,
162 serde_rename: None,
163 },
164 ],
165 doc: String::new(),
166 cfg: None,
167 serde_tag: None,
168 serde_rename_all: None,
169 }
170 }
171
172 #[test]
173 fn test_from_binding_to_core() {
174 let typ = simple_type();
175 let result = gen_from_binding_to_core(&typ, "my_crate");
176 assert!(result.contains("impl From<Config> for my_crate::Config"));
177 assert!(result.contains("name: val.name"));
178 assert!(result.contains("timeout: val.timeout"));
179 assert!(result.contains("backend: val.backend.map(Into::into)"));
180 }
181
182 #[test]
183 fn test_from_core_to_binding() {
184 let typ = simple_type();
185 let result = gen_from_core_to_binding(&typ, "my_crate", &AHashSet::new());
186 assert!(result.contains("impl From<my_crate::Config> for Config"));
187 }
188
189 #[test]
190 fn test_enum_from_binding_to_core() {
191 let enum_def = simple_enum();
192 let result = gen_enum_from_binding_to_core(&enum_def, "my_crate");
193 assert!(result.contains("impl From<Backend> for my_crate::Backend"));
194 assert!(result.contains("Backend::Cpu => Self::Cpu"));
195 assert!(result.contains("Backend::Gpu => Self::Gpu"));
196 }
197
198 #[test]
199 fn test_enum_from_core_to_binding() {
200 let enum_def = simple_enum();
201 let result = gen_enum_from_core_to_binding(&enum_def, "my_crate");
202 assert!(result.contains("impl From<my_crate::Backend> for Backend"));
203 assert!(result.contains("my_crate::Backend::Cpu => Self::Cpu"));
204 assert!(result.contains("my_crate::Backend::Gpu => Self::Gpu"));
205 }
206
207 #[test]
208 fn test_from_binding_to_core_with_cfg_gated_field() {
209 let mut typ = simple_type();
211 typ.has_stripped_cfg_fields = true;
212 typ.fields.push(FieldDef {
213 name: "layout".into(),
214 ty: TypeRef::String,
215 optional: false,
216 default: None,
217 doc: String::new(),
218 sanitized: false,
219 is_boxed: false,
220 type_rust_path: None,
221 cfg: Some("feature = \"layout-detection\"".into()),
222 typed_default: None,
223 core_wrapper: CoreWrapper::None,
224 vec_inner_core_wrapper: CoreWrapper::None,
225 newtype_wrapper: None,
226 });
227
228 let result = gen_from_binding_to_core(&typ, "my_crate");
229
230 assert!(result.contains("impl From<Config> for my_crate::Config"));
232 assert!(result.contains("name: val.name"));
234 assert!(result.contains("timeout: val.timeout"));
235 assert!(!result.contains("layout: val.layout"));
237 assert!(result.contains("..Default::default()"));
239 }
240
241 #[test]
242 fn test_from_core_to_binding_with_cfg_gated_field() {
243 let mut typ = simple_type();
245 typ.fields.push(FieldDef {
246 name: "layout".into(),
247 ty: TypeRef::String,
248 optional: false,
249 default: None,
250 doc: String::new(),
251 sanitized: false,
252 is_boxed: false,
253 type_rust_path: None,
254 cfg: Some("feature = \"layout-detection\"".into()),
255 typed_default: None,
256 core_wrapper: CoreWrapper::None,
257 vec_inner_core_wrapper: CoreWrapper::None,
258 newtype_wrapper: None,
259 });
260
261 let result = gen_from_core_to_binding(&typ, "my_crate", &AHashSet::new());
262
263 assert!(result.contains("impl From<my_crate::Config> for Config"));
265 assert!(result.contains("name: val.name"));
267 assert!(!result.contains("layout:"));
269 }
270}