Skip to content

Commit d9c641b

Browse files
committed
feat: adding support for struct inheritages
1 parent 486a09a commit d9c641b

File tree

3 files changed

+95
-22
lines changed

3 files changed

+95
-22
lines changed

examples/minimal/src/main.rs

Lines changed: 22 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
use std::{
22
self,
33
error::Error,
4+
marker,
45
sync::Arc,
56
};
67

@@ -19,23 +20,29 @@ use raw_struct::{
1920
};
2021

2122
fn main() -> Result<(), Box<dyn Error + Send + Sync>> {
22-
let mut memory = [0u8; 0x40];
23+
let mut memory = [0u8; 0x80];
2324
memory[0..4].copy_from_slice(&0x6Fu32.to_le_bytes());
2425
memory[4..8].copy_from_slice(&0x99u32.to_le_bytes());
26+
memory[0x40..0x44].copy_from_slice(&0xFF00FFu32.to_le_bytes());
2527

2628
println!("{}", <dyn MyStruct as Copyable>::MEMORY_SIZE);
2729

2830
let memory = Arc::new(CopyMemoryView::new(memory));
2931
{
3032
let object = Reference::<dyn MyStruct, _>::new(memory.clone(), 0x00);
31-
println!("field_a = {}", object.field_a()?);
32-
println!("field_b = {}", object.field_b()?);
33+
println!("field_a = {:X}", object.field_a()?);
34+
println!("field_b = {:X}", object.field_b()?);
35+
36+
let object_ex = object.cast::<dyn MyStructExt>();
37+
println!("ex field_b = {:X}", object_ex.field_b()?);
38+
println!("ex ext_field_a = {:X}", object_ex.ext_field_a()?);
39+
println!("X a & b combined = {:X}", object_ex.first_t()?);
3340
}
3441

3542
{
3643
let object = Copy::<dyn MyStruct>::read_object(&*memory, 0x00)?;
37-
println!("field_a = {}", object.field_a()?);
38-
println!("field_b = {}", object.field_b()?);
44+
println!("field_a = {:X}", object.field_a()?);
45+
println!("field_b = {:X}", object.field_b()?);
3946
}
4047

4148
Ok(())
@@ -78,9 +85,18 @@ struct MyStruct {
7885
pub field_g: [u8; 0x20],
7986
}
8087

88+
#[raw_struct(memory = "T")]
89+
struct X<T>
90+
where
91+
T: marker::Copy + Send + Sync + 'static,
92+
{
93+
#[field(offset = "0x00")]
94+
first_t: T,
95+
}
96+
8197
#[raw_struct(size = 0x44)]
98+
#[inherits(MyStruct, X::<u64>)]
8299
struct MyStructExt {
83100
#[field(offset = 0x40)]
84101
pub ext_field_a: u32,
85102
}
86-
impl MyStruct for dyn MyStructExt {}

raw_struct_derive/src/derive_raw_struct.rs

Lines changed: 67 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ use syn::{
88
Parse,
99
ParseStream,
1010
},
11+
parse_quote,
1112
punctuated::Punctuated,
1213
spanned::Spanned,
1314
Attribute,
@@ -22,6 +23,8 @@ use syn::{
2223
Lit,
2324
LitStr,
2425
MetaNameValue,
26+
Path,
27+
PathArguments,
2528
Result,
2629
Token,
2730
TypeGenerics,
@@ -209,6 +212,7 @@ struct ViewableGenerator<'a> {
209212
args: StructArgs,
210213

211214
attributes: Vec<&'a Attribute>,
215+
inherits: Vec<Path>,
212216
fields: Vec<ViewableField<'a>>,
213217

214218
generics_impl: ImplGenerics<'a>,
@@ -236,26 +240,37 @@ impl<'a> ViewableGenerator<'a> {
236240
}
237241
}
238242

239-
fn parse_attributes(target: &'a ItemStruct) -> Result<Vec<&'a Attribute>> {
240-
target
241-
.attrs
242-
.iter()
243-
.map(|attr| {
244-
if attr.path.is_ident("doc") {
245-
Ok(attr)
246-
} else {
247-
Err(Error::new(
243+
fn parse_attributes(target: &'a ItemStruct) -> Result<(Vec<&'a Attribute>, Vec<Path>)> {
244+
let mut attributes = Vec::with_capacity(target.attrs.len());
245+
let mut inherits = None;
246+
247+
for attr in &target.attrs {
248+
if attr.path.is_ident("doc") {
249+
attributes.push(attr);
250+
} else if attr.path.is_ident("inherits") {
251+
if inherits.is_some() {
252+
return Err(Error::new(
248253
attr.span(),
249-
"only \"doc\" attributes are supported on raw_structs",
250-
))
254+
"only one instance of the \"inherits\" attributes is supported",
255+
));
251256
}
252-
})
253-
.collect::<Result<Vec<_>>>()
257+
258+
let args = attr.parse_args_with(Punctuated::<Path, Token![,]>::parse_terminated)?;
259+
inherits = Some(args.iter().cloned().collect::<Vec<_>>());
260+
} else {
261+
return Err(Error::new(
262+
attr.span(),
263+
"only \"doc\" or \"inherits\" attributes are supported on raw_structs",
264+
));
265+
}
266+
}
267+
268+
Ok((attributes, inherits.unwrap_or_default()))
254269
}
255270

256271
fn new(target: &'a ItemStruct, target_args: StructArgs) -> Result<Self> {
257272
let fields = Self::parse_fields(&target)?;
258-
let attributes = Self::parse_attributes(&target)?;
273+
let (attributes, inherits) = Self::parse_attributes(&target)?;
259274

260275
let (generics_impl, generics_type, generics_where) = target.generics.split_for_impl();
261276

@@ -285,6 +300,7 @@ impl<'a> ViewableGenerator<'a> {
285300
args: target_args,
286301

287302
attributes,
303+
inherits,
288304
fields,
289305

290306
generics_impl,
@@ -410,6 +426,36 @@ impl<'a> ViewableGenerator<'a> {
410426
for #instance_name<A, MemoryView> { }
411427
}
412428
}
429+
430+
fn generate_inheritances(&self) -> TokenStream {
431+
let accessor_name = &self.accessor_name;
432+
let (accessor_impl_generics, accessor_ty_generics, accessor_where_clause) =
433+
self.accessor_generics.split_for_impl();
434+
435+
let mut inheritances = Vec::with_capacity(self.inherits.len());
436+
for path in &self.inherits {
437+
let mut path = path.clone();
438+
let Some(last) = path.segments.last_mut() else {
439+
panic!("expected a path to have at least one segment");
440+
};
441+
442+
last.ident = Ident::new(&format!("{}_Accessor", last.ident), last.span());
443+
last.arguments = match &last.arguments {
444+
PathArguments::None => PathArguments::AngleBracketed(parse_quote! { <MemoryView> }),
445+
PathArguments::Parenthesized(_) => unreachable!(),
446+
PathArguments::AngleBracketed(value) => {
447+
let args = value.args.iter();
448+
PathArguments::AngleBracketed(parse_quote! { <MemoryView, #(#args,)*> })
449+
}
450+
};
451+
452+
inheritances.push(quote! {
453+
impl #accessor_impl_generics #path for dyn #accessor_name #accessor_ty_generics #accessor_where_clause {}
454+
});
455+
}
456+
457+
quote! { #(#inheritances)* }
458+
}
413459
}
414460

415461
pub fn raw_struct(attr: TokenStream, input: TokenStream) -> Result<TokenStream> {
@@ -432,12 +478,19 @@ pub fn raw_struct(attr: TokenStream, input: TokenStream) -> Result<TokenStream>
432478
// generator.generate_instance_struct().to_string()
433479
// );
434480

481+
// println!(
482+
// "/* Inheritances: */ {}",
483+
// generator.generate_inheritances().to_string()
484+
// );
485+
435486
let main_trait = generator.generate_main_trait();
436487
let accessors = generator.generate_accessor_trait();
437488
let instance = generator.generate_instance_struct();
489+
let inheritances = generator.generate_inheritances();
438490
Ok(quote! {
439491
#main_trait
440492
#accessors
441493
#instance
494+
#inheritances
442495
})
443496
}

raw_struct_derive/src/lib.rs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,12 @@ mod derive_raw_struct;
66
/// Marks a struct as a representation of a C-style struct with memory-mapped fields.
77
///
88
/// # Supported Attributes:
9-
/// - `size = "<struct size>"` (required)
10-
/// Defines the total memory size of the struct.
9+
/// - `#[raw_struct(...)]`
10+
/// - `size = "<struct size>"` (required)
11+
/// Defines the total memory size of the struct.
12+
/// - `#[inherits(...)]`
13+
/// One or multiple base classes similar to the `#[derive(...)]` attribute.
14+
/// Note: base classes must be raw_structs as well.
1115
///
1216
/// Each field within the struct must be annotated with the `#[field(...)]` attribute.
1317
///

0 commit comments

Comments
 (0)