#![cfg_attr(feature="const_fn", feature(const_fn))]
#![no_std]
use core::ptr;
#[derive(Debug)]
#[repr(transparent)]
pub struct Volatile<T: Copy>(T);
impl<T: Copy> Volatile<T> {
#[cfg(feature="const_fn")]
pub const fn new(value: T) -> Volatile<T> {
Volatile(value)
}
#[cfg(not(feature="const_fn"))]
pub fn new(value: T) -> Volatile<T> {
Volatile(value)
}
pub fn read(&self) -> T {
unsafe { ptr::read_volatile(&self.0) }
}
pub fn write(&mut self, value: T) {
unsafe { ptr::write_volatile(&mut self.0, value) };
}
pub fn update<F>(&mut self, f: F)
where F: FnOnce(&mut T)
{
let mut value = self.read();
f(&mut value);
self.write(value);
}
}
impl<T: Copy> Clone for Volatile<T> {
fn clone(&self) -> Self {
Volatile(self.read())
}
}
#[derive(Debug, Clone)]
pub struct ReadOnly<T: Copy>(Volatile<T>);
impl<T: Copy> ReadOnly<T> {
#[cfg(feature = "const_fn")]
pub const fn new(value: T) -> ReadOnly<T> {
ReadOnly(Volatile::new(value))
}
#[cfg(not(feature = "const_fn"))]
pub fn new(value: T) -> ReadOnly<T> {
ReadOnly(Volatile::new(value))
}
pub fn read(&self) -> T {
self.0.read()
}
}
#[derive(Debug, Clone)]
pub struct WriteOnly<T: Copy>(Volatile<T>);
impl<T: Copy> WriteOnly<T> {
#[cfg(feature = "const_fn")]
pub const fn new(value: T) -> WriteOnly<T> {
WriteOnly(Volatile::new(value))
}
#[cfg(not(feature = "const_fn"))]
pub fn new(value: T) -> WriteOnly<T> {
WriteOnly(Volatile::new(value))
}
pub fn write(&mut self, value: T) {
self.0.write(value)
}
}
pub type ReadWrite<T> = Volatile<T>;
#[cfg(test)]
mod tests {
use super::Volatile;
#[test]
fn test_read() {
assert_eq!(Volatile(42).read(), 42);
}
#[test]
fn test_write() {
let mut volatile = Volatile(42);
volatile.write(50);
assert_eq!(volatile.0, 50);
}
#[test]
fn test_update() {
let mut volatile = Volatile(42);
volatile.update(|v| *v += 1);
assert_eq!(volatile.0, 43);
}
#[test]
fn test_pointer_recast() {
let mut target_value = 0u32;
let target_ptr: *mut u32 = &mut target_value;
let volatile_ptr = target_ptr as *mut Volatile<u32>;
unsafe { (*volatile_ptr).write(42u32); }
assert_eq!(target_value, 42u32);
}
}