Skip to main content

interrupt_ref_cell/
lib.rs

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