Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
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
1 change: 1 addition & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,5 +45,6 @@ pub use volatile_ptr::VolatilePtr;
pub use volatile_ref::VolatileRef;

pub mod access;
pub mod ops;
mod volatile_ptr;
mod volatile_ref;
49 changes: 49 additions & 0 deletions src/ops.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
#![allow(missing_docs)]

use core::ptr;

#[cfg(feature = "unstable")]
use core::intrinsics;

pub trait Ops: Copy + Default {}

pub trait UnitaryOps<T>: Ops {
unsafe fn read(src: *const T) -> T;
unsafe fn write(dst: *mut T, src: T);
}

pub trait BulkOps<T>: Ops {
unsafe fn memmove(dst: *mut T, src: *const T, count: usize);
unsafe fn memcpy(dst: *mut T, src: *const T, count: usize);
unsafe fn memset(dst: *mut T, val: u8, count: usize);
}

#[derive(Default, Copy, Clone)]
pub struct VolatileOps;

impl Ops for VolatileOps {}

impl<T> UnitaryOps<T> for VolatileOps {
unsafe fn read(src: *const T) -> T {
unsafe { ptr::read_volatile(src) }
}

unsafe fn write(dst: *mut T, src: T) {
unsafe { ptr::write_volatile(dst, src) }
}
}

#[cfg(feature = "unstable")]
impl<T> BulkOps<T> for VolatileOps {
unsafe fn memmove(dst: *mut T, src: *const T, count: usize) {
unsafe { intrinsics::volatile_copy_memory(dst, src, count) }
}

unsafe fn memcpy(dst: *mut T, src: *const T, count: usize) {
unsafe { intrinsics::volatile_copy_nonoverlapping_memory(dst, src, count) }
}

unsafe fn memset(dst: *mut T, val: u8, count: usize) {
unsafe { intrinsics::volatile_set_memory(dst, val, count) }
}
}
11 changes: 6 additions & 5 deletions src/volatile_ptr/mod.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use core::{fmt, marker::PhantomData, ptr::NonNull};

use crate::access::ReadWrite;
use crate::{access::ReadWrite, ops::VolatileOps};

mod macros;
mod operations;
Expand All @@ -25,18 +25,19 @@ mod very_unstable;
///
/// The size of this struct is the same as the size of the contained reference.
#[repr(transparent)]
pub struct VolatilePtr<'a, T, A = ReadWrite>
pub struct VolatilePtr<'a, T, A = ReadWrite, O = VolatileOps>
where
T: ?Sized,
{
pointer: NonNull<T>,
reference: PhantomData<&'a T>,
access: PhantomData<A>,
ops: PhantomData<O>,
}

impl<'a, T, A> Copy for VolatilePtr<'a, T, A> where T: ?Sized {}
impl<'a, T, A, O> Copy for VolatilePtr<'a, T, A, O> where T: ?Sized {}

impl<T, A> Clone for VolatilePtr<'_, T, A>
impl<T, A, O> Clone for VolatilePtr<'_, T, A, O>
where
T: ?Sized,
{
Expand All @@ -45,7 +46,7 @@ where
}
}

impl<T, A> fmt::Debug for VolatilePtr<'_, T, A>
impl<T, A, O> fmt::Debug for VolatilePtr<'_, T, A, O>
where
T: Copy + fmt::Debug + ?Sized,
{
Expand Down
48 changes: 33 additions & 15 deletions src/volatile_ptr/operations.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,8 @@
use core::{
marker::PhantomData,
ptr::{self, NonNull},
};
use core::{marker::PhantomData, ptr::NonNull};

use crate::{
access::{Access, ReadOnly, ReadWrite, Readable, Writable, WriteOnly},
ops::{Ops, UnitaryOps},
VolatilePtr,
};

Expand Down Expand Up @@ -50,16 +48,32 @@ where
unsafe { Self::new_generic(pointer) }
}

pub(super) const unsafe fn new_generic<A>(pointer: NonNull<T>) -> VolatilePtr<'a, T, A> {
#[allow(missing_docs)]
pub const unsafe fn new_restricted_with_ops<A, O>(
access: A,
ops: O,
pointer: NonNull<T>,
) -> VolatilePtr<'a, T, A>
where
A: Access,
O: Ops,
{
let _ = access;
let _ = ops;
unsafe { Self::new_generic(pointer) }
}

pub(crate) const unsafe fn new_generic<A, O>(pointer: NonNull<T>) -> VolatilePtr<'a, T, A, O> {
VolatilePtr {
pointer,
reference: PhantomData,
access: PhantomData,
ops: PhantomData,
}
}
}

impl<'a, T, A> VolatilePtr<'a, T, A>
impl<'a, T, A, O> VolatilePtr<'a, T, A, O>
where
T: ?Sized,
{
Expand All @@ -86,8 +100,9 @@ where
where
T: Copy,
A: Readable,
O: UnitaryOps<T>,
{
unsafe { ptr::read_volatile(self.pointer.as_ptr()) }
unsafe { O::read(self.pointer.as_ptr()) }
}

/// Performs a volatile write, setting the contained value to the given `value`.
Expand All @@ -112,8 +127,9 @@ where
where
T: Copy,
A: Writable,
O: UnitaryOps<T>,
{
unsafe { ptr::write_volatile(self.pointer.as_ptr(), value) };
unsafe { O::write(self.pointer.as_ptr(), value) };
}

/// Updates the contained value using the given closure and volatile instructions.
Expand All @@ -136,6 +152,7 @@ where
where
T: Copy,
A: Readable + Writable,
O: UnitaryOps<T>,
F: FnOnce(T) -> T,
{
let new = f(self.read());
Expand Down Expand Up @@ -204,18 +221,19 @@ where
/// ## Safety
///
/// The pointer returned by `f` must satisfy the requirements of [`Self::new`].
pub unsafe fn map<F, U>(self, f: F) -> VolatilePtr<'a, U, A>
pub unsafe fn map<F, U>(self, f: F) -> VolatilePtr<'a, U, A, O>
where
F: FnOnce(NonNull<T>) -> NonNull<U>,
A: Access,
O: Ops,
U: ?Sized,
{
unsafe { VolatilePtr::new_restricted(A::default(), f(self.pointer)) }
unsafe { VolatilePtr::new_generic::<A, O>(f(self.pointer)) }
}
}

/// Methods for restricting access.
impl<'a, T> VolatilePtr<'a, T, ReadWrite>
impl<'a, T, O> VolatilePtr<'a, T, ReadWrite, O>
where
T: ?Sized,
{
Expand All @@ -234,8 +252,8 @@ where
/// assert_eq!(read_only.read(), -4);
/// // read_only.write(10); // compile-time error
/// ```
pub fn read_only(self) -> VolatilePtr<'a, T, ReadOnly> {
unsafe { VolatilePtr::new_restricted(ReadOnly, self.pointer) }
pub fn read_only(self) -> VolatilePtr<'a, T, ReadOnly, O> {
unsafe { VolatilePtr::new_generic::<ReadOnly, O>(self.pointer) }
}

/// Restricts access permissions to write-only.
Expand All @@ -257,7 +275,7 @@ where
/// field_2.write(14);
/// // field_2.read(); // compile-time error
/// ```
pub fn write_only(self) -> VolatilePtr<'a, T, WriteOnly> {
unsafe { VolatilePtr::new_restricted(WriteOnly, self.pointer) }
pub fn write_only(self) -> VolatilePtr<'a, T, WriteOnly, O> {
unsafe { VolatilePtr::new_generic::<WriteOnly, O>(self.pointer) }
}
}
Loading