pub struct VolatilePtr<'a, T, A = ReadWrite, O = VolatileOps>where
T: ?Sized,{ /* private fields */ }
Expand description
Wraps a pointer to make accesses to the referenced value volatile.
Allows volatile reads and writes on the referenced value. The referenced value needs to
be Copy
for reading and writing, as volatile reads and writes take and return copies
of the value.
Since not all volatile resources (e.g. memory mapped device registers) are both readable
and writable, this type supports limiting the allowed access types through an optional second
generic parameter A
that can be one of ReadWrite
, ReadOnly
, or WriteOnly
. It defaults
to ReadWrite
, which allows all operations.
The size of this struct is the same as the size of the contained reference.
Implementations§
Source§impl<'a, T> VolatilePtr<'a, T>where
T: ?Sized,
impl<'a, T> VolatilePtr<'a, T>where
T: ?Sized,
Constructor functions.
These functions construct new VolatilePtr
values. While the new
function creates a VolatilePtr
instance with unrestricted access, there
are also functions for creating read-only or write-only instances.
Sourcepub unsafe fn new(pointer: NonNull<T>) -> VolatilePtr<'a, T>
pub unsafe fn new(pointer: NonNull<T>) -> VolatilePtr<'a, T>
Turns the given pointer into a VolatilePtr
.
§Safety
- The given pointer must be valid.
- No other thread must have access to the given pointer. This must remain true
for the whole lifetime of the
VolatilePtr
.
Sourcepub const unsafe fn new_read_only(
pointer: NonNull<T>,
) -> VolatilePtr<'a, T, ReadOnly>
pub const unsafe fn new_read_only( pointer: NonNull<T>, ) -> VolatilePtr<'a, T, ReadOnly>
Sourcepub const unsafe fn new_restricted<A>(
access: A,
pointer: NonNull<T>,
) -> VolatilePtr<'a, T, A>where
A: Access,
pub const unsafe fn new_restricted<A>(
access: A,
pointer: NonNull<T>,
) -> VolatilePtr<'a, T, A>where
A: Access,
pub const unsafe fn new_restricted_with_ops<A, O>( access: A, ops: O, pointer: NonNull<T>, ) -> VolatilePtr<'a, T, A>
Source§impl<'a, T, A, O> VolatilePtr<'a, T, A, O>where
T: ?Sized,
impl<'a, T, A, O> VolatilePtr<'a, T, A, O>where
T: ?Sized,
Sourcepub fn read(self) -> Twhere
T: Copy,
A: Readable,
O: UnitaryOps<T>,
pub fn read(self) -> Twhere
T: Copy,
A: Readable,
O: UnitaryOps<T>,
Performs a volatile read of the contained value.
Returns a copy of the read value. Volatile reads are guaranteed not to be optimized
away by the compiler, but by themselves do not have atomic ordering
guarantees. To also get atomicity, consider looking at the Atomic
wrapper types of
the standard/core
library.
§Examples
use volatile::{VolatilePtr, access};
use core::ptr::NonNull;
let value = 42;
let pointer = unsafe {
VolatilePtr::new_restricted(access::ReadOnly, NonNull::from(&value))
};
assert_eq!(pointer.read(), 42);
Sourcepub fn write(self, value: T)where
T: Copy,
A: Writable,
O: UnitaryOps<T>,
pub fn write(self, value: T)where
T: Copy,
A: Writable,
O: UnitaryOps<T>,
Performs a volatile write, setting the contained value to the given value
.
Volatile writes are guaranteed to not be optimized away by the compiler, but by
themselves do not have atomic ordering guarantees. To also get atomicity, consider
looking at the Atomic
wrapper types of the standard/core
library.
§Example
use volatile::VolatilePtr;
use core::ptr::NonNull;
let mut value = 42;
let mut volatile = unsafe { VolatilePtr::new((&mut value).into()) };
volatile.write(50);
assert_eq!(volatile.read(), 50);
Sourcepub fn update<F>(self, f: F)
pub fn update<F>(self, f: F)
Updates the contained value using the given closure and volatile instructions.
Performs a volatile read of the contained value, passes it to the
function f
, and then performs a volatile write of the returned value back to
the target.
use volatile::VolatilePtr;
use core::ptr::NonNull;
let mut value = 42;
let mut volatile = unsafe { VolatilePtr::new((&mut value).into()) };
volatile.update(|val| val + 1);
assert_eq!(volatile.read(), 43);
Sourcepub fn as_raw_ptr(self) -> NonNull<T>
pub fn as_raw_ptr(self) -> NonNull<T>
Extracts the wrapped raw pointer.
§Example
use volatile::VolatilePtr;
use core::ptr::NonNull;
let mut value = 42;
let mut volatile = unsafe { VolatilePtr::new((&mut value).into()) };
volatile.write(50);
let unwrapped: *mut i32 = volatile.as_raw_ptr().as_ptr();
assert_eq!(unsafe { *unwrapped }, 50); // non volatile access, be careful!
Sourcepub unsafe fn map<F, U>(self, f: F) -> VolatilePtr<'a, U, A, O>
pub unsafe fn map<F, U>(self, f: F) -> VolatilePtr<'a, U, A, O>
Constructs a new VolatilePtr
by mapping the wrapped pointer.
This method is useful for accessing only a part of a volatile value, e.g. a subslice or
a struct field. For struct field access, there is also the safe
map_field
macro that wraps this function.
§Examples
Accessing a struct field:
use volatile::VolatilePtr;
use core::ptr::NonNull;
struct Example { field_1: u32, field_2: u8, }
let mut value = Example { field_1: 15, field_2: 255 };
let mut volatile = unsafe { VolatilePtr::new((&mut value).into()) };
// construct a volatile pointer to a field
let field_2 = unsafe { volatile.map(|ptr| NonNull::new(core::ptr::addr_of_mut!((*ptr.as_ptr()).field_2)).unwrap()) };
assert_eq!(field_2.read(), 255);
Don’t misuse this method to do a non-volatile read of the referenced value:
use volatile::VolatilePtr;
use core::ptr::NonNull;
let mut value = 5;
let mut volatile = unsafe { VolatilePtr::new((&mut value).into()) };
// DON'T DO THIS:
let mut readout = 0;
unsafe { volatile.map(|value| {
readout = *value.as_ptr(); // non-volatile read, might lead to bugs
value
})};
§Safety
The pointer returned by f
must satisfy the requirements of Self::new
.
Source§impl<'a, T, O> VolatilePtr<'a, T, ReadWrite, O>where
T: ?Sized,
impl<'a, T, O> VolatilePtr<'a, T, ReadWrite, O>where
T: ?Sized,
Methods for restricting access.
Sourcepub fn read_only(self) -> VolatilePtr<'a, T, ReadOnly, O>
pub fn read_only(self) -> VolatilePtr<'a, T, ReadOnly, O>
Restricts access permissions to read-only.
§Example
use volatile::VolatilePtr;
use core::ptr::NonNull;
let mut value: i16 = -4;
let mut volatile = unsafe { VolatilePtr::new((&mut value).into()) };
let read_only = volatile.read_only();
assert_eq!(read_only.read(), -4);
// read_only.write(10); // compile-time error
Sourcepub fn write_only(self) -> VolatilePtr<'a, T, WriteOnly, O>
pub fn write_only(self) -> VolatilePtr<'a, T, WriteOnly, O>
Restricts access permissions to write-only.
§Example
Creating a write-only pointer to a struct field:
use volatile::{VolatilePtr, map_field};
use core::ptr::NonNull;
struct Example { field_1: u32, field_2: u8, }
let mut value = Example { field_1: 15, field_2: 255 };
let mut volatile = unsafe { VolatilePtr::new((&mut value).into()) };
// construct a volatile write-only pointer to `field_2`
let mut field_2 = map_field!(volatile.field_2).write_only();
field_2.write(14);
// field_2.read(); // compile-time error
Source§impl<'a, T, A, O> VolatilePtr<'a, [T], A, O>
impl<'a, T, A, O> VolatilePtr<'a, [T], A, O>
Sourcepub fn index<I>(
self,
index: I,
) -> VolatilePtr<'a, <I as SliceIndex<[T]>>::Output, A, O>
pub fn index<I>( self, index: I, ) -> VolatilePtr<'a, <I as SliceIndex<[T]>>::Output, A, O>
Applies the index operation on the wrapped slice.
Returns a shared Volatile
reference to the resulting subslice.
This is a convenience method for the map(|slice| slice.index(index))
operation, so it
has the same behavior as the indexing operation on slice (e.g. panic if index is
out-of-bounds).
§Examples
Accessing a single slice element:
use volatile::VolatilePtr;
use core::ptr::NonNull;
let array = [1, 2, 3];
let slice = &array[..];
let volatile = unsafe { VolatilePtr::new_read_only(NonNull::from(slice)) };
assert_eq!(volatile.index(1).read(), 2);
Accessing a subslice:
use volatile::VolatilePtr;
use core::ptr::NonNull;
let array = [1, 2, 3];
let slice = &array[..];
let volatile = unsafe { VolatilePtr::new_read_only(NonNull::from(slice)) };
let subslice = volatile.index(1..);
assert_eq!(subslice.index(0).read(), 2);
Sourcepub fn iter(self) -> impl Iterator<Item = VolatilePtr<'a, T, A, O>>
pub fn iter(self) -> impl Iterator<Item = VolatilePtr<'a, T, A, O>>
Returns an iterator over the slice.
Sourcepub fn copy_into_slice(self, dst: &mut [T])
pub fn copy_into_slice(self, dst: &mut [T])
Copies all elements from self
into dst
, using a volatile memcpy.
The length of dst
must be the same as self
.
The method is only available with the unstable
feature enabled (requires a nightly
Rust compiler).
§Panics
This function will panic if the two slices have different lengths.
§Examples
Copying two elements from a volatile slice:
use volatile::VolatilePtr;
use core::ptr::NonNull;
let src = [1, 2];
// the `Volatile` type does not work with arrays, so convert `src` to a slice
let slice = &src[..];
let volatile = unsafe { VolatilePtr::new_read_only(NonNull::from(slice)) };
let mut dst = [5, 0, 0];
// Because the slices have to be the same length,
// we slice the destination slice from three elements
// to two. It will panic if we don't do this.
volatile.copy_into_slice(&mut dst[1..]);
assert_eq!(src, [1, 2]);
assert_eq!(dst, [5, 1, 2]);
Sourcepub fn copy_from_slice(self, src: &[T])
pub fn copy_from_slice(self, src: &[T])
Copies all elements from src
into self
, using a volatile memcpy.
The length of src
must be the same as self
.
This method is similar to the slice::copy_from_slice
method of the standard library. The
difference is that this method performs a volatile copy.
The method is only available with the unstable
feature enabled (requires a nightly
Rust compiler).
§Panics
This function will panic if the two slices have different lengths.
§Examples
Copying two elements from a slice into a volatile slice:
use volatile::VolatilePtr;
use core::ptr::NonNull;
let src = [1, 2, 3, 4];
let mut dst = [0, 0];
// the `Volatile` type does not work with arrays, so convert `dst` to a slice
let slice = &mut dst[..];
let mut volatile = unsafe { VolatilePtr::new(NonNull::from(slice)) };
// Because the slices have to be the same length,
// we slice the source slice from four elements
// to two. It will panic if we don't do this.
volatile.copy_from_slice(&src[2..]);
assert_eq!(src, [1, 2, 3, 4]);
assert_eq!(dst, [3, 4]);
Sourcepub fn copy_within(self, src: impl RangeBounds<usize>, dest: usize)
pub fn copy_within(self, src: impl RangeBounds<usize>, dest: usize)
Copies elements from one part of the slice to another part of itself, using a
volatile memmove
.
src
is the range within self
to copy from. dest
is the starting index of the
range within self
to copy to, which will have the same length as src
. The two ranges
may overlap. The ends of the two ranges must be less than or equal to self.len()
.
This method is similar to the slice::copy_within
method of the standard library. The
difference is that this method performs a volatile copy.
This method is only available with the unstable
feature enabled (requires a nightly
Rust compiler).
§Panics
This function will panic if either range exceeds the end of the slice, or if the end
of src
is before the start.
§Examples
Copying four bytes within a slice:
extern crate core;
use volatile::VolatilePtr;
use core::ptr::NonNull;
let mut byte_array = *b"Hello, World!";
let mut slice: &mut [u8] = &mut byte_array[..];
let mut volatile = unsafe { VolatilePtr::new(NonNull::from(slice)) };
volatile.copy_within(1..5, 8);
assert_eq!(&byte_array, b"Hello, Wello!");
Sourcepub fn split_at(
self,
mid: usize,
) -> (VolatilePtr<'a, [T], A, O>, VolatilePtr<'a, [T], A, O>)where
A: Access,
pub fn split_at(
self,
mid: usize,
) -> (VolatilePtr<'a, [T], A, O>, VolatilePtr<'a, [T], A, O>)where
A: Access,
Divides one slice into two at an index.
The first will contain all indices from [0, mid)
(excluding
the index mid
itself) and the second will contain all
indices from [mid, len)
(excluding the index len
itself).
§Panics
Panics if mid > len
.
Sourcepub fn as_chunks<const N: usize>(
self,
) -> (VolatilePtr<'a, [[T; N]], A, O>, VolatilePtr<'a, [T], A, O>)
pub fn as_chunks<const N: usize>( self, ) -> (VolatilePtr<'a, [[T; N]], A, O>, VolatilePtr<'a, [T], A, O>)
Splits the slice into a slice of N
-element arrays,
starting at the beginning of the slice,
and a remainder slice with length strictly less than N
.
§Panics
Panics if N
is 0.
Sourcepub unsafe fn as_chunks_unchecked<const N: usize>(
self,
) -> VolatilePtr<'a, [[T; N]], A, O>
pub unsafe fn as_chunks_unchecked<const N: usize>( self, ) -> VolatilePtr<'a, [[T; N]], A, O>
Splits the slice into a slice of N
-element arrays,
assuming that there’s no remainder.
§Safety
This may only be called when
- The slice splits exactly into
N
-element chunks (akaself.len() % N == 0
). N != 0
.
Source§impl<A, O> VolatilePtr<'_, [u8], A, O>
impl<A, O> VolatilePtr<'_, [u8], A, O>
Methods for volatile byte slices
Sourcepub fn fill(self, value: u8)
pub fn fill(self, value: u8)
Sets all elements of the byte slice to the given value
using a volatile memset
.
This method is similar to the slice::fill
method of the standard library, with the
difference that this method performs a volatile write operation. Another difference
is that this method is only available for byte slices (not general &mut [T]
slices)
because there currently isn’t a instrinsic function that allows non-u8
values.
This method is only available with the unstable
feature enabled (requires a nightly
Rust compiler).
§Example
use volatile::VolatilePtr;
use core::ptr::NonNull;
let mut vec = vec![0; 10];
let mut buf = unsafe { VolatilePtr::new(NonNull::from(vec.as_mut_slice())) };
buf.fill(1);
assert_eq!(unsafe { buf.as_raw_ptr().as_mut() }, &mut vec![1; 10]);
Source§impl<'a, T, A, O, const N: usize> VolatilePtr<'a, [T; N], A, O>
impl<'a, T, A, O, const N: usize> VolatilePtr<'a, [T; N], A, O>
Methods for converting arrays to slices
These methods are only available with the unstable
feature enabled (requires a nightly
Rust compiler).
Sourcepub fn as_slice(self) -> VolatilePtr<'a, [T], A, O>
pub fn as_slice(self) -> VolatilePtr<'a, [T], A, O>
Converts an array pointer to a slice pointer.
This makes it possible to use the methods defined on slices.
§Example
Copying two elements from a volatile array reference using copy_into_slice
:
use volatile::VolatilePtr;
use core::ptr::NonNull;
let src = [1, 2];
let volatile = unsafe { VolatilePtr::new_read_only(NonNull::from(&src)) };
let mut dst = [0, 0];
// convert the `Volatile<&[i32; 2]>` array reference to a `Volatile<&[i32]>` slice
let volatile_slice = volatile.as_slice();
// we can now use the slice methods
volatile_slice.copy_into_slice(&mut dst);
assert_eq!(dst, [1, 2]);
Trait Implementations§
Source§impl<T, A, O> Clone for VolatilePtr<'_, T, A, O>where
T: ?Sized,
impl<T, A, O> Clone for VolatilePtr<'_, T, A, O>where
T: ?Sized,
Source§fn clone(&self) -> VolatilePtr<'_, T, A, O>
fn clone(&self) -> VolatilePtr<'_, T, A, O>
1.0.0§fn clone_from(&mut self, source: &Self)
fn clone_from(&mut self, source: &Self)
source
. Read moreSource§impl<T, A, O> Debug for VolatilePtr<'_, T, A, O>where
T: ?Sized,
impl<T, A, O> Debug for VolatilePtr<'_, T, A, O>where
T: ?Sized,
impl<'a, T, A, O> Copy for VolatilePtr<'a, T, A, O>where
T: ?Sized,
Auto Trait Implementations§
impl<'a, T, A, O> Freeze for VolatilePtr<'a, T, A, O>where
T: ?Sized,
impl<'a, T, A, O> RefUnwindSafe for VolatilePtr<'a, T, A, O>where
A: RefUnwindSafe,
O: RefUnwindSafe,
T: RefUnwindSafe + ?Sized,
impl<'a, T, A = ReadWrite, O = VolatileOps> !Send for VolatilePtr<'a, T, A, O>
impl<'a, T, A = ReadWrite, O = VolatileOps> !Sync for VolatilePtr<'a, T, A, O>
impl<'a, T, A, O> Unpin for VolatilePtr<'a, T, A, O>where
A: Unpin,
O: Unpin,
T: ?Sized,
impl<'a, T, A, O> UnwindSafe for VolatilePtr<'a, T, A, O>where
T: RefUnwindSafe + ?Sized,
A: UnwindSafe,
O: UnwindSafe,
Blanket Implementations§
§impl<T> Any for Twhere
T: 'static + ?Sized,
impl<T> Any for Twhere
T: 'static + ?Sized,
§impl<T> Borrow<T> for Twhere
T: ?Sized,
impl<T> Borrow<T> for Twhere
T: ?Sized,
§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
§impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> CloneToUninit for Twhere
T: Clone,
§unsafe fn clone_to_uninit(&self, dst: *mut T)
unsafe fn clone_to_uninit(&self, dst: *mut T)
clone_to_uninit
)