10000 Rewrite crate to operate on reference values by phil-opp · Pull Request #13 · rust-osdev/volatile · GitHub
[go: up one dir, main page]

Skip to content

Rewrite crate to operate on reference values #13

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 31 commits into from
Sep 21, 2020
Merged
Changes from 1 commit
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
277b25b
Different rewrite approaches
phil-opp Jul 29, 2020
93fb1e1
Decide for foo.rs approach
phil-opp Jul 29, 2020
8be4430
Update documentation
phil-opp Jul 29, 2020
401a86b
Remove const_fn cargo feature
phil-opp Jul 29, 2020
59dd91d
Reorganize access module and make it public
phil-opp Jul 29, 2020
53fd257
Add constructor methods for read/write-only types
phil-opp Jul 29, 2020
b469f42
Make methods generic using `Deref` trait
phil-opp Jul 29, 2020
d0bcea2
Add methods for working with volatile slices
phil-opp Jul 29, 2020
1b4931d
Document `copy_into_slice` method
phil-opp Jul 29, 2020
4766a43
Add `as_slice`/`as_mut_slice` methods for volatile array references
phil-opp Jul 30, 2020
cfbd66e
Rename the 'nightly' feature to 'unstable'
phil-opp Jul 31, 2020
bf8031c
Document constructor functions
phil-opp Jul 31, 2020
93e7150
Provide a custom fmt::Debug implementation to prevent reading of writ…
phil-opp Jul 31, 2020
8682a86
Improve documentation of `Volatile::new`
phil-opp Jul 31, 2020
46a7603
Warn on missing documentation
phil-opp Jul 31, 2020
7dffe2c
Improve documentation
phil-opp Aug 19, 2020
dfbaa68
Run cargo fmt
phil-opp Aug 19, 2020
76e7657
Don't derive Default
phil-opp Aug 19, 2020
4ba88d3
Add `map`/`map_mut`/`extract_inner` methods
phil-opp Aug 19, 2020
fb7e6a5
Use map/map_mut for index/index_mut implementation
phil-opp Aug 19, 2020
a78fd04
Use map/map_mut for array to slice conversion methods
phil-opp Aug 19, 2020
eabda2e
Add documentation for slice index methods
phil-opp Aug 19, 2020
2e272d6
Fix typo in docs
phil-opp Aug 19, 2020
d120638
Change order of impl blocks to show `read`/`write` methods first in docs
phil-opp Aug 19, 2020
966bea9
Enable `unstable` feature when building docs on docs.rs
phil-opp Aug 19, 2020
408a5f1
Create a CI workflow
phil-opp Aug 19, 2020
9bc9f95
Fix as_slice/as_mut_slice
phil-opp Aug 19, 2020
267ef61
Add `fill` and `copy_within` methods for slices
phil-opp Sep 9, 2020
401c5ba
Derive `Debug` and `Clone` for access types
phil-opp Sep 21, 2020
a4ccd3d
Document new slice methods
phil-opp Sep 21, 2020
2eaa1d6
Update check_range call for latest nightly
phil-opp Sep 21, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Add map/map_mut/extract_inner methods
  • Loading branch information
phil-opp committed Aug 19, 2020
commit 4ba88d3f68ba05ee9aaee57abccfe9f74bca80a3
161 changes: 161 additions & 0 deletions src/lib.rs
10000
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,147 @@ impl<R> Volatile<R> {
}
}

/// Method for extracting the wrapped value.
impl<R, A> Volatile<R, A> {
/// Extracts the inner value stored in the wrapper type.
///
/// This method gives direct access to the wrapped reference and thus allows
/// non-volatile access again. This is seldom what you want since there is usually
/// a reason that a reference is wrapped in `Volatile`. However, in some cases it might
/// be required or useful to use the `read_volatile`/`write_volatile` pointer methods of
/// the standard library directly, which this method makes possible.
///
/// Since no memory safety violation can occur when accessing the referenced value using
/// non-volatile operations, this method is safe. However, it _can_ lead to bugs at the
/// application level, so this method should be used with care.
///
/// ## Example
///
/// ```
/// use volatile::Volatile;
///
/// let mut value = 42;
/// let mut volatile = Volatile::new(&mut value);
/// volatile.write(50);
/// let unwrapped: &mut i32 = volatile.extract_inner();
///
/// assert_eq!(*unwrapped, 50); // non volatile access, be careful!
/// ```
pub fn extract_inner(self) -> R {
self.reference
}
}

