Skip to content

Commit eb430d1

Browse files
committed
Unify codegen for structs and unions
1 parent fd6dac3 commit eb430d1

File tree

1 file changed

+43
-54
lines changed
  • rust/binaryninja-derive/src

1 file changed

+43
-54
lines changed

rust/binaryninja-derive/src/lib.rs

Lines changed: 43 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -140,7 +140,9 @@ fn impl_abstract_type(ast: DeriveInput) -> Result<TokenStream> {
140140
let ident = ast.ident;
141141
match ast.data {
142142
Data::Struct(s) => match s.fields {
143-
Fields::Named(fields) => impl_abstract_struct_type(ident, fields, repr),
143+
Fields::Named(fields) => {
144+
impl_abstract_structure_type(ident, fields, repr, StructureKind::Struct)
145+
}
144146
Fields::Unnamed(_) => Err(s
145147
.fields
146148
.span()
@@ -150,12 +152,35 @@ fn impl_abstract_type(ast: DeriveInput) -> Result<TokenStream> {
150152
.error("unit structs are unsupported; provide at least one named field")),
151153
},
152154
Data::Enum(e) => impl_abstract_enum_type(ident, e.variants, repr),
153-
Data::Union(u) => impl_abstract_union_type(ident, u.fields, repr),
155+
Data::Union(u) => impl_abstract_structure_type(ident, u.fields, repr, StructureKind::Union),
154156
}
155157
}
156158

157-
fn field_arguments(name: &Ident, fields: &[AbstractField]) -> Vec<TokenStream> {
158-
fields
159+
enum StructureKind {
160+
Struct,
161+
Union,
162+
}
163+
164+
fn impl_abstract_structure_type(
165+
name: Ident,
166+
fields: FieldsNamed,
167+
repr: Repr,
168+
kind: StructureKind,
169+
) -> Result<TokenStream> {
170+
if !repr.c {
171+
let msg = match kind {
172+
StructureKind::Struct => "struct must be `repr(C)`",
173+
StructureKind::Union => "union must be `repr(C)`",
174+
};
175+
return Err(name.span().error(msg));
176+
}
177+
178+
let fields = fields
179+
.named
180+
.into_iter()
181+
.map(AbstractField::from_field)
182+
.collect::<Result<Vec<_>>>()?;
183+
let args = fields
159184
.iter()
160185
.map(|field| {
161186
let ident = &field.ident;
@@ -169,63 +194,27 @@ fn field_arguments(name: &Ident, fields: &[AbstractField]) -> Vec<TokenStream> {
169194
::binaryninja::types::MemberScope::NoScope,
170195
}
171196
})
172-
.collect()
173-
}
174-
175-
fn impl_abstract_struct_type(name: Ident, fields: FieldsNamed, repr: Repr) -> Result<TokenStream> {
176-
if !repr.c {
177-
return Err(name.span().error("struct must be `repr(C)`"));
178-
}
179-
180-
let fields = fields
181-
.named
182-
.into_iter()
183-
.map(AbstractField::from_field)
184-
.collect::<Result<Vec<_>>>()?;
185-
let args = field_arguments(&name, &fields);
186-
let packed = repr.packed.is_some();
187-
let alignment = repr.align.map(|align| quote! { .set_alignment(#align) });
188-
Ok(quote! {
189-
impl ::binaryninja::types::AbstractType for #name {
190-
fn resolve_type() -> ::binaryninja::rc::Ref<::binaryninja::types::Type> {
191-
::binaryninja::types::Type::structure(
192-
&::binaryninja::types::Structure::builder()
193-
#(.insert(#args))*
194-
.set_width(::std::mem::size_of::<#name>() as u64)
195-
.set_packed(#packed)
196-
#alignment
197-
.finalize()
198-
)
199-
}
200-
}
201-
})
202-
}
203-
204-
fn impl_abstract_union_type(name: Ident, fields: FieldsNamed, repr: Repr) -> Result<TokenStream> {
205-
if !repr.c {
206-
return Err(name.span().error("union must be `repr(C)`"));
207-
}
208-
209-
let fields = fields
210-
.named
211-
.into_iter()
212-
.map(AbstractField::from_field)
213-
.collect::<Result<Vec<_>>>()?;
214-
let args = field_arguments(&name, &fields);
215-
let packed = repr.packed.is_some();
216-
let alignment = repr.align.map(|align| quote! { .set_alignment(#align) });
197+
.collect::<Vec<_>>();
198+
let is_packed = repr.packed.is_some();
199+
let set_alignment = repr.align.map(|align| quote! { .set_alignment(#align) });
200+
let set_union = match kind {
201+
StructureKind::Struct => None,
202+
StructureKind::Union => Some(quote! {
203+
.set_structure_type(
204+
::binaryninja::types::StructureType::UnionStructureType
205+
)
206+
}),
207+
};
217208
Ok(quote! {
218209
impl ::binaryninja::types::AbstractType for #name {
219210
fn resolve_type() -> ::binaryninja::rc::Ref<::binaryninja::types::Type> {
220211
::binaryninja::types::Type::structure(
221212
&::binaryninja::types::Structure::builder()
222213
#(.insert(#args))*
223-
.set_structure_type(
224-
::binaryninja::types::StructureType::UnionStructureType
225-
)
226214
.set_width(::std::mem::size_of::<#name>() as u64)
227-
.set_packed(#packed)
228-
#alignment
215+
.set_packed(#is_packed)
216+
#set_alignment
217+
#set_union
229218
.finalize()
230219
)
231220
}

0 commit comments

Comments
 (0)