Skip to content

Commit d8a4fda

Browse files
committed
feat: explicitly populate memory access errors and improved proc-macro code
1 parent 0b6dd5a commit d8a4fda

File tree

16 files changed

+439
-247
lines changed

16 files changed

+439
-247
lines changed

Cargo.lock

Lines changed: 3 additions & 3 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ members = [
88
]
99

1010
[workspace.package]
11-
version = "0.1.3"
11+
version = "0.2.0"
1212
edition = "2021"
1313
authors = ["Markus Hadenfeldt <[email protected]>"]
1414
description = "raw_struct is a Rust procedural macro for easily declaring C-style structs that reference local or external memory, based on your memory implementation. It generates appropiate getter methods for easy access."

README.MD

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,17 @@
11
# raw_struct &emsp; [![Latest Version]][crates.io] [![License: GPL v3]](./LICENSE) [![GitHub build status]][actions]
22

3-
[License: GPL v3]: https://img.shields.io/badge/License-GPLv3-blue.svg
4-
[Latest Version]: https://img.shields.io/crates/v/raw_struct.svg
3+
[license: gpl v3]: https://img.shields.io/badge/License-GPLv3-blue.svg
4+
[latest version]: https://img.shields.io/crates/v/raw_struct.svg
55
[crates.io]: https://crates.io/crates/raw_struct
6-
[GitHub build status]: https://github.com/WolverinDEV/raw-struct/workflows/Rust/badge.svg?branch=master
6+
[github build status]: https://github.com/WolverinDEV/raw-struct/workflows/Rust/badge.svg?branch=master
77
[actions]: https://github.com/WolverinDEV/raw-struct/actions?query=workflow%3ARust
88

99
`raw_struct` is a Rust procedural macro for easily declaring C-style structs that reference local or external memory, based on your memory implementation. It generates appropiate getter methods for easy access. This crate has support for `no_std` environments.
1010

1111
## Usage
12+
1213
To use `raw_struct`, simply define a struct with the raw_struct attribute as following:
14+
1315
```rust
1416
#[raw_struct(size = 0x10)]
1517
struct MyStruct {
@@ -25,10 +27,11 @@ struct MyStruct {
2527
```
2628

2729
To reference the declared struct in memory you can ether do so by `Reference` or `Copy`:
30+
2831
```rust
2932
let memory = [0u8; 0x10];
3033
{
31-
let object = Reference::<dyn MyStruct>::new(0x00, Arc::new(memory.clone()));
34+
let object = Reference::<dyn MyStruct, _>::new(0x00, Arc::new(memory.clone()));
3235
println!("field_a = {}", object.field_a()?);
3336
println!("field_b = {}", object.field_b()?);
3437
}
@@ -41,9 +44,15 @@ let memory = [0u8; 0x10];
4144
```
4245

4346
## Examples
47+
4448
Examples can be found within the examples directory of this repository. These examples demonstrate how to use raw_struct in various contexts.
4549

