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}