1use crate::{LayoutReceipt, UiDraw, UiDrawList, UiDrawListView, UiView};
7
8#[doc = crate::_tags!(ui)]
9#[doc = crate::_doc_meta! {
11 location("ui/frame", struct UiOutput),
12}]
13#[must_use]
28#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash)]
29pub struct UiOutput<L, V, D> {
30 layouts: L,
31 views: V,
32 draws: D,
33}
34
35#[rustfmt::skip]
36impl<L, V, D> UiOutput<L, V, D> {
37 pub const fn from_parts(layouts: L, views: V, draws: D) -> Self {
39 Self { layouts, views, draws }
40 }
41
42 pub const fn layout_storage(&self) -> &L { &self.layouts }
44 pub const fn view_storage(&self) -> &V { &self.views }
46 pub const fn draw_list(&self) -> &D { &self.draws }
48
49 pub fn into_parts(self) -> (L, V, D) { (self.layouts, self.views, self.draws) }
51
52 pub const fn into_parts_const(self) -> (L, V, D) where Self: Copy {
54 (self.layouts, self.views, self.draws)
55 }
56}
57
58#[rustfmt::skip]
59impl<L, V, S, T, B> UiOutput<L, V, UiDrawList<S, T, B>>
60where
61 L: AsRef<[LayoutReceipt]>,
62 V: AsRef<[UiView]>,
63 B: AsRef<[UiDraw<S, T>]>,
64{
65 pub fn as_view(&self) -> UiOutputView<'_, S, T> {
67 UiOutputView::from_parts(self.layouts.as_ref(), self.views.as_ref(), self.draws.as_view())
68 }
69 pub fn layouts(&self) -> &[LayoutReceipt] { self.layouts.as_ref() }
71 pub fn views(&self) -> &[UiView] { self.views.as_ref() }
73}
74
75#[doc = crate::_tags!(ui lifetime)]
76#[doc = crate::_doc_meta! {
78 location("ui/frame", struct UiOutputView),
79 #[cfg(target_pointer_width = "32")]
80 test_size_of(UiOutputView<u8, &str> = 24|192; niche Option),
81 #[cfg(target_pointer_width = "64")]
82 test_size_of(UiOutputView<u8, &str> = 48|384; niche Option),
83}]
84#[must_use]
88#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
89pub struct UiOutputView<'a, S, T = &'a str> {
90 layouts: &'a [LayoutReceipt],
91 views: &'a [UiView],
92 draws: UiDrawListView<'a, S, T>,
93}
94
95#[rustfmt::skip]
96impl<'a, S, T> UiOutputView<'a, S, T> {
97 pub const fn from_parts(
99 layouts: &'a [LayoutReceipt],
100 views: &'a [UiView],
101 draws: UiDrawListView<'a, S, T>,
102 ) -> Self {
103 Self { layouts, views, draws }
104 }
105 pub const fn from_slices(
107 layouts: &'a [LayoutReceipt],
108 views: &'a [UiView],
109 draws: &'a [UiDraw<S, T>],
110 ) -> Self {
111 Self::from_parts(layouts, views, UiDrawList::from_slice(draws))
112 }
113 pub const fn layouts(&self) -> &'a [LayoutReceipt] { self.layouts }
115 pub const fn views(&self) -> &'a [UiView] { self.views }
117 pub const fn draw_list(&self) -> &UiDrawListView<'a, S, T> { &self.draws }
119}
120
121#[cfg(test)]
122mod _test {
123 use super::*;
124 use crate::{Ptr, UiRect};
125
126 #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
127 enum Style {
128 Background,
129 Foreground,
130 }
131 fn draw(style: Style) -> UiDraw<Style> {
132 UiDraw::rect_fill(UiRect::default(), style)
133 }
134
135 #[test]
136 fn constructs_from_parts() {
137 let layouts = [LayoutReceipt::default()];
138 let views = [UiView::default()];
139 let draws = UiDrawList::from_array([draw(Style::Background), draw(Style::Foreground)]);
140 let output = UiOutput::from_parts(layouts, views, draws);
141 assert_eq!(output.layout_storage().len(), 1);
142 assert_eq!(output.view_storage().len(), 1);
143 assert_eq!(output.draw_list().len(), 2);
144 }
145 #[test]
146 fn borrowed_view_preserves_all_streams() {
147 let output = UiOutput::from_parts(
148 [LayoutReceipt::default()],
149 [UiView::default()],
150 UiDrawList::from_array([draw(Style::Background), draw(Style::Foreground)]),
151 );
152 let view = output.as_view();
153 assert_eq!(view.layouts(), output.layout_storage().as_slice());
154 assert_eq!(view.views(), output.view_storage().as_slice());
155 assert_eq!(view.draw_list().as_slice(), output.draw_list().as_slice(),);
156 assert!(Ptr::eq(view.layouts().as_ptr(), output.layout_storage().as_ptr(),));
157 assert!(Ptr::eq(view.views().as_ptr(), output.view_storage().as_ptr(),));
158 assert!(Ptr::eq(
159 view.draw_list().as_slice().as_ptr(),
160 output.draw_list().as_slice().as_ptr(),
161 ));
162 }
163 #[test]
164 fn constructs_view_directly_from_slices() {
165 let layouts = [LayoutReceipt::default()];
166 let views = [UiView::default()];
167 let draws = [draw(Style::Background), draw(Style::Foreground)];
168 let output = UiOutputView::from_slices(&layouts, &views, &draws);
169 assert_eq!(output.layouts(), &layouts);
170 assert_eq!(output.views(), &views);
171 assert_eq!(output.draw_list().as_slice(), &draws);
172 }
173 #[test]
174 fn into_parts_returns_original_storage() {
175 let layouts = [LayoutReceipt::default()];
176 let views = [UiView::default()];
177 let draws = UiDrawList::from_array([draw(Style::Background)]);
178 let output = UiOutput::from_parts(layouts, views, draws);
179 let (actual_layouts, actual_views, actual_draws) = output.into_parts();
180 assert_eq!(actual_layouts, layouts);
181 assert_eq!(actual_views, views);
182 assert_eq!(actual_draws.as_slice(), draws.as_slice());
183 }
184}