4650
To run the examples, clone the repository and use the following command:
51+
4752
```bash
4853
cargo run --bin <example_name>
49-
```
54+
```
55+
56+
## Performance
57+
58+
In release mode, accessing `raw_structs` behind a `Copy<...>` is as efficient as general memory accesses, with **zero overhead**.

examples/dyn_memory/src/main.rs

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
use std::{
22
self,
33
error::Error,
4-
marker,
4+
marker::{
5+
self,
6+
},
57
};
68

79
use raw_struct::{
@@ -12,12 +14,16 @@ use raw_struct::{
1214
};
1315

1416
fn main() -> Result<(), Box<dyn Error + Send + Sync>> {
17+
/*
18+
* Note:
19+
* Accessing all the container entries evaluates in release mode to just a mov instruction.
20+
*/
1521
let buffer = [0x1122u64, 0x8877, 0x9988];
1622
let object = Copy::<dyn Container<u64>>::read_object(&buffer, 0x00)?;
1723

1824
println!(
1925
"Memory size: 0x{:X}",
20-
<dyn Container::<u64> as Viewable<_>>::MEMORY_SIZE
26+
<dyn Container::<u64> as Viewable>::MEMORY_SIZE
2127
);
2228
println!("Vat a = 0x{:X}", object.var_a()?);
2329
println!("Inner = 0x{:X}", object.inner()?);

examples/minimal/src/main.rs

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -18,18 +18,15 @@ use raw_struct::{
1818
};
1919

2020
fn main() -> Result<(), Box<dyn Error + Send + Sync>> {
21-
let mut memory = [0u8; 0x20];
21+
let mut memory = [0u8; 0x40];
2222
memory[0..4].copy_from_slice(&0x6Fu32.to_le_bytes());
2323
memory[4..8].copy_from_slice(&0x99u32.to_le_bytes());
2424

25-
println!(
26-
"{}",
27-
<dyn MyStruct as Viewable::<dyn MyStruct>>::MEMORY_SIZE
28-
);
25+
println!("{}", <dyn MyStruct as Viewable>::MEMORY_SIZE);
2926

3027
let memory = Arc::new(memory);
3128
{
32-
let object = Reference::<dyn MyStruct>::new(memory.clone(), 0x00);
29+
let object = Reference::<dyn MyStruct, _>::new(memory.clone(), 0x00);
3330
println!("field_a = {}", object.field_a()?);
3431
println!("field_b = {}", object.field_b()?);
3532
}

raw_struct/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ description.workspace = true
1010
readme = "../README.MD"
1111

1212
[dependencies]
13-
raw_struct_derive = { version = "0.1", path = "../raw_struct_derive" }
13+
raw_struct_derive = { version = "0.2", path = "../raw_struct_derive" }
1414

1515
[features]
1616
no_std = []

raw_struct/src/builtins/array.rs

Lines changed: 25 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,11 @@ pub trait Array<T: ?Sized> {
3030
}
3131

3232
impl<T: FromMemoryView> dyn Array<T> {
33-
pub fn element_at(&self, memory: &dyn MemoryView, index: usize) -> Result<T, AccessError> {
33+
pub fn element_at<E>(
34+
&self,
35+
memory: &dyn MemoryView<Error = E>,
36+
index: usize,
37+
) -> Result<T, AccessError<E>> {
3438
let offset = (index * mem::size_of::<T>()) as u64;
3539
T::read_object(memory, self.start_address() + offset).map_err(|err| AccessError {
3640
source: err,
@@ -42,11 +46,11 @@ impl<T: FromMemoryView> dyn Array<T> {
4246
})
4347
}
4448

45-
pub fn elements(
49+
pub fn elements<E>(
4650
&self,
47-
memory: &dyn MemoryView,
51+
memory: &dyn MemoryView<Error = E>,
4852
range: Range<usize>,
49-
) -> Result<Vec<T>, AccessError> {
53+
) -> Result<Vec<T>, AccessError<E>> {
5054
let element_count = range.end - range.start;
5155
let mut result = Vec::with_capacity(element_count);
5256

@@ -75,17 +79,21 @@ impl<T: FromMemoryView> dyn Array<T> {
7579
}
7680
}
7781

78-
impl<T: ?Sized + Viewable<T>> dyn Array<T> {
79-
pub fn element_reference(&self, memory: Arc<dyn MemoryView>, index: usize) -> Reference<T> {
82+
impl<T: ?Sized + Viewable> dyn Array<T> {
83+
pub fn element_reference<E: 'static>(
84+
&self,
85+
memory: Arc<dyn MemoryView<Error = E>>,
86+
index: usize,
87+
) -> Reference<T, E> {
8088
let offset = (index * T::MEMORY_SIZE) as u64;
8189
Reference::new(memory, self.start_address() + offset)
8290
}
8391

84-
pub fn elements_reference(
92+
pub fn elements_reference<E: 'static>(
8593
&self,
86-
memory: Arc<dyn MemoryView>,
94+
memory: Arc<dyn MemoryView<Error = E>>,
8795
range: Range<usize>,
88-
) -> Vec<Reference<T>> {
96+
) -> Vec<Reference<T, E>> {
8997
Vec::from_iter(range.map(|index| {
9098
Reference::new(
9199
memory.clone(),
@@ -95,15 +103,15 @@ impl<T: ?Sized + Viewable<T>> dyn Array<T> {
95103
}
96104
}
97105

98-
impl<T: ?Sized + Viewable<T>> dyn Array<T>
106+
impl<T: ?Sized + Viewable> dyn Array<T>
99107
where
100-
T::Implementation<T::Memory>: marker::Copy,
108+
T::Instance<T::Memory>: marker::Copy,
101109
{
102-
pub fn element_copy(
110+
pub fn element_copy<E>(
103111
&self,
104-
memory: &dyn MemoryView,
112+
memory: &dyn MemoryView<Error = E>,
105113
index: usize,
106-
) -> Result<Copy<T>, AccessError> {
114+
) -> Result<Copy<T>, AccessError<E>> {
107115
let offset = (index * T::MEMORY_SIZE) as u64;
108116
Copy::read_object(memory, self.start_address() + offset).map_err(|err| AccessError {
109117
source: err,
@@ -115,11 +123,11 @@ where
115123
})
116124
}
117125

118-
pub fn elements_copy(
126+
pub fn elements_copy<E>(
119127
&self,
120-
memory: &dyn MemoryView,
128+
memory: &dyn MemoryView<Error = E>,
121129
range: Range<usize>,
122-
) -> Result<Vec<Copy<T>>, AccessError> {
130+
) -> Result<Vec<Copy<T>>, AccessError<E>> {
123131
let element_count = range.end - range.start;
124132
let mut result = Vec::<T::Memory>::with_capacity(element_count);
125133

raw_struct/src/builtins/ptr.rs

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,10 @@ impl<T: ?Sized> Ptr64<T> {
5454
impl<T: marker::Copy> Ptr64<T> {
5555
/// Create a copy of the value the pointer points to
5656
#[must_use = "copied result must be used"]
57-
pub fn read_value(&self, memory: &dyn MemoryView) -> Result<Option<T>, AccessError> {
57+
pub fn read_value<E>(
58+
&self,
59+
memory: &dyn MemoryView<Error = E>,
60+
) -> Result<Option<T>, AccessError<E>> {
5861
if self.address > 0 {
5962
let memory = T::read_object(memory, self.address).map_err(|err| AccessError {
6063
source: err,
@@ -74,9 +77,12 @@ impl<T: marker::Copy> Ptr64<T> {
7477
}
7578
}
7679

77-
impl<T: ?Sized + Viewable<T>> Ptr64<T> {
80+
impl<T: ?Sized + Viewable> Ptr64<T> {
7881
#[must_use]
79-
pub fn value_reference(&self, memory: Arc<dyn MemoryView>) -> Option<Reference<T>> {
82+
pub fn value_reference<E: 'static>(
83+
&self,
84+
memory: Arc<dyn MemoryView<Error = E>>,
85+
) -> Option<Reference<T, E>> {
8086
if self.address > 0 {
8187
Some(Reference::new(memory, self.address))
8288
} else {
@@ -86,7 +92,10 @@ impl<T: ?Sized + Viewable<T>> Ptr64<T> {
8692

8793
/// Create a copy of the value the pointer points to
8894
#[must_use = "copied result must be used"]
89-
pub fn value_copy(&self, memory: &dyn MemoryView) -> Result<Option<Copy<T>>, AccessError> {
95+
pub fn value_copy<E>(
96+
&self,
97+
memory: &dyn MemoryView<Error = E>,
98+
) -> Result<Option<Copy<T>>, AccessError<E>> {
9099
if self.address > 0 {
91100
let memory =
92101
T::Memory::read_object(memory, self.address).map_err(|err| AccessError {

raw_struct/src/copy.rs

Lines changed: 12 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -4,21 +4,18 @@ use core::{
44
ops::Deref,
55
};
66

7-
use crate::{
8-
view::Viewable,
9-
ViewableImplementation,
10-
};
7+
use crate::view::Viewable;
118

129
/// A Copy represents an owned copy of the struct binary contents
1310
#[repr(transparent)]
14-
pub struct Copy<T: ?Sized + Viewable<T>> {
15-
inner: T::Implementation<T::Memory>,
11+
pub struct Copy<T: ?Sized + Viewable> {
12+
inner: T::Instance<T::Memory>,
1613
}
1714

18-
impl<T: ?Sized + Viewable<T>> Copy<T> {
15+
impl<T: ?Sized + Viewable> Copy<T> {
1916
pub fn new(inner: T::Memory) -> Self {
2017
Self {
21-
inner: T::create(inner),
18+
inner: T::create_view(inner),
2219
}
2320
}
2421

@@ -30,18 +27,18 @@ impl<T: ?Sized + Viewable<T>> Copy<T> {
3027
}
3128
}
3229

33-
impl<T: ?Sized + Viewable<T>> Deref for Copy<T> {
34-
type Target = T;
30+
impl<T: ?Sized + Viewable> Deref for Copy<T> {
31+
type Target = T::Instance<T::Memory>;
3532

3633
fn deref(&self) -> &Self::Target {
37-
self.inner.as_trait()
34+
&self.inner
3835
}
3936
}
4037

4138
impl<T> Clone for Copy<T>
4239
where
43-
T: ?Sized + Viewable<T>,
44-
T::Implementation<T::Memory>: Clone,
40+
T: ?Sized + Viewable,
41+
T::Instance<T::Memory>: Clone,
4542
{
4643
fn clone(&self) -> Self {
4744
Self {
@@ -52,7 +49,7 @@ where
5249

5350
impl<T> marker::Copy for Copy<T>
5451
where
55-
T: ?Sized + Viewable<T>,
56-
T::Implementation<T::Memory>: marker::Copy,
52+
T: ?Sized + Viewable,
53+
T::Instance<T::Memory>: marker::Copy,
5754
{
5855
}

raw_struct/src/error.rs

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,16 @@
11
use alloc::{
22
borrow::Cow,
3-
boxed::Box,
43
format,
54
};
65
#[cfg(feature = "no_std")]
76
pub use core::error::Error as ErrorType;
8-
use core::fmt;
7+
use core::{
8+
convert::Infallible,
9+
fmt,
10+
};
911
#[cfg(not(feature = "no_std"))]
1012
pub use std::error::Error as ErrorType;
1113

12-
pub type Error = Box<dyn ErrorType + Send + Sync + 'static>;
13-
1414
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
1515
pub enum AccessMode {
1616
Read,
@@ -38,8 +38,8 @@ impl fmt::Display for AccessViolation {
3838
impl ErrorType for AccessViolation {}
3939

4040
#[derive(Debug)]
41-
pub struct AccessError {
42-
pub source: Error,
41+
pub struct AccessError<S = Infallible> {
42+
pub source: S,
4343

4444
pub offset: u64,
4545
pub size: usize,
@@ -49,7 +49,7 @@ pub struct AccessError {
4949
pub member: Option<Cow<'static, str>>,
5050
}
5151

52-
impl fmt::Display for AccessError {
52+
impl<S: fmt::Display> fmt::Display for AccessError<S> {
5353
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
5454
write!(
5555
f,
@@ -67,8 +67,8 @@ impl fmt::Display for AccessError {
6767
}
6868
}
6969

70-
impl ErrorType for AccessError {
70+
impl<S: ErrorType + 'static> ErrorType for AccessError<S> {
7171
fn source(&self) -> Option<&(dyn ErrorType + 'static)> {
72-
Some(&*self.source)
72+
Some(&self.source)
7373
}
7474
}

0 commit comments

Comments
 (0)