fret_runtime/model/
host.rs1use std::{
2 any::Any,
3 panic::{AssertUnwindSafe, Location, catch_unwind, resume_unwind},
4};
5
6use super::error::ModelUpdateError;
7use super::handle::Model;
8use super::store::ModelStore;
9
10pub struct ModelCx<'a, H: ModelHost + ?Sized> {
15 pub(super) host: &'a mut H,
16}
17
18impl<'a, H: ModelHost + ?Sized> ModelCx<'a, H> {
19 pub fn app(&mut self) -> &mut H {
21 self.host
22 }
23}
24
25pub trait ModelHost {
30 fn models(&self) -> &ModelStore;
31 fn models_mut(&mut self) -> &mut ModelStore;
32
33 fn read<T: Any, R>(
34 &mut self,
35 model: &Model<T>,
36 f: impl FnOnce(&mut Self, &T) -> R,
37 ) -> Result<R, ModelUpdateError> {
38 let mut lease = self.models_mut().lease(model)?;
39 let result = if cfg!(panic = "unwind") {
40 catch_unwind(AssertUnwindSafe(|| f(self, lease.value_ref())))
41 } else {
42 Ok(f(self, lease.value_ref()))
43 };
44
45 self.models_mut().end_lease(&mut lease);
46
47 match result {
48 Ok(value) => Ok(value),
49 Err(panic) => resume_unwind(panic),
50 }
51 }
52
53 fn model_revision<T: Any>(&self, model: &Model<T>) -> Option<u64> {
54 self.models().revision(model)
55 }
56
57 #[track_caller]
58 fn update_model<T: Any, R>(
59 &mut self,
60 model: &Model<T>,
61 f: impl FnOnce(&mut T, &mut ModelCx<'_, Self>) -> R,
62 ) -> Result<R, ModelUpdateError> {
63 let changed_at = Location::caller();
64
65 let mut lease = self.models_mut().lease(model)?;
66 let result = if cfg!(panic = "unwind") {
67 catch_unwind(AssertUnwindSafe(|| {
68 let mut cx = ModelCx { host: self };
69 f(lease.value_mut(), &mut cx)
70 }))
71 } else {
72 Ok({
73 let mut cx = ModelCx { host: self };
74 f(lease.value_mut(), &mut cx)
75 })
76 };
77
78 match result {
79 Ok(value) => {
80 lease.mark_dirty();
81 self.models_mut()
82 .end_lease_with_changed_at(&mut lease, changed_at);
83 Ok(value)
84 }
85 Err(panic) => {
86 self.models_mut().end_lease(&mut lease);
87 resume_unwind(panic)
88 }
89 }
90 }
91}