interrupt_ref_cell/
lib.rs

1//! A [`RefCell`] for sharing data with interrupt handlers or signal handlers on the same thread.
2//!
3//! [`InterruptRefCell`] is just like [`RefCell`], but disables interrupts during borrows.
4//!
5//! See [`std::cell`] for a module-level description of cells.
6//!
7//! # Synchronization
8//!
9//! This cell synchronizes the current thread _with itself_ via a [`compiler_fence`].
10//!
11//! A compiler fence is sufficient for sharing a `!Sync` type, such as [`RefCell`], with an interrupt handler on the same thread.
12//!
13//! [`compiler_fence`]: std::sync::atomic::compiler_fence
14//!
15//! # Caveats
16//!
17//! <div class="warning">Interrupts are disabled on a best-effort basis.</div>
18//!
19//! Holding a reference does not guarantee that interrupts are disabled.
20//! Dropping shared references in the wrong order might enable interrupts prematurely.
21//! Similarly, you can just enable interrupts manually while holding a reference.
22//!
23//! # Examples
24//!
25//! ```
26//! use interrupt_ref_cell::{InterruptRefCell, LocalKeyExt};
27//!
28//! thread_local! {
29//!     static X: InterruptRefCell<Vec<i32>> = InterruptRefCell::new(Vec::new());
30//! }
31//!
32//! fn interrupt_handler() {
33//!     X.with_borrow_mut(|v| v.push(1));
34//! }
35//! #
36//! # // Setup signal handling for demo
37//! #
38//! # use nix::libc;
39//! # use nix::sys::signal::{self, SigHandler, Signal};
40//! #
41//! # extern "C" fn handle_sigint(_signal: libc::c_int) {
42//! #     interrupt_handler();
43//! # }
44//! #
45//! # let handler = SigHandler::Handler(handle_sigint);
46//! # unsafe { signal::signal(Signal::SIGINT, handler) }.unwrap();
47//! #
48//! # fn raise_interrupt() {
49//! #     signal::raise(Signal::SIGINT);
50//! # }
51//!
52//! X.with_borrow(|v| {
53//!     // Raise an interrupt
54//!     raise_interrupt();
55//!     assert_eq!(*v, vec![]);
56//! });
57//!
58//! // The interrupt handler runs
59//!
60//! X.with_borrow(|v| assert_eq!(*v, vec![1]));
61//! ```
62
63#![cfg_attr(target_os = "none", no_std)]
64
65mod interrupt_dropper;
66#[cfg(not(target_os = "none"))]
67mod local_key;
68
69use core::cell::{BorrowError, BorrowMutError, Ref, RefCell, RefMut};
70use core::cmp::Ordering;
71use core::ops::{Deref, DerefMut};
72use core::{fmt, mem};
73
74use self::interrupt_dropper::InterruptDropper;
75#[cfg(not(target_os = "none"))]
76pub use self::local_key::LocalKeyExt;
77
78/// A mutable memory location with dynamically checked borrow rules
79///
80/// See the [module-level documentation](self) for more.
81pub struct InterruptRefCell<T: ?Sized> {
82    inner: RefCell<T>,
83}
84
85impl<T: ?Sized + fmt::Debug> fmt::Debug for InterruptRefCell<T> {
86    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
87        let mut d = f.debug_struct("InterruptRefCell");
88        match self.try_borrow() {
89            Ok(borrow) => d.field("value", &borrow),
90            Err(_) => d.field("value", &format_args!("<borrowed>")),
91        };
92        d.finish()
93    }
94}
95
96impl<T> InterruptRefCell<T> {
97    /// Creates a new `InterruptRefCell` containing `value`.
98    ///
99    /// # Examples
100    ///
101    /// ```
102    /// use interrupt_ref_cell::InterruptRefCell;
103    ///
104    /// let c = InterruptRefCell::new(5);
105    /// ```
106    #[inline]
107    pub const fn new(value: T) -> Self {
108        Self {
109            inner: RefCell::new(value),
110        }
111    }
112
113    /// Consumes the `InterruptRefCell`, returning the wrapped value.
114    ///
115    /// # Examples
116    ///
117    /// ```
118    /// use interrupt_ref_cell::InterruptRefCell;
119    ///
120    /// let c = InterruptRefCell::new(5);
121    ///
122    /// let five = c.into_inner();
123    /// ```
124    #[inline]
125    pub fn into_inner(self) -> T {
126        self.inner.into_inner()
127    }
128
129    /// Replaces the wrapped value with a new one, returning the old value,
130    /// without deinitializing either one.
131    ///
132    /// This function corresponds to [`std::mem::replace`](../mem/fn.replace.html).
133    ///
134    /// # Panics
135    ///
136    /// Panics if the value is currently borrowed.
137    ///
138    /// # Examples
139    ///
140    /// ```
141    /// use interrupt_ref_cell::InterruptRefCell;
142    /// let cell = InterruptRefCell::new(5);
143    /// let old_value = cell.replace(6);
144    /// assert_eq!(old_value, 5);
145    /// assert_eq!(cell, InterruptRefCell::new(6));
146    /// ```
147    #[inline]
148    #[track_caller]
149    pub fn replace(&self, t: T) -> T {
150        mem::replace(&mut *self.borrow_mut(), t)
151    }
152
153    /// Replaces the wrapped value with a new one computed from `f`, returning
154    /// the old value, without deinitializing either one.
155    ///
156    /// # Panics
157    ///
158    /// Panics if the value is currently borrowed.
159    ///
160    /// # Examples
161    ///
162    /// ```
163    /// use interrupt_ref_cell::InterruptRefCell;
164    /// let cell = InterruptRefCell::new(5);
165    /// let old_value = cell.replace_with(|&mut old| old + 1);
166    /// assert_eq!(old_value, 5);
167    /// assert_eq!(cell, InterruptRefCell::new(6));
168    /// ```
169    #[inline]
170    #[track_caller]
171    pub fn replace_with<F: FnOnce(&mut T) -> T>(&self, f: F) -> T {
172        let mut_borrow = &mut *self.borrow_mut();
173        let replacement = f(mut_borrow);
174        mem::replace(mut_borrow, replacement)
175    }
176
177    /// Swaps the wrapped value of `self` with the wrapped value of `other`,
178    /// without deinitializing either one.
179    ///
180    /// This function corresponds to [`std::mem::swap`](../mem/fn.swap.html).
181    ///
182    /// # Panics
183    ///
184    /// Panics if the value in either `InterruptRefCell` is currently borrowed, or
185    /// if `self` and `other` point to the same `InterruptRefCell`.
186    ///
187    /// # Examples
188    ///
189    /// ```
190    /// use interrupt_ref_cell::InterruptRefCell;
191    /// let c = InterruptRefCell::new(5);
192    /// let d = InterruptRefCell::new(6);
193    /// c.swap(&d);
194    /// assert_eq!(c, InterruptRefCell::new(6));
195    /// assert_eq!(d, InterruptRefCell::new(5));
196    /// ```
197    #[inline]
198    pub fn swap(&self, other: &Self) {
199        mem::swap(&mut *self.borrow_mut(), &mut *other.borrow_mut())
200    }
201}
202
203impl<T: ?Sized> InterruptRefCell<T> {
204    /// Immutably borrows the wrapped value.
205    ///
206    /// The borrow lasts until the returned `InterruptRef` exits scope. Multiple
207    /// immutable borrows can be taken out at the same time.
208    ///
209    /// # Panics
210    ///
211    /// Panics if the value is currently mutably borrowed. For a non-panicking variant, use
212    /// [`try_borrow`](#method.try_borrow).
213    ///
214    /// # Examples
215    ///
216    /// ```
217    /// use interrupt_ref_cell::InterruptRefCell;
218    ///
219    /// let c = InterruptRefCell::new(5);
220    ///
221    /// let borrowed_five = c.borrow();
222    /// let borrowed_five2 = c.borrow();
223    /// ```
224    ///
225    /// An example of panic:
226    ///
227    /// ```should_panic
228    /// use interrupt_ref_cell::InterruptRefCell;
229    ///
230    /// let c = InterruptRefCell::new(5);
231    ///
232    /// let m = c.borrow_mut();
233    /// let b = c.borrow(); // this causes a panic
234    /// ```
235    #[inline]
236    #[track_caller]
237    pub fn borrow(&self) -> InterruptRef<'_, T> {
238        self.try_borrow().expect("already mutably borrowed")
239    }
240
241    /// Immutably borrows the wrapped value, returning an error if the value is currently mutably
242    /// borrowed.
243    ///
244    /// The borrow lasts until the returned `InterruptRef` exits scope. Multiple immutable borrows can be
245    /// taken out at the same time.
246    ///
247    /// This is the non-panicking variant of [`borrow`](#method.borrow).
248    ///
249    /// # Examples
250    ///
251    /// ```
252    /// use interrupt_ref_cell::InterruptRefCell;
253    ///
254    /// let c = InterruptRefCell::new(5);
255    ///
256    /// {
257    ///     let m = c.borrow_mut();
258    ///     assert!(c.try_borrow().is_err());
259    /// }
260    ///
261    /// {
262    ///     let m = c.borrow();
263    ///     assert!(c.try_borrow().is_ok());
264    /// }
265    /// ```
266    #[inline]
267    #[cfg_attr(feature = "debug_interruptrefcell", track_caller)]
268    pub fn try_borrow(&self) -> Result<InterruptRef<'_, T>, BorrowError> {
269        let guard = interrupts::disable();
270        self.inner.try_borrow().map(|inner| {
271            let inner = InterruptDropper::from(inner);
272            InterruptRef { inner, guard }
273        })
274    }
275
276    /// Mutably borrows the wrapped value.
277    ///
278    /// The borrow lasts until the returned `InterruptRefMut` or all `InterruptRefMut`s derived
279    /// from it exit scope. The value cannot be borrowed while this borrow is
280    /// active.
281    ///
282    /// # Panics
283    ///
284    /// Panics if the value is currently borrowed. For a non-panicking variant, use
285    /// [`try_borrow_mut`](#method.try_borrow_mut).
286    ///
287    /// # Examples
288    ///
289    /// ```
290    /// use interrupt_ref_cell::InterruptRefCell;
291    ///
292    /// let c = InterruptRefCell::new("hello".to_owned());
293    ///
294    /// *c.borrow_mut() = "bonjour".to_owned();
295    ///
296    /// assert_eq!(&*c.borrow(), "bonjour");
297    /// ```
298    ///
299    /// An example of panic:
300    ///
301    /// ```should_panic
302    /// use interrupt_ref_cell::InterruptRefCell;
303    ///
304    /// let c = InterruptRefCell::new(5);
305    /// let m = c.borrow();
306    ///
307    /// let b = c.borrow_mut(); // this causes a panic
308    /// ```
309    #[inline]
310    #[track_caller]
311    pub fn borrow_mut(&self) -> InterruptRefMut<'_, T> {
312        self.try_borrow_mut().expect("already borrowed")
313    }
314
315    /// Mutably borrows the wrapped value, returning an error if the value is currently borrowed.
316    ///
317    /// The borrow lasts until the returned `InterruptRefMut` or all `InterruptRefMut`s derived
318    /// from it exit scope. The value cannot be borrowed while this borrow is
319    /// active.
320    ///
321    /// This is the non-panicking variant of [`borrow_mut`](#method.borrow_mut).
322    ///
323    /// # Examples
324    ///
325    /// ```
326    /// use interrupt_ref_cell::InterruptRefCell;
327    ///
328    /// let c = InterruptRefCell::new(5);
329    ///
330    /// {
331    ///     let m = c.borrow();
332    ///     assert!(c.try_borrow_mut().is_err());
333    /// }
334    ///
335    /// assert!(c.try_borrow_mut().is_ok());
336    /// ```
337    #[inline]
338    #[cfg_attr(feature = "debug_interruptrefcell", track_caller)]
339    pub fn try_borrow_mut(&self) -> Result<InterruptRefMut<'_, T>, BorrowMutError> {
340        let guard = interrupts::disable();
341        self.inner.try_borrow_mut().map(|inner| {
342            let inner = InterruptDropper::from(inner);
343            InterruptRefMut { inner, guard }
344        })
345    }
346
347    /// Returns a raw pointer to the underlying data in this cell.
348    ///
349    /// # Examples
350    ///
351    /// ```
352    /// use interrupt_ref_cell::InterruptRefCell;
353    ///
354    /// let c = InterruptRefCell::new(5);
355    ///
356    /// let ptr = c.as_ptr();
357    /// ```
358    #[inline]
359    pub fn as_ptr(&self) -> *mut T {
360        self.inner.as_ptr()
361    }
362
363    /// Returns a mutable reference to the underlying data.
364    ///
365    /// Since this method borrows `InterruptRefCell` mutably, it is statically guaranteed
366    /// that no borrows to the underlying data exist. The dynamic checks inherent
367    /// in [`borrow_mut`] and most other methods of `InterruptRefCell` are therefore
368    /// unnecessary.
369    ///
370    /// This method can only be called if `InterruptRefCell` can be mutably borrowed,
371    /// which in general is only the case directly after the `InterruptRefCell` has
372    /// been created. In these situations, skipping the aforementioned dynamic
373    /// borrowing checks may yield better ergonomics and runtime-performance.
374    ///
375    /// In most situations where `InterruptRefCell` is used, it can't be borrowed mutably.
376    /// Use [`borrow_mut`] to get mutable access to the underlying data then.
377    ///
378    /// [`borrow_mut`]: InterruptRefCell::borrow_mut()
379    ///
380    /// # Examples
381    ///
382    /// ```
383    /// use interrupt_ref_cell::InterruptRefCell;
384    ///
385    /// let mut c = InterruptRefCell::new(5);
386    /// *c.get_mut() += 1;
387    ///
388    /// assert_eq!(c, InterruptRefCell::new(6));
389    /// ```
390    #[inline]
391    pub fn get_mut(&mut self) -> &mut T {
392        self.inner.get_mut()
393    }
394
395    /// Immutably borrows the wrapped value, returning an error if the value is
396    /// currently mutably borrowed.
397    ///
398    /// # Safety
399    ///
400    /// Unlike `InterruptRefCell::borrow`, this method is unsafe because it does not
401    /// return a `InterruptRef`, thus leaving the borrow flag untouched. Mutably
402    /// borrowing the `InterruptRefCell` while the reference returned by this method
403    /// is alive is undefined behaviour.
404    ///
405    /// # Examples
406    ///
407    /// ```
408    /// use interrupt_ref_cell::InterruptRefCell;
409    ///
410    /// let c = InterruptRefCell::new(5);
411    ///
412    /// {
413    ///     let m = c.borrow_mut();
414    ///     assert!(unsafe { c.try_borrow_unguarded() }.is_err());
415    /// }
416    ///
417    /// {
418    ///     let m = c.borrow();
419    ///     assert!(unsafe { c.try_borrow_unguarded() }.is_ok());
420    /// }
421    /// ```
422    #[inline]
423    pub unsafe fn try_borrow_unguarded(&self) -> Result<&T, BorrowError> {
424        let guard = interrupts::disable();
425        let ret = self.inner.try_borrow_unguarded();
426        drop(guard);
427        ret
428    }
429}
430
431impl<T: Default> InterruptRefCell<T> {
432    /// Takes the wrapped value, leaving `Default::default()` in its place.
433    ///
434    /// # Panics
435    ///
436    /// Panics if the value is currently borrowed.
437    ///
438    /// # Examples
439    ///
440    /// ```
441    /// use interrupt_ref_cell::InterruptRefCell;
442    ///
443    /// let c = InterruptRefCell::new(5);
444    /// let five = c.take();
445    ///
446    /// assert_eq!(five, 5);
447    /// assert_eq!(c.into_inner(), 0);
448    /// ```
449    pub fn take(&self) -> T {
450        self.replace(Default::default())
451    }
452}
453
454impl<T: Clone> Clone for InterruptRefCell<T> {
455    /// # Panics
456    ///
457    /// Panics if the value is currently mutably borrowed.
458    #[inline]
459    #[track_caller]
460    fn clone(&self) -> InterruptRefCell<T> {
461        InterruptRefCell::new(self.borrow().clone())
462    }
463
464    /// # Panics
465    ///
466    /// Panics if `other` is currently mutably borrowed.
467    #[inline]
468    #[track_caller]
469    fn clone_from(&mut self, other: &Self) {
470        self.get_mut().clone_from(&other.borrow())
471    }
472}
473
474impl<T: Default> Default for InterruptRefCell<T> {
475    /// Creates a `InterruptRefCell<T>`, with the `Default` value for T.
476    #[inline]
477    fn default() -> InterruptRefCell<T> {
478        InterruptRefCell::new(Default::default())
479    }
480}
481
482impl<T: ?Sized + PartialEq> PartialEq for InterruptRefCell<T> {
483    /// # Panics
484    ///
485    /// Panics if the value in either `InterruptRefCell` is currently mutably borrowed.
486    #[inline]
487    fn eq(&self, other: &InterruptRefCell<T>) -> bool {
488        *self.borrow() == *other.borrow()
489    }
490}
491
492impl<T: ?Sized + Eq> Eq for InterruptRefCell<T> {}
493
494impl<T: ?Sized + PartialOrd> PartialOrd for InterruptRefCell<T> {
495    /// # Panics
496    ///
497    /// Panics if the value in either `InterruptRefCell` is currently mutably borrowed.
498    #[inline]
499    fn partial_cmp(&self, other: &InterruptRefCell<T>) -> Option<Ordering> {
500        self.borrow().partial_cmp(&*other.borrow())
501    }
502
503    /// # Panics
504    ///
505    /// Panics if the value in either `InterruptRefCell` is currently mutably borrowed.
506    #[inline]
507    fn lt(&self, other: &InterruptRefCell<T>) -> bool {
508        *self.borrow() < *other.borrow()
509    }
510
511    /// # Panics
512    ///
513    /// Panics if the value in either `InterruptRefCell` is currently mutably borrowed.
514    #[inline]
515    fn le(&self, other: &InterruptRefCell<T>) -> bool {
516        *self.borrow() <= *other.borrow()
517    }
518
519    /// # Panics
520    ///
521    /// Panics if the value in either `InterruptRefCell` is currently mutably borrowed.
522    #[inline]
523    fn gt(&self, other: &InterruptRefCell<T>) -> bool {
524        *self.borrow() > *other.borrow()
525    }
526
527    /// # Panics
528    ///
529    /// Panics if the value in either `InterruptRefCell` is currently mutably borrowed.
530    #[inline]
531    fn ge(&self, other: &InterruptRefCell<T>) -> bool {
532        *self.borrow() >= *other.borrow()
533    }
534}
535
536impl<T: ?Sized + Ord> Ord for InterruptRefCell<T> {
537    /// # Panics
538    ///
539    /// Panics if the value in either `InterruptRefCell` is currently mutably borrowed.
540    #[inline]
541    fn cmp(&self, other: &InterruptRefCell<T>) -> Ordering {
542        self.borrow().cmp(&*other.borrow())
543    }
544}
545
546impl<T> From<T> for InterruptRefCell<T> {
547    /// Creates a new `InterruptRefCell<T>` containing the given value.
548    fn from(t: T) -> InterruptRefCell<T> {
549        InterruptRefCell::new(t)
550    }
551}
552
553/// Wraps a borrowed reference to a value in a `InterruptRefCell` box.
554/// A wrapper type for an immutably borrowed value from a `InterruptRefCell<T>`.
555///
556/// See the [module-level documentation](self) for more.
557pub struct InterruptRef<'b, T: ?Sized + 'b> {
558    inner: InterruptDropper<Ref<'b, T>>,
559    guard: interrupts::Guard,
560}
561
562impl<T: ?Sized> Deref for InterruptRef<'_, T> {
563    type Target = T;
564
565    #[inline]
566    fn deref(&self) -> &Self::Target {
567        self.inner.deref()
568    }
569}
570
571impl<'b, T: ?Sized> InterruptRef<'b, T> {
572    /// Copies a `InterruptRef`.
573    ///
574    /// The `InterruptRefCell` is already immutably borrowed, so this cannot fail.
575    ///
576    /// This is an associated function that needs to be used as
577    /// `InterruptRef::clone(...)`. A `Clone` implementation or a method would interfere
578    /// with the widespread use of `r.borrow().clone()` to clone the contents of
579    /// a `InterruptRefCell`.
580    #[allow(clippy::should_implement_trait)]
581    #[must_use]
582    #[inline]
583    pub fn clone(orig: &InterruptRef<'b, T>) -> InterruptRef<'b, T> {
584        let guard = interrupts::disable();
585        let inner = InterruptDropper::from(Ref::clone(&orig.inner));
586        InterruptRef { inner, guard }
587    }
588
589    /// Makes a new `InterruptRef` for a component of the borrowed data.
590    ///
591    /// The `InterruptRefCell` is already immutably borrowed, so this cannot fail.
592    ///
593    /// This is an associated function that needs to be used as `InterruptRef::map(...)`.
594    /// A method would interfere with methods of the same name on the contents
595    /// of a `InterruptRefCell` used through `Deref`.
596    ///
597    /// # Examples
598    ///
599    /// ```
600    /// use interrupt_ref_cell::{InterruptRefCell, InterruptRef};
601    ///
602    /// let c = InterruptRefCell::new((5, 'b'));
603    /// let b1: InterruptRef<'_, (u32, char)> = c.borrow();
604    /// let b2: InterruptRef<'_, u32> = InterruptRef::map(b1, |t| &t.0);
605    /// assert_eq!(*b2, 5)
606    /// ```
607    #[inline]
608    pub fn map<U: ?Sized, F>(orig: InterruptRef<'b, T>, f: F) -> InterruptRef<'b, U>
609    where
610        F: FnOnce(&T) -> &U,
611    {
612        let InterruptRef { inner, guard } = orig;
613        let inner = InterruptDropper::from(Ref::map(InterruptDropper::into_inner(inner), f));
614        InterruptRef { inner, guard }
615    }
616
617    /// Makes a new `InterruptRef` for an optional component of the borrowed data. The
618    /// original guard is returned as an `Err(..)` if the closure returns
619    /// `None`.
620    ///
621    /// The `InterruptRefCell` is already immutably borrowed, so this cannot fail.
622    ///
623    /// This is an associated function that needs to be used as
624    /// `InterruptRef::filter_map(...)`. A method would interfere with methods of the same
625    /// name on the contents of a `InterruptRefCell` used through `Deref`.
626    ///
627    /// # Examples
628    ///
629    /// ```
630    /// use interrupt_ref_cell::{InterruptRefCell, InterruptRef};
631    ///
632    /// let c = InterruptRefCell::new(vec![1, 2, 3]);
633    /// let b1: InterruptRef<'_, Vec<u32>> = c.borrow();
634    /// let b2: Result<InterruptRef<'_, u32>, _> = InterruptRef::filter_map(b1, |v| v.get(1));
635    /// assert_eq!(*b2.unwrap(), 2);
636    /// ```
637    #[allow(clippy::result_large_err)]
638    #[inline]
639    pub fn filter_map<U: ?Sized, F>(
640        orig: InterruptRef<'b, T>,
641        f: F,
642    ) -> Result<InterruptRef<'b, U>, Self>
643    where
644        F: FnOnce(&T) -> Option<&U>,
645    {
646        let guard = interrupts::disable();
647        let filter_map = Ref::filter_map(InterruptDropper::into_inner(orig.inner), f);
648        drop(guard);
649        match filter_map {
650            Ok(inner) => {
651                let inner = InterruptDropper::from(inner);
652                Ok(InterruptRef {
653                    inner,
654                    guard: orig.guard,
655                })
656            }
657            Err(inner) => {
658                let inner = InterruptDropper::from(inner);
659                Err(InterruptRef {
660                    inner,
661                    guard: orig.guard,
662                })
663            }
664        }
665    }
666
667    /// Splits a `InterruptRef` into multiple `InterruptRef`s for different components of the
668    /// borrowed data.
669    ///
670    /// The `InterruptRefCell` is already immutably borrowed, so this cannot fail.
671    ///
672    /// This is an associated function that needs to be used as
673    /// `InterruptRef::map_split(...)`. A method would interfere with methods of the same
674    /// name on the contents of a `InterruptRefCell` used through `Deref`.
675    ///
676    /// # Examples
677    ///
678    /// ```
679    /// use interrupt_ref_cell::{InterruptRefCell, InterruptRef};
680    ///
681    /// let cell = InterruptRefCell::new([1, 2, 3, 4]);
682    /// let borrow = cell.borrow();
683    /// let (begin, end) = InterruptRef::map_split(borrow, |slice| slice.split_at(2));
684    /// assert_eq!(*begin, [1, 2]);
685    /// assert_eq!(*end, [3, 4]);
686    /// ```
687    #[inline]
688    pub fn map_split<U: ?Sized, V: ?Sized, F>(
689        orig: InterruptRef<'b, T>,
690        f: F,
691    ) -> (InterruptRef<'b, U>, InterruptRef<'b, V>)
692    where
693        F: FnOnce(&T) -> (&U, &V),
694    {
695        let guard = interrupts::disable();
696        let (a, b) = Ref::map_split(InterruptDropper::into_inner(orig.inner), f);
697        (
698            InterruptRef {
699                inner: InterruptDropper::from(a),
700                guard,
701            },
702            InterruptRef {
703                inner: InterruptDropper::from(b),
704                guard: orig.guard,
705            },
706        )
707    }
708}
709
710impl<T: ?Sized + fmt::Debug> fmt::Debug for InterruptRef<'_, T> {
711    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
712        self.inner.fmt(f)
713    }
714}
715
716impl<T: ?Sized + fmt::Display> fmt::Display for InterruptRef<'_, T> {
717    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
718        self.inner.fmt(f)
719    }
720}
721
722impl<'b, T: ?Sized> InterruptRefMut<'b, T> {
723    /// Makes a new `InterruptRefMut` for a component of the borrowed data, e.g., an enum
724    /// variant.
725    ///
726    /// The `InterruptRefCell` is already mutably borrowed, so this cannot fail.
727    ///
728    /// This is an associated function that needs to be used as
729    /// `InterruptRefMut::map(...)`. A method would interfere with methods of the same
730    /// name on the contents of a `InterruptRefCell` used through `Deref`.
731    ///
732    /// # Examples
733    ///
734    /// ```
735    /// use interrupt_ref_cell::{InterruptRefCell, InterruptRefMut};
736    ///
737    /// let c = InterruptRefCell::new((5, 'b'));
738    /// {
739    ///     let b1: InterruptRefMut<'_, (u32, char)> = c.borrow_mut();
740    ///     let mut b2: InterruptRefMut<'_, u32> = InterruptRefMut::map(b1, |t| &mut t.0);
741    ///     assert_eq!(*b2, 5);
742    ///     *b2 = 42;
743    /// }
744    /// assert_eq!(*c.borrow(), (42, 'b'));
745    /// ```
746    #[inline]
747    pub fn map<U: ?Sized, F>(orig: InterruptRefMut<'b, T>, f: F) -> InterruptRefMut<'b, U>
748    where
749        F: FnOnce(&mut T) -> &mut U,
750    {
751        let InterruptRefMut { inner, guard } = orig;
752        let inner = InterruptDropper::from(RefMut::map(InterruptDropper::into_inner(inner), f));
753        InterruptRefMut { inner, guard }
754    }
755
756    /// Makes a new `InterruptRefMut` for an optional component of the borrowed data. The
757    /// original guard is returned as an `Err(..)` if the closure returns
758    /// `None`.
759    ///
760    /// The `InterruptRefCell` is already mutably borrowed, so this cannot fail.
761    ///
762    /// This is an associated function that needs to be used as
763    /// `InterruptRefMut::filter_map(...)`. A method would interfere with methods of the
764    /// same name on the contents of a `InterruptRefCell` used through `Deref`.
765    ///
766    /// # Examples
767    ///
768    /// ```
769    /// use interrupt_ref_cell::{InterruptRefCell, InterruptRefMut};
770    ///
771    /// let c = InterruptRefCell::new(vec![1, 2, 3]);
772    ///
773    /// {
774    ///     let b1: InterruptRefMut<'_, Vec<u32>> = c.borrow_mut();
775    ///     let mut b2: Result<InterruptRefMut<'_, u32>, _> = InterruptRefMut::filter_map(b1, |v| v.get_mut(1));
776    ///
777    ///     if let Ok(mut b2) = b2 {
778    ///         *b2 += 2;
779    ///     }
780    /// }
781    ///
782    /// assert_eq!(*c.borrow(), vec![1, 4, 3]);
783    /// ```
784    #[allow(clippy::result_large_err)]
785    #[inline]
786    pub fn filter_map<U: ?Sized, F>(
787        orig: InterruptRefMut<'b, T>,
788        f: F,
789    ) -> Result<InterruptRefMut<'b, U>, Self>
790    where
791        F: FnOnce(&mut T) -> Option<&mut U>,
792    {
793        let guard = interrupts::disable();
794        let filter_map = RefMut::filter_map(InterruptDropper::into_inner(orig.inner), f);
795        drop(guard);
796        match filter_map {
797            Ok(inner) => {
798                let inner = InterruptDropper::from(inner);
799                Ok(InterruptRefMut {
800                    inner,
801                    guard: orig.guard,
802                })
803            }
804            Err(inner) => {
805                let inner = InterruptDropper::from(inner);
806                Err(InterruptRefMut {
807                    inner,
808                    guard: orig.guard,
809                })
810            }
811        }
812    }
813
814    /// Splits a `InterruptRefMut` into multiple `InterruptRefMut`s for different components of the
815    /// borrowed data.
816    ///
817    /// The underlying `InterruptRefCell` will remain mutably borrowed until both
818    /// returned `InterruptRefMut`s go out of scope.
819    ///
820    /// The `InterruptRefCell` is already mutably borrowed, so this cannot fail.
821    ///
822    /// This is an associated function that needs to be used as
823    /// `InterruptRefMut::map_split(...)`. A method would interfere with methods of the
824    /// same name on the contents of a `InterruptRefCell` used through `Deref`.
825    ///
826    /// # Examples
827    ///
828    /// ```
829    /// use interrupt_ref_cell::{InterruptRefCell, InterruptRefMut};
830    ///
831    /// let cell = InterruptRefCell::new([1, 2, 3, 4]);
832    /// let borrow = cell.borrow_mut();
833    /// let (mut begin, mut end) = InterruptRefMut::map_split(borrow, |slice| slice.split_at_mut(2));
834    /// assert_eq!(*begin, [1, 2]);
835    /// assert_eq!(*end, [3, 4]);
836    /// begin.copy_from_slice(&[4, 3]);
837    /// end.copy_from_slice(&[2, 1]);
838    /// ```
839    #[inline]
840    pub fn map_split<U: ?Sized, V: ?Sized, F>(
841        orig: InterruptRefMut<'b, T>,
842        f: F,
843    ) -> (InterruptRefMut<'b, U>, InterruptRefMut<'b, V>)
844    where
845        F: FnOnce(&mut T) -> (&mut U, &mut V),
846    {
847        let guard = interrupts::disable();
848        let (a, b) = RefMut::map_split(InterruptDropper::into_inner(orig.inner), f);
849        (
850            InterruptRefMut {
851                inner: InterruptDropper::from(a),
852                guard,
853            },
854            InterruptRefMut {
855                inner: InterruptDropper::from(b),
856                guard: orig.guard,
857            },
858        )
859    }
860}
861
862/// A wrapper type for a mutably borrowed value from a `InterruptRefCell<T>`.
863///
864/// See the [module-level documentation](self) for more.
865pub struct InterruptRefMut<'b, T: ?Sized + 'b> {
866    inner: InterruptDropper<RefMut<'b, T>>,
867    guard: interrupts::Guard,
868}
869
870impl<T: ?Sized> Deref for InterruptRefMut<'_, T> {
871    type Target = T;
872
873    #[inline]
874    fn deref(&self) -> &Self::Target {
875        self.inner.deref()
876    }
877}
878
879impl<T: ?Sized> DerefMut for InterruptRefMut<'_, T> {
880    #[inline]
881    fn deref_mut(&mut self) -> &mut Self::Target {
882        self.inner.deref_mut()
883    }
884}
885
886impl<T: ?Sized + fmt::Debug> fmt::Debug for InterruptRefMut<'_, T> {
887    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
888        self.inner.fmt(f)
889    }
890}
891
892impl<T: ?Sized + fmt::Display> fmt::Display for InterruptRefMut<'_, T> {
893    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
894        self.inner.fmt(f)
895    }
896}