1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160
/*********************************************************************************************************************** * Copyright (c) 2019 by the authors * * Author: André Borrmann * License: Apache License 2.0 **********************************************************************************************************************/ #![doc(html_root_url = "https://docs.rs/ruspiro-singleton/0.3.1")] #![no_std] //! # Singleton pattern implementation //! //! Provide a cross core synchronisation safe singleton implementation pattern //! //! # Example //! ``` //! use ruspiro_singleton::*; //! //! static FOO: Singleton<Foo> = Singleton::new(Foo::new(0)); //! //! struct Foo { //! count: u32, //! } //! //! impl Foo { //! pub const fn new(initial_count: u32) -> Self { //! Foo { //! count: initial_count, //! } //! } //! //! pub fn count(&self) -> u32 { //! self.count //! } //! //! pub fn add_count(&mut self, value: u32) -> u32 { //! self.count += value; //! self.count //! } //! } //! //! fn main () { //! let counter = FOO.take_for( |foo| { //! println!("secure access to the singleton"); //! // do something with the singleton, it is mutable inside 'take_for' //! let c = foo.add_count(1); //! // and return any value, the return value of take_for is inferred from the return //! // value of the closure given to this function. //! c //! }); //! //! println!("successfull {}", counter); //! } //! ``` //! //! In case only immutable access to the contents of the singleton is required the ``use_for`` function //! can be used. //! ``` //! # use ruspiro_singleton::*; //! # static FOO: Singleton<Foo> = Singleton::new(Foo::new(0)); //! # struct Foo { //! # count: u32, //! # } //! # impl Foo { //! # pub const fn new(initial_count: u32) -> Self { //! # Foo { //! # count: initial_count, //! # } //! # } //! # //! # pub fn count(&self) -> u32 { //! # self.count //! # } //! # } //! //! fn main () { //! let counter = FOO.use_for( |foo| { //! foo.count() //! }); //! //! println!("current counter: {}", counter); //! } //! ``` //! use core::cell::UnsafeCell; use ruspiro_lock::Spinlock; /// The Singleton wrapper stores any type pub struct Singleton<T: 'static> { inner: UnsafeCell<T>, lock: Spinlock, } // The Singleton need to implement Sync to ensure cross core sync compile check mechanisms #[doc(hidden)] unsafe impl<T> Sync for Singleton<T> {} #[doc(hidden)] unsafe impl<T> Send for Singleton<T> {} impl<T: 'static> Singleton<T> { /// Create a new singleton instance to be used in a static variable. Only ``const fn`` constructors are allowed here. /// If this is not sufficient the ``Singleton`` may be further wrapped by a ``lazy_static!`` available as /// external crate from [crates.io](https://crates.io/crates/lazy_static) pub const fn new(data: T) -> Singleton<T> { Singleton { inner: UnsafeCell::new(data), lock: Spinlock::new(), } } /// Take the stored singleton for whatever operation and prevent usage by other cores /// Safe access to the singleton mutable instance is guarantied inside the given closure. /// /// # Example /// ``` /// # use ruspiro_singleton::*; /// # static FOO: Singleton<u32> = Singleton::new(0); /// # fn main() { /// FOO.take_for(|foo| { /// // do something mutable with [foo] /// }); /// # } /// ``` pub fn take_for<F, R>(&self, f: F) -> R where F: FnOnce(&mut T) -> R, { // to ensure atomic access to the singleton wrapped resource we aquire a lock before allowing to access // the same. While the lock is aquired interrupts are disabled. This ensures there are now deadlocks // possible when a lock is interrupted and the handler tries to aquire the same lock self.lock.aquire(); let r = f(unsafe { &mut *self.inner.get() }); // after processing we can release the lock so other cores can access the singleton as well // this also re-enables interrupts self.lock.release(); r } /// Immutable access to a singleton for a specific operation. /// This access does not enforce any lock nor guarantees safe atomic access to the instance. However, it is usefull /// in read-only access scenarios like inside interrupt handlers. /// /// # Example /// ``` /// # use ruspiro_singleton::*; /// # static FOO: Singleton<u32> = Singleton::new(0); /// # fn main() { /// FOO.use_for(|foo| { /// // do something immutable with [foo] /// }); /// # } /// ``` pub fn use_for<F, R>(&self, f: F) -> R where F: FnOnce(&T) -> R, { f(unsafe { &*self.inner.get() }) } }