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
/* mutstatic.rs
 *
 * Developed by Tim Walls <tim.walls@snowgoons.com>
 * Copyright (c) All Rights Reserved, Tim Walls
 */
//! Mutable static singleton helper

#[doc(hidden)]
#[macro_export]
macro_rules! mut_singleton {
  ($type:ty, $name:ident, $accessor:ident, $accessor_isolated:ident, $constructor:expr) => {
    static mut $name : Option<$type> = None;

    /**
     * Return a reference to the global singleton instance of $type.  The
     * caller should pass an isolation token obtained by
     * [`avr_oxide::concurrency::interrupt::isolated()`]
     */
    #[allow(dead_code)]
    #[inline(never)]
    pub fn $accessor_isolated(_isotoken: avr_oxide::concurrency::Isolated) -> &'static mut $type {
      unsafe {
        if $name.is_none() {
          core::ptr::replace(&mut $name, Some($constructor));
        }

        match &mut $name {
          None => avr_oxide::oserror::halt(avr_oxide::oserror::OsError::InternalError),
          Some(instance) => instance
        }
      }
    }
    /**
     * Return a reference to a global singleton instance of $type.
     * Interrupts will be locked for the duration of the call to ensure
     * consistency; if calling from a context wherein interrupts are
     * already disabled, calling $accessor_isolated() will be more
     * efficient.
     */
    #[allow(dead_code)]
    pub fn $accessor() -> &'static mut $type {
      avr_oxide::concurrency::interrupt::isolated(|isotoken|{
        $accessor_isolated(isotoken)
      })
    }
  };
}

#[doc(hidden)]
#[macro_export]
macro_rules! mut_singleton_explicit_init {
  ($type:ty, $name:ident, $initialiser:ident, $accessor:ident, $accessor_isolated:ident, $constructor:expr) => {
    static mut $name : core::mem::MaybeUninit<$type> = core::mem::MaybeUninit::uninit();

    /**
     * Inititalise the global singleton of $type.
     */
    pub unsafe fn $initialiser() {
      core::ptr::write(
        $name.as_mut_ptr(),
        $constructor
      );
    }

    /**
     * Return a reference to the global singleton instance of $type.  The
     * caller should pass an isolation token obtained by
     * [`avr_oxide::concurrency::interrupt::isolated()`]
     */
    #[allow(dead_code)]
    pub fn $accessor_isolated(_isotoken: avr_oxide::concurrency::Isolated) -> &'static mut $type {
      unsafe {
        $name.assume_init_mut()
      }
    }

    /**
     * Return a reference to a global singleton instance of $type.
     * Interrupts will be locked for the duration of the call to ensure
     * consistency; if calling from a context wherein interrupts are
     * already disabled, calling $accessor_isolated() will be more
     * efficient.
     */
    #[allow(dead_code)]
    pub fn $accessor() -> &'static mut $type {
      avr_oxide::concurrency::interrupt::isolated(|isotoken|{
        unsafe {
          $name.assume_init_mut()
        }
      })
    }
  };
}