/// Transformation methods for accessing struct fields
impl<R, T, A> Volatile<R, A>
where
R: Deref<Target = T>,
T: ?Sized,
{
/// Constructs a new `Volatile` reference by mapping the wrapped value.
///
/// This method is useful for accessing individual fields of volatile structs.
///
/// Note that this method gives temporary access to the wrapped reference, which allows
/// accessing the value in a non-volatile way. This is normally not what you want, so
/// **this method should only be used for reference-to-reference transformations**.
///
/// ## Examples
///
/// Accessing a struct field:
///
/// ```
/// use volatile::Volatile;
///
/// struct Example { field_1: u32, field_2: u8, }
/// let mut value = Example { field_1: 15, field_2: 255 };
/// let mut volatile = Volatile::new(&mut value);
///
/// // construct a volatile reference to a field
/// let field_2 = volatile.map(|example| &example.field_2);
/// assert_eq!(field_2.read(), 255);
/// ```
///
/// Don't misuse this method to do a non-volatile read of the referenced value:
///
/// ```
/// use volatile::Volatile;
///
/// let mut value = 5;
/// let mut volatile = Volatile::new(&mut value);
///
/// // DON'T DO THIS:
/// let mut readout = 0;
/// volatile.map(|value| {
/// readout = *value; // non-volatile read, might lead to bugs
/// value
/// });
/// ```
pub fn map<'a, F, U>(&'a self, f: F) -> Volatile<&'a U, A>
where
F: FnOnce(&'a T) -> &'a U,
U: ?Sized,
T: 'a,
{
Volatile {
reference: f(self.reference.deref()),
access: self.access,
}
}

/// Constructs a new mutable `Volatile` reference by mapping the wrapped value.
///
/// This method is useful for accessing individual fields of volatile structs.
///
/// Note that this method gives temporary access to the wrapped reference, which allows
/// accessing the value in a non-volatile way. This is normally not what you want, so
/// **this method should only be used for reference-to-reference transformations**.
///
/// ## Examples
///
/// Accessing a struct field:
///
/// ```
/// use volatile::Volatile;
///
/// struct Example { field_1: u32, field_2: u8, }
/// let mut value = Example { field_1: 15, field_2: 255 };
/// let mut volatile = Volatile::new(&mut value);
///
/// // construct a volatile reference to a field
/// let mut field_2 = volatile.map_mut(|example| &mut example.field_2);
/// field_2.write(128);
/// assert_eq!(field_2.read(), 128);
/// ```
///
/// Don't misuse this method to do a non-volatile read or write of the referenced value:
///
/// ```
/// use volatile::Volatile;
///
/// let mut value = 5;
/// let mut volatile = Volatile::new(&mut value);
///
/// // DON'T DO THIS:
/// volatile.map_mut(|value| {
/// *value = 10; // non-volatile write, might lead to bugs
/// value
/// });
/// ```
pub fn map_mut<'a, F, U>(&'a mut self, f: F) -> Volatile<&'a mut U, A>
where
F: FnOnce(&mut T) -> &mut U,
R: DerefMut,
U: ?Sized,
T: 'a,
{
Volatile {
reference: f(&mut self.reference),
access: self.access,
}
}
}

/// Methods for references to `Copy` types
impl<R, T, A> Volatile<R, A>
where
Expand Down Expand Up @@ -501,4 +642,24 @@ mod tests {
volatile.index_mut(0).update(|v| *v += 1);
assert_eq!(val, [2, 2, 3]);
}

#[test]
fn test_struct() {
struct S {
field_1: u32,
field_2: bool,
}

let mut val = S {
field_1: 60,
field_2: true,
};
let mut volatile = Volatile::new(&mut val);
volatile.map_mut(|s| &mut s.field_1).update(|v| *v += 1);
let mut field_2 = volatile.map_mut(|s| &mut s.field_2);
assert!(field_2.read());
field_2.write(false);
assert_eq!(volatile.map(|s| &s.field_1).read(), 61);
assert_eq!(volatile.map(|s| &s.field_2).read(), false);
}
}
0