1 | //! Implements `buffer_interface::*` traits for enums dispatching to backends |
2 | |
3 | use crate::{backend_interface::*, backends, InitError, Rect, SoftBufferError}; |
4 | |
5 | use raw_window_handle::{HasDisplayHandle, HasWindowHandle}; |
6 | use std::num::NonZeroU32; |
7 | #[cfg (any(wayland_platform, x11_platform, kms_platform))] |
8 | use std::sync::Arc; |
9 | |
10 | /// A macro for creating the enum used to statically dispatch to the platform-specific implementation. |
11 | macro_rules! make_dispatch { |
12 | ( |
13 | <$dgen: ident, $wgen: ident> => |
14 | $( |
15 | $(#[$attr:meta])* |
16 | $name: ident |
17 | ($context_inner: ty, $surface_inner: ty, $buffer_inner: ty), |
18 | )* |
19 | ) => { |
20 | pub(crate) enum ContextDispatch<$dgen> { |
21 | $( |
22 | $(#[$attr])* |
23 | $name($context_inner), |
24 | )* |
25 | } |
26 | |
27 | impl<D: HasDisplayHandle> ContextDispatch<D> { |
28 | pub fn variant_name(&self) -> &'static str { |
29 | match self { |
30 | $( |
31 | $(#[$attr])* |
32 | Self::$name(_) => stringify!($name), |
33 | )* |
34 | } |
35 | } |
36 | } |
37 | |
38 | impl<D: HasDisplayHandle> ContextInterface<D> for ContextDispatch<D> { |
39 | fn new(mut display: D) -> Result<Self, InitError<D>> |
40 | where |
41 | D: Sized, |
42 | { |
43 | $( |
44 | $(#[$attr])* |
45 | match <$context_inner as ContextInterface<D>>::new(display) { |
46 | Ok(x) => { |
47 | return Ok(Self::$name(x)); |
48 | } |
49 | Err(InitError::Unsupported(d)) => display = d, |
50 | Err(InitError::Failure(f)) => return Err(InitError::Failure(f)), |
51 | } |
52 | )* |
53 | |
54 | Err(InitError::Unsupported(display)) |
55 | } |
56 | } |
57 | |
58 | #[allow(clippy::large_enum_variant)] // it's boxed anyways |
59 | pub(crate) enum SurfaceDispatch<$dgen, $wgen> { |
60 | $( |
61 | $(#[$attr])* |
62 | $name($surface_inner), |
63 | )* |
64 | } |
65 | |
66 | impl<D: HasDisplayHandle, W: HasWindowHandle> SurfaceInterface<D, W> for SurfaceDispatch<D, W> { |
67 | type Context = ContextDispatch<D>; |
68 | type Buffer<'a> = BufferDispatch<'a, D, W> where Self: 'a; |
69 | |
70 | fn new(window: W, display: &Self::Context) -> Result<Self, InitError<W>> |
71 | where |
72 | W: Sized, |
73 | Self: Sized { |
74 | match display { |
75 | $( |
76 | $(#[$attr])* |
77 | ContextDispatch::$name(inner) => Ok(Self::$name(<$surface_inner>::new(window, inner)?)), |
78 | )* |
79 | } |
80 | } |
81 | |
82 | fn window(&self) -> &W { |
83 | match self { |
84 | $( |
85 | $(#[$attr])* |
86 | Self::$name(inner) => inner.window(), |
87 | )* |
88 | } |
89 | } |
90 | |
91 | fn resize(&mut self, width: NonZeroU32, height: NonZeroU32) -> Result<(), SoftBufferError> { |
92 | match self { |
93 | $( |
94 | $(#[$attr])* |
95 | Self::$name(inner) => inner.resize(width, height), |
96 | )* |
97 | } |
98 | } |
99 | |
100 | fn buffer_mut(&mut self) -> Result<BufferDispatch<'_, D, W>, SoftBufferError> { |
101 | match self { |
102 | $( |
103 | $(#[$attr])* |
104 | Self::$name(inner) => Ok(BufferDispatch::$name(inner.buffer_mut()?)), |
105 | )* |
106 | } |
107 | } |
108 | |
109 | fn fetch(&mut self) -> Result<Vec<u32>, SoftBufferError> { |
110 | match self { |
111 | $( |
112 | $(#[$attr])* |
113 | Self::$name(inner) => inner.fetch(), |
114 | )* |
115 | } |
116 | } |
117 | } |
118 | |
119 | pub(crate) enum BufferDispatch<'a, $dgen, $wgen> { |
120 | $( |
121 | $(#[$attr])* |
122 | $name($buffer_inner), |
123 | )* |
124 | } |
125 | |
126 | impl<'a, D: HasDisplayHandle, W: HasWindowHandle> BufferInterface for BufferDispatch<'a, D, W> { |
127 | #[inline] |
128 | fn pixels(&self) -> &[u32] { |
129 | match self { |
130 | $( |
131 | $(#[$attr])* |
132 | Self::$name(inner) => inner.pixels(), |
133 | )* |
134 | } |
135 | } |
136 | |
137 | #[inline] |
138 | fn pixels_mut(&mut self) -> &mut [u32] { |
139 | match self { |
140 | $( |
141 | $(#[$attr])* |
142 | Self::$name(inner) => inner.pixels_mut(), |
143 | )* |
144 | } |
145 | } |
146 | |
147 | fn age(&self) -> u8 { |
148 | match self { |
149 | $( |
150 | $(#[$attr])* |
151 | Self::$name(inner) => inner.age(), |
152 | )* |
153 | } |
154 | } |
155 | |
156 | fn present(self) -> Result<(), SoftBufferError> { |
157 | match self { |
158 | $( |
159 | $(#[$attr])* |
160 | Self::$name(inner) => inner.present(), |
161 | )* |
162 | } |
163 | } |
164 | |
165 | fn present_with_damage(self, damage: &[Rect]) -> Result<(), SoftBufferError> { |
166 | match self { |
167 | $( |
168 | $(#[$attr])* |
169 | Self::$name(inner) => inner.present_with_damage(damage), |
170 | )* |
171 | } |
172 | } |
173 | } |
174 | }; |
175 | } |
176 | |
177 | // XXX empty enum with generic bound is invalid? |
178 | |
179 | make_dispatch! { |
180 | <D, W> => |
181 | #[cfg (x11_platform)] |
182 | X11(Arc<backends::x11::X11DisplayImpl<D>>, backends::x11::X11Impl<D, W>, backends::x11::BufferImpl<'a, D, W>), |
183 | #[cfg (wayland_platform)] |
184 | Wayland(Arc<backends::wayland::WaylandDisplayImpl<D>>, backends::wayland::WaylandImpl<D, W>, backends::wayland::BufferImpl<'a, D, W>), |
185 | #[cfg (kms_platform)] |
186 | Kms(Arc<backends::kms::KmsDisplayImpl<D>>, backends::kms::KmsImpl<D, W>, backends::kms::BufferImpl<'a, D, W>), |
187 | #[cfg (target_os = "windows" )] |
188 | Win32(D, backends::win32::Win32Impl<D, W>, backends::win32::BufferImpl<'a, D, W>), |
189 | #[cfg (target_vendor = "apple" )] |
190 | CoreGraphics(D, backends::cg::CGImpl<D, W>, backends::cg::BufferImpl<'a, D, W>), |
191 | #[cfg (target_arch = "wasm32" )] |
192 | Web(backends::web::WebDisplayImpl<D>, backends::web::WebImpl<D, W>, backends::web::BufferImpl<'a, D, W>), |
193 | #[cfg (target_os = "redox" )] |
194 | Orbital(D, backends::orbital::OrbitalImpl<D, W>, backends::orbital::BufferImpl<'a, D, W>), |
195 | } |
196 | |