Skip to content

Commit e5d85ee

Browse files
committed
feat: adding support for inheritance
1 parent 77f074f commit e5d85ee

File tree

4 files changed

+124
-57
lines changed

4 files changed

+124
-57
lines changed

examples/dyn_memory/src/main.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ fn main() -> Result<(), Box<dyn Error + Send + Sync>> {
2727
}
2828

2929
#[raw_struct(memory = "([u8; 0x10], T)")]
30-
struct Container<T: marker::Copy + FromMemoryView + Send + Sync + 'static> {
30+
struct Container<T: marker::Copy + FromMemoryView> {
3131
#[field(offset = 0x00)]
3232
pub var_a: u64,
3333

examples/minimal/src/main.rs

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,14 +7,17 @@ use raw_struct::{
77
builtins::Ptr64,
88
raw_struct,
99
Copy,
10+
FromMemoryView,
1011
Reference,
1112
SizedViewable,
1213
};
1314

1415
fn main() -> Result<(), Box<dyn Error + Send + Sync>> {
15-
let mut memory = [0u8; 0x40];
16+
let mut memory = [0u8; 0x44];
1617
memory[0..4].copy_from_slice(&0x6Fu32.to_le_bytes());
1718
memory[4..8].copy_from_slice(&0x99u32.to_le_bytes());
19+
memory[4..8].copy_from_slice(&0x99u32.to_le_bytes());
20+
memory[0x40..][..4].copy_from_slice(&0xAAu32.to_le_bytes());
1821

1922
println!(
2023
"MyStruct size = 0x{:X}",
@@ -25,6 +28,10 @@ fn main() -> Result<(), Box<dyn Error + Send + Sync>> {
2528
let object = Reference::<MyStruct, _>::new(memory.as_slice(), 0x00);
2629
println!("field_a = {:X}", object.field_a()?);
2730
println!("field_b = {:X}", object.field_b()?);
31+
32+
let object = object.cast::<MyStructExt>();
33+
println!("ext_field_a = {:X}", object.ext_field_a()?);
34+
println!("field_base = {:X}", object.field_base()?);
2835
}
2936

3037
{
@@ -73,8 +80,14 @@ struct MyStruct {
7380
pub field_g: [u8; 0x20],
7481
}
7582

76-
#[raw_struct(size = 0x44)]
77-
struct MyStructExt /* : MyStruct */ {
83+
#[raw_struct]
84+
struct MyStructBase<T: FromMemoryView> {
85+
#[field(offset = 0x00)]
86+
pub field_base: T,
87+
}
88+
89+
#[raw_struct(size = 0x44, inherits = "MyStructBase::<u32>")]
90+
struct MyStructExt {
7891
#[field(offset = 0x40)]
7992
pub ext_field_a: u32,
8093
}

raw_struct/src/reference.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ impl<T: Viewable, M: MemoryView> Reference<T, M> {
4848
}
4949
}
5050

51-
pub fn reference_address(&self) -> u64 {
51+
pub fn reference_memory_address(&self) -> u64 {
5252
self.inner.memory_view().address()
5353
}
5454

raw_struct_derive/src/derive_raw_struct.rs

Lines changed: 106 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -11,23 +11,24 @@ use syn::{
1111
Parse,
1212
ParseStream,
1313
},
14+
parse_quote,
1415
punctuated::Punctuated,
1516
spanned::Spanned,
16-
Attribute,
1717
Error,
1818
Expr,
1919
Field,
20-
FieldsNamed,
20+
Fields,
21+
GenericArgument,
2122
GenericParam,
22-
Generics,
2323
Ident,
24+
ItemStruct,
2425
Lit,
2526
LitStr,
2627
MetaNameValue,
2728
Path,
29+
PathArguments,
2830
Result,
2931
Token,
30-
Visibility,
3132
};
3233

3334
struct StaticIdent(&'static str);
@@ -97,6 +98,7 @@ impl Parse for FieldArgs {
9798
#[derive(Debug)]
9899
struct StructArgs {
99100
memory: Option<TokenStream>,
101+
inherits: Option<Path>,
100102
}
101103

102104
impl Parse for StructArgs {
@@ -106,6 +108,7 @@ impl Parse for StructArgs {
106108

107109
let mut size = None;
108110
let mut memory = None;
111+
let mut inherits = None;
109112

110113
for kv in &vars {
111114
if kv.path.is_ident("size") {
@@ -121,6 +124,11 @@ impl Parse for StructArgs {
121124
Lit::Str(value) => memory = Some(value.parse::<Expr>()?.to_token_stream()),
122125
_ => return Err(Error::new(kv.lit.span(), "expected a string")),
123126
}
127+
} else if kv.path.is_ident("inherits") {
128+
match &kv.lit {
129+
Lit::Str(value) => inherits = Some(value.parse::<Path>()?),
130+
_ => return Err(Error::new(kv.lit.span(), "expected a string")),
131+
}
124132
} else {
125133
return Err(Error::new(kv.path.span(), "unknown attribute"));
126134
}
@@ -129,11 +137,41 @@ impl Parse for StructArgs {
129137
let size = size.map(|size: TokenStream| quote::quote!([u8; #size]).to_token_stream());
130138
Ok(Self {
131139
memory: memory.or(size),
140+
inherits,
132141
})
133142
}
134143
}
135144

136-
fn extract_struct_fields(fields: &FieldsNamed) -> Result<Vec<(FieldArgs, Field)>> {
145+
fn add_type_param(path: &mut Path, ty: syn::Type) {
146+
if let Some(last) = path.segments.last_mut() {
147+
match &mut last.arguments {
148+
PathArguments::None => {
149+
// Turn `None` into `<T>`
150+
last.arguments =
151+
PathArguments::AngleBracketed(syn::AngleBracketedGenericArguments {
152+
colon2_token: None,
153+
lt_token: Default::default(),
154+
args: vec![GenericArgument::Type(ty)].into_iter().collect(),
155+
gt_token: Default::default(),
156+
});
157+
}
158+
PathArguments::AngleBracketed(args) => {
159+
// Already has <...>, just push
160+
args.args.push(GenericArgument::Type(ty));
161+
}
162+
PathArguments::Parenthesized(_) => {
163+
// Function-like path segment, can't add normal type params
164+
panic!("cannot add type arguments to a function-like path segment");
165+
}
166+
}
167+
}
168+
}
169+
170+
fn extract_struct_fields(fields: &Fields) -> Result<Vec<(FieldArgs, Field)>> {
171+
let Fields::Named(fields) = fields else {
172+
return Err(Error::new(fields.span(), "only named fields supported"));
173+
};
174+
137175
let mut result = Vec::with_capacity(fields.named.len());
138176
for field in fields.named.iter() {
139177
let mut field = field.clone();
@@ -198,41 +236,7 @@ fn generate_reference_accessors(fields: &[(FieldArgs, Field)]) -> Result<TokenSt
198236
.into_token_stream())
199237
}
200238

201-
#[derive(Debug)]
202-
#[allow(unused)]
203-
pub struct ItemRawStruct {
204-
pub attrs: Vec<Attribute>,
205-
pub vis: Visibility,
206-
pub struct_token: Token![struct],
207-
pub ident: Ident,
208-
pub generics: Generics,
209-
pub super_class: Option<(Token![:], Path)>,
210-
pub fields: FieldsNamed,
211-
pub semi_token: Option<Token![;]>,
212-
}
213-
214-
impl Parse for ItemRawStruct {
215-
fn parse(input: ParseStream) -> Result<Self> {
216-
Ok(Self {
217-
attrs: input.call(Attribute::parse_outer)?,
218-
vis: input.parse()?,
219-
struct_token: input.parse()?,
220-
ident: input.parse()?,
221-
generics: input.parse()?,
222-
super_class: if input.peek(Token![:]) {
223-
let colon: Token![:] = input.parse()?;
224-
let path: Path = input.parse()?;
225-
Some((colon, path))
226-
} else {
227-
None
228-
},
229-
fields: input.parse()?,
230-
semi_token: input.parse()?,
231-
})
232-
}
233-
}
234-
235-
fn generate_struct_definition(_args: &StructArgs, target: &ItemRawStruct) -> Result<TokenStream> {
239+
fn generate_struct_definition(args: &StructArgs, target: &ItemStruct) -> Result<TokenStream> {
236240
let attr_clone_copy = syn::parse_quote! {
237241
#[derive(Clone, Copy)]
238242
};
@@ -262,18 +266,26 @@ fn generate_struct_definition(_args: &StructArgs, target: &ItemRawStruct) -> Res
262266
})
263267
.collect::<Vec<_>>();
264268

269+
let memory = if let Some(inherits) = &args.inherits {
270+
let mut inherits = inherits.clone();
271+
self::add_type_param(&mut inherits, parse_quote!(#IDENT_MEMORY_VIEW_T));
272+
quote! { inner: #inherits }
273+
} else {
274+
quote! { memory: #IDENT_MEMORY_VIEW_T }
275+
};
276+
265277
Ok(quote! {
266278
#(#attributes)*
267279
#vis struct #name #struct_generics {
268-
memory: #IDENT_MEMORY_VIEW_T,
280+
#memory,
269281
_type: std::marker::PhantomData<(#(#type_list,)*)>,
270282
}
271283
})
272284
}
273285

274286
pub fn raw_struct(attr: TokenStream, input: TokenStream) -> Result<TokenStream> {
275287
let args = syn::parse2::<StructArgs>(attr)?;
276-
let target = syn::parse2::<ItemRawStruct>(input)?;
288+
let target = syn::parse2::<ItemStruct>(input)?;
277289

278290
let struct_name = target.ident.clone();
279291
let struct_name_str = format!("{}", target.ident);
@@ -295,6 +307,54 @@ pub fn raw_struct(attr: TokenStream, input: TokenStream) -> Result<TokenStream>
295307

296308
let struct_def = self::generate_struct_definition(&args, &target)?;
297309

310+
let impl_impl = if let Some(_inherits) = &args.inherits {
311+
quote! {
312+
impl #impl_generics raw_struct::ViewableImplementation<#IDENT_MEMORY_VIEW_T> for #struct_name #impl_ty_generics #impl_where_clause {
313+
fn memory_view(&self) -> &#IDENT_MEMORY_VIEW_T {
314+
self.inner.memory_view()
315+
}
316+
317+
fn into_memory_view(self) -> #IDENT_MEMORY_VIEW_T {
318+
self.inner.into_memory_view()
319+
}
320+
}
321+
}
322+
} else {
323+
quote! {
324+
impl #impl_generics raw_struct::ViewableImplementation<#IDENT_MEMORY_VIEW_T> for #struct_name #impl_ty_generics #impl_where_clause {
325+
fn memory_view(&self) -> &#IDENT_MEMORY_VIEW_T {
326+
&self.memory
327+
}
328+
329+
fn into_memory_view(self) -> #IDENT_MEMORY_VIEW_T {
330+
self.memory
331+
}
332+
}
333+
}
334+
};
335+
336+
let impl_construct_from_memory = if let Some(inherits) = &args.inherits {
337+
quote! { #struct_name { inner: #inherits ::from_memory(memory), _type: Default::default() } }
338+
} else {
339+
quote! { #struct_name { memory, _type: Default::default() } }
340+
};
341+
342+
let deref_impl = if let Some(inherits) = &args.inherits {
343+
let mut inherits = inherits.clone();
344+
self::add_type_param(&mut inherits, parse_quote!(#IDENT_MEMORY_VIEW_T));
345+
Some(quote! {
346+
impl #impl_generics core::ops::Deref for #struct_name #impl_ty_generics #impl_where_clause {
347+
type Target = #inherits;
348+
349+
fn deref(&self) -> &Self::Target {
350+
&self.inner
351+
}
352+
}
353+
})
354+
} else {
355+
None
356+
};
357+
298358
let sized_impl = if let Some(memory) = args.memory {
299359
Some(quote! {
300360
impl #vanilla_impl_generics raw_struct::SizedViewable for #struct_name #vanilla_ty_generics #vanilla_where_clause {
@@ -312,15 +372,7 @@ pub fn raw_struct(attr: TokenStream, input: TokenStream) -> Result<TokenStream>
312372
#accessors
313373
}
314374

315-
impl #impl_generics raw_struct::ViewableImplementation<#IDENT_MEMORY_VIEW_T> for #struct_name #impl_ty_generics #impl_where_clause {
316-
fn memory_view(&self) -> &#IDENT_MEMORY_VIEW_T {
317-
&self.memory
318-
}
319-
320-
fn into_memory_view(self) -> #IDENT_MEMORY_VIEW_T {
321-
self.memory
322-
}
323-
}
375+
#impl_impl
324376

325377
impl #vanilla_impl_generics raw_struct::Viewable for #struct_name #vanilla_ty_generics #vanilla_where_clause {
326378
type Implementation<#IDENT_MEMORY_VIEW_T: raw_struct::MemoryView> = #struct_name #impl_ty_generics;
@@ -330,10 +382,12 @@ pub fn raw_struct(attr: TokenStream, input: TokenStream) -> Result<TokenStream>
330382
}
331383

332384
fn from_memory<#IDENT_MEMORY_VIEW_T: raw_struct::MemoryView>(memory: #IDENT_MEMORY_VIEW_T) -> Self::Implementation<#IDENT_MEMORY_VIEW_T> {
333-
#struct_name { memory, _type: Default::default() }
385+
#impl_construct_from_memory
334386
}
335387
}
336388

337389
#sized_impl
390+
391+
#deref_impl
338392
})
339393
}

0 commit comments

Comments
 (0)