volatile-0.3.0/.cargo_vcs_info.json0000644000000001121371024437000127440ustar00{ "git": { "sha1": "51855f4be297e0dcbac9fe01e647f3bfa2a4d02f" } } volatile-0.3.0/.gitignore010066400017500001750000000000221371021762700135440ustar0000000000000000target Cargo.lock volatile-0.3.0/Cargo.toml0000644000000021601371024437000107470ustar00# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO # # When uploading crates to the registry Cargo will automatically # "normalize" Cargo.toml files for maximal compatibility # with all versions of Cargo and also rewrite `path` dependencies # to registry (e.g., crates.io) dependencies # # If you believe there's an error in this file please file an # issue against the rust-lang/cargo repository. If you're # editing this file be aware that the upstream Cargo.toml # will likely look very different (and much more reasonable) [package] name = "volatile" version = "0.3.0" authors = ["Philipp Oppermann "] description = "A simple volatile wrapper type" documentation = "https://docs.rs/volatile" keywords = ["volatile"] license = "MIT OR Apache-2.0" repository = "https://github.com/phil-opp/volatile" [package.metadata.release] no-dev-version = true pre-release-commit-message = "Release version {{version}}" [[package.metadata.release.pre-release-replacements]] exactly = 1 file = "Changelog.md" replace = "# Unreleased\n\n# {{version}} – {{date}}" search = "# Unreleased" [dependencies] [features] const_fn = [] volatile-0.3.0/Cargo.toml.orig010066400017500001750000000011201371024436600144430ustar0000000000000000[package] name = "volatile" version = "0.3.0" authors = ["Philipp Oppermann "] license = "MIT OR Apache-2.0" keywords = ["volatile"] description = "A simple volatile wrapper type" documentation = "https://docs.rs/volatile" repository = "https://github.com/phil-opp/volatile" [dependencies] [features] const_fn = [] [package.metadata.release] no-dev-version = true pre-release-replacements = [ { file="Changelog.md", search="# Unreleased", replace="# Unreleased\n\n# {{version}} – {{date}}", exactly=1 }, ] pre-release-commit-message = "Release version {{version}}" volatile-0.3.0/Changelog.md010066400017500001750000000004561371024436600140000ustar0000000000000000# Unreleased # 0.3.0 – 2020-07-29 - **Breaking:** Remove `Debug` and `Clone` derives for `WriteOnly` ([#12](https://github.com/rust-osdev/volatile/pull/12)) # 0.2.7 – 2020-07-29 - Derive `Default` for `Volatile`, `WriteOnly` and `ReadOnly` ([#10](https://github.com/embed-rs/volatile/pull/10)) volatile-0.3.0/src/lib.rs010066400017500001750000000206411371024422200134570ustar0000000000000000#![cfg_attr(feature = "const_fn", feature(const_fn))] //! Provides wrapper types `Volatile`, `ReadOnly`, `WriteOnly`, `ReadWrite`, which wrap any copy-able type and allows for //! volatile memory access to wrapped value. Volatile memory accesses are never optimized away by //! the compiler, and are useful in many low-level systems programming and concurrent contexts. //! //! The wrapper types *do not* enforce any atomicity guarantees; to also get atomicity, consider //! looking at the `Atomic` wrapper type found in `libcore` or `libstd`. //! //! These wrappers do not depend on the standard library and never panic. //! //! # Dealing with Volatile Pointers //! //! Frequently, one may have to deal with volatile pointers, eg, writes to specific memory //! locations. The canonical way to solve this is to cast the pointer to a volatile wrapper //! directly, eg: //! //! ```rust //! use volatile::Volatile; //! //! let mut_ptr = 0xFEE00000 as *mut u32; //! //! let volatile_ptr = mut_ptr as *mut Volatile; //! ``` //! //! and then perform operations on the pointer as usual in a volatile way. This method works as all //! of the volatile wrapper types are the same size as their contained values. #![no_std] use core::ptr; /// A wrapper type around a volatile variable, which allows for volatile reads and writes /// to the contained value. The stored type needs to be `Copy`, as volatile reads and writes /// take and return copies of the value. /// /// The size of this struct is the same as the size of the contained type. #[derive(Debug, Default)] #[repr(transparent)] pub struct Volatile(T); impl Volatile { /// Construct a new volatile instance wrapping the given value. /// /// ```rust /// use volatile::Volatile; /// /// let value = Volatile::new(0u32); /// ``` /// /// # Panics /// /// This method never panics. #[cfg(feature = "const_fn")] pub const fn new(value: T) -> Volatile { Volatile(value) } /// Construct a new volatile instance wrapping the given value. /// /// ```rust /// use volatile::Volatile; /// /// let value = Volatile::new(0u32); /// ``` /// /// # Panics /// /// This method never panics. #[cfg(not(feature = "const_fn"))] pub fn new(value: T) -> Volatile { Volatile(value) } /// Performs a volatile read of the contained value, returning 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 type. /// /// ```rust /// use volatile::Volatile; /// /// let value = Volatile::new(42u32); /// /// assert_eq!(value.read(), 42u32); /// ``` /// /// # Panics /// /// This method never panics. pub fn read(&self) -> T { // UNSAFE: Safe, as we know that our internal value exists. unsafe { ptr::read_volatile(&self.0) } } /// Performs a volatile write, setting the contained value to the given value `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 type. /// /// ```rust /// use volatile::Volatile; /// /// let mut value = Volatile::new(0u32); /// /// value.write(42u32); /// /// assert_eq!(value.read(), 42u32); /// ``` /// /// # Panics /// /// This method never panics. pub fn write(&mut self, value: T) { // UNSAFE: Safe, as we know that our internal value exists. unsafe { ptr::write_volatile(&mut self.0, value) }; } /// Performs a volatile read of the contained value, passes a mutable reference to it to the /// function `f`, and then performs a volatile write of the (potentially updated) value back to /// the contained value. /// /// ```rust /// use volatile::Volatile; /// /// let mut value = Volatile::new(21u32); /// /// value.update(|val_ref| *val_ref *= 2); /// /// assert_eq!(value.read(), 42u32); /// ``` /// /// # Panics /// /// Ths method never panics. pub fn update(&mut self, f: F) where F: FnOnce(&mut T), { let mut value = self.read(); f(&mut value); self.write(value); } } impl Clone for Volatile { fn clone(&self) -> Self { Volatile(self.read()) } } /// A volatile wrapper which only allows read operations. /// /// The size of this struct is the same as the contained type. #[derive(Debug, Clone, Default)] pub struct ReadOnly(Volatile); impl ReadOnly { /// Construct a new read-only volatile wrapper wrapping the given value. /// /// ```rust /// use volatile::ReadOnly; /// /// let value = ReadOnly::new(42u32); /// ``` /// /// # Panics /// /// This function never panics. #[cfg(feature = "const_fn")] pub const fn new(value: T) -> ReadOnly { ReadOnly(Volatile::new(value)) } /// Construct a new read-only volatile wrapper wrapping the given value. /// /// ```rust /// use volatile::ReadOnly; /// /// let value = ReadOnly::new(42u32); /// ``` /// /// # Panics /// /// This function never panics. #[cfg(not(feature = "const_fn"))] pub fn new(value: T) -> ReadOnly { ReadOnly(Volatile::new(value)) } /// Perform a volatile read of the contained value, returning a copy of the read value. /// Functionally equivalent to `Volatile::read`. /// /// ```rust /// use volatile::ReadOnly; /// /// let value = ReadOnly::new(42u32); /// assert_eq!(value.read(), 42u32); /// ``` /// /// # Panics /// /// This function never panics. pub fn read(&self) -> T { self.0.read() } } /// A volatile wrapper which only allows write operations. /// /// The size of this struct is the same as the contained type. #[derive(Default)] pub struct WriteOnly(Volatile); impl WriteOnly { /// Constructs a new write only volatile wrapper around the given value. /// /// ```rust /// use volatile::WriteOnly; /// /// let value = WriteOnly::new(0u32); /// ``` /// /// # Panics /// /// This function never panics. #[cfg(feature = "const_fn")] pub const fn new(value: T) -> WriteOnly { WriteOnly(Volatile::new(value)) } /// Constructs a new write only volatile wrapper around the given value. /// /// ```rust /// use volatile::WriteOnly; /// /// let value = WriteOnly::new(0u32); /// ``` /// /// # Panics /// /// This function never panics. #[cfg(not(feature = "const_fn"))] pub fn new(value: T) -> WriteOnly { WriteOnly(Volatile::new(value)) } /// Performs a volatile write of value `value` into the contained value. Functionally identical /// to `Volatile::write`. /// /// ```rust /// use volatile::WriteOnly; /// /// let mut value = WriteOnly::new(0u32); /// /// value.write(42u32); /// ``` /// /// # Panics /// /// This method never panics. pub fn write(&mut self, value: T) { self.0.write(value) } } /// A volatile wrapper which allows both read and write operations; /// functionally equivalent to the `Volatile` type, as it is a type /// alias for it. /// /// The size of this struct is the same as the contained type. pub type ReadWrite = Volatile; #[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; // UNSAFE: Safe, as we know the value exists on the stack. unsafe { (*volatile_ptr).write(42u32); } assert_eq!(target_value, 42u32); } }