ferroui_base/rendering/
owned_disposable.rs1use std::rc::Rc;
2
3use crate::platform::{IPlatformGraphicsContext, IPlatformRenderInterfaceContext};
4use crate::reactive::IDisposable;
5
6pub trait OwnedDisposableValue {
8 fn dispose_owned(&self);
9}
10
11impl OwnedDisposableValue for dyn IDisposable {
12 fn dispose_owned(&self) {
13 self.dispose();
14 }
15}
16
17impl OwnedDisposableValue for dyn IPlatformGraphicsContext {
18 fn dispose_owned(&self) {
19 self.dispose();
20 }
21}
22
23impl OwnedDisposableValue for dyn IPlatformRenderInterfaceContext {
24 fn dispose_owned(&self) {
25 self.dispose();
26 }
27}
28
29pub struct OwnedDisposable<T: ?Sized + OwnedDisposableValue> {
32 owns: bool,
33 value: Option<Rc<T>>,
34}
35
36impl<T: ?Sized + OwnedDisposableValue> OwnedDisposable<T> {
37 pub fn new(value: Rc<T>, owns: bool) -> Self {
38 Self { owns, value: Some(value) }
39 }
40
41 pub fn value(&self) -> Rc<T> {
46 match &self.value {
47 Some(value) => value.clone(),
48 None => panic!("Cannot access a disposed object: 'OwnedDisposable'."),
49 }
50 }
51
52 pub fn dispose(&mut self) {
54 if let Some(value) = self.value.take() {
55 if self.owns {
56 value.dispose_owned();
57 }
58 }
59 }
60}
61
62#[cfg(test)]
63mod tests {
64 use super::*;
65 use crate::reactive::Disposable;
66 use std::cell::Cell;
67
68 fn counting() -> (Rc<Cell<i32>>, Rc<dyn IDisposable>) {
69 let count = Rc::new(Cell::new(0));
70 let c = count.clone();
71 struct Counting(Rc<Cell<i32>>);
73 impl IDisposable for Counting {
74 fn dispose(&self) {
75 self.0.set(self.0.get() + 1);
76 }
77 }
78 (count, Rc::new(Counting(c)))
79 }
80
81 #[test]
82 fn disposes_an_owned_value_once() {
83 let (count, value) = counting();
84 let mut owned = OwnedDisposable::new(value.clone(), true);
85 assert!(Rc::ptr_eq(&owned.value(), &value));
86 owned.dispose();
87 owned.dispose();
88 assert_eq!(count.get(), 1);
89 }
90
91 #[test]
92 fn does_not_dispose_a_value_it_does_not_own() {
93 let (count, value) = counting();
94 let mut owned = OwnedDisposable::new(value, false);
95 owned.dispose();
96 assert_eq!(count.get(), 0);
97 }
98
99 #[test]
100 #[should_panic(expected = "OwnedDisposable")]
101 fn value_panics_after_dispose() {
102 let mut owned = OwnedDisposable::new(Disposable::empty(), false);
103 owned.dispose();
104 owned.value();
105 }
106}