Skip to main content

fret_ui_kit/declarative/
cached_subtree.rs

1use fret_core::{Corners, Rect, TextStyle};
2use fret_ui::element::{AnyElement, LayoutStyle, ViewCacheProps};
3use fret_ui::{ElementContext, UiHost};
4
5use crate::{IntoUiElement, collect_children};
6
7/// Component-layer helper for authoring explicit cached subtree boundaries.
8///
9/// This intentionally lives in the ecosystem layer (ADR 0066): it is sugar on top of the
10/// mechanism-only `ElementContext::view_cache(...)` API in `fret-ui`.
11pub trait CachedSubtreeExt {
12    type Host: UiHost;
13
14    /// Build an explicit cached subtree boundary using default cache-root behavior.
15    fn cached_subtree<I, T>(&mut self, f: impl FnOnce(&mut Self) -> I) -> AnyElement
16    where
17        I: IntoIterator<Item = T>,
18        T: IntoUiElement<Self::Host>,
19    {
20        self.cached_subtree_with(CachedSubtreeProps::default(), f)
21    }
22
23    /// Build an explicit cached subtree boundary with additional cache-root hints.
24    fn cached_subtree_with<I, T>(
25        &mut self,
26        props: CachedSubtreeProps,
27        f: impl FnOnce(&mut Self) -> I,
28    ) -> AnyElement
29    where
30        I: IntoIterator<Item = T>,
31        T: IntoUiElement<Self::Host>;
32}
33
34#[derive(Debug, Clone, Copy, Default)]
35pub struct CachedSubtreeProps {
36    pub layout: LayoutStyle,
37    pub contained_layout: bool,
38    pub cache_key: u64,
39}
40
41impl CachedSubtreeProps {
42    pub fn layout(mut self, layout: LayoutStyle) -> Self {
43        self.layout = layout;
44        self
45    }
46
47    pub fn contained_layout(mut self, contained_layout: bool) -> Self {
48        self.contained_layout = contained_layout;
49        self
50    }
51
52    pub fn cache_key(mut self, cache_key: u64) -> Self {
53        self.cache_key = cache_key;
54        self
55    }
56
57    pub fn cache_key_text_style(mut self, style: &TextStyle) -> Self {
58        self.cache_key =
59            fret_ui::cache_key::mix(self.cache_key, fret_ui::cache_key::text_style_key(style));
60        self
61    }
62
63    pub fn cache_key_clip_rect(mut self, rect: Rect) -> Self {
64        self.cache_key =
65            fret_ui::cache_key::mix(self.cache_key, fret_ui::cache_key::rect_key(rect));
66        self
67    }
68
69    pub fn cache_key_clip_rrect(mut self, rect: Rect, corners: Corners) -> Self {
70        self.cache_key =
71            fret_ui::cache_key::mix(self.cache_key, fret_ui::cache_key::rect_key(rect));
72        self.cache_key =
73            fret_ui::cache_key::mix(self.cache_key, fret_ui::cache_key::corners_key(corners));
74        self
75    }
76}
77
78impl<'a, H: UiHost> CachedSubtreeExt for ElementContext<'a, H> {
79    type Host = H;
80
81    fn cached_subtree_with<I, T>(
82        &mut self,
83        props: CachedSubtreeProps,
84        f: impl FnOnce(&mut Self) -> I,
85    ) -> AnyElement
86    where
87        I: IntoIterator<Item = T>,
88        T: IntoUiElement<Self::Host>,
89    {
90        let view_cache = ViewCacheProps {
91            layout: props.layout,
92            contained_layout: props.contained_layout,
93            cache_key: props.cache_key,
94        };
95        self.view_cache(view_cache, move |cx| {
96            let items = f(cx);
97            collect_children(cx, items)
98        })
99    }
100}