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
/*********************************************************************************************************************** 
 * Copyright (c) 2019 by the authors
 * 
 * Author: André Borrmann 
 * License: Apache License 2.0
 **********************************************************************************************************************/
#![doc(html_root_url = "https://docs.rs/ruspiro-singleton/0.0.2")]
#![no_std]

//! # Singleton pattern implementation
//! 
//! Provide a cross core synchronisation safe singleton implementation pattern
//! 
//! # Example
//! ```
//! static MY_SINGLETON: Singleton<MySingleton> = Singleton::new(MySingleton::new(0));
//! 
//! struct MySingleton {
//!     count: u32,
//! }
//! 
//! impl MySingleton {
//!     pub fn new(initial_count: u32) -> Self {
//!         MySingleton {
//!             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 = MY_SINGLETON.take_for( |singleton| {
//!         println!("secure access to the singleton");
//!         // do something with the singleton, it is mutable inside 'take_for'
//!         let c = singleton.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);
//! # }
//! ```
//! 
use core::cell::UnsafeCell;
use ruspiro_lock::Spinlock;

/// The Singleton wrapper stores any type
pub struct Singleton<T> {
    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> { }

impl<T> Singleton<T> {
    /// Create a new singleton instance to be used in a static variable. Only ``const fn`` constructors are allows 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.
    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
            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
            self.lock.release();
            r
        }

    /// Unsafe weak access to a singleton for a specific operation. Access by other cores is **not** permitted.
    /// 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 to ensure they do not depend on any lock that could
    /// lead to a dead-lock situation. The access to the singleton is imutable to enforce read-only access to the same.
    /// 
    /// # Example
    /// ```
    /// fn sample() {
    ///     unsafe {
    ///         MY_SINGLETON.use_weak_for(|my| {
    ///             // do something with [my]
    ///             let _ = my.any_imutable_function();
    ///         })
    ///     };
    /// }
    /// ```
    pub unsafe fn use_weak_for<F, R>(&self, f: F) -> R
        where F: FnOnce(&T) -> R {
            f( & *self.inner.get() )
        }
}