I'm developing a library that works with PE files for both 32- and 64-bit architectures. Some structures will reference both virtual addresses (VA, e.g. ImageBase
) and relative virtual addresses (RVA, e.g. section offset), for example:
type VA32 = u32;
type RVA32 = i32;
struct Header32 {
image_base: VA32,
section_offsets: Vec<RVA32>,
}
let hdr = Header32 { /* ... */ };
When dealing with 32-bit PE files, a VA should be 32-bits and unsigned, and an RVA should be 32-bits and signed. For 64-bit PE files, both types should be 64-bits.
I'd like my structs to use the appropriate width for these types, probably by making them generic:
struct Header<VA, RVA> {
image_base: VA,
section_offsets: Vec<RVA>,
}
type VA32 = u32;
type RVA32 = i32;
let hdr: Header<VA32, RVA32> = Header { /* ... */ };
But VA32
only ever goes with RVA32
, and VA64
should only ever be provided with RVA64
. Is there an idiomatic way that I can express this?
Using a completely made up syntax, I desire to do something like:
struct Header<Arch> {
image_base: arch.VA,
section_offsets: Vec<arch.RVA>,
}
type Arch32 = { VA: u32, RVA: i32 }
let hdr: Header<Arch32> = Header { /* ... */ };
You can do something similar to your made up syntax using traits with associated types and zero sized structs as markers.
trait Arch {
type VA;
type RVA;
}
#[derive(Debug)]
struct Arch32;
impl Arch for Arch32 {
type VA = u32;
type RVA = i32;
}
#[derive(Debug)]
struct Arch64;
impl Arch for Arch64 {
type VA = u64;
type RVA = i64;
}
#[derive(Debug)]
struct Header<T: Arch> {
image_base: T::VA,
section_offsets: Vec<T::RVA>,
}
playground
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With