Skip to content

Commit 6a45203

Browse files
authored
Merge pull request #196 from rust-windowing/traits
Use traits to define common backend interface
2 parents 2b44e7a + d7b32fa commit 6a45203

File tree

14 files changed

+608
-562
lines changed

14 files changed

+608
-562
lines changed

.github/workflows/ci.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,7 @@ jobs:
9393

9494
- name: Pin versions of dev-deps
9595
if: matrix.rust_version == '1.65.0'
96-
run: cargo update -p half --precise 2.2.1
96+
run: cargo update -p exr --precise 1.71.0 && cargo update -p ahash --precise 0.8.7
9797

9898
- name: Build tests
9999
shell: bash

src/backend_dispatch.rs

Lines changed: 195 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,195 @@
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::rc::Rc;
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(Rc<backends::x11::X11DisplayImpl<D>>, backends::x11::X11Impl<D, W>, backends::x11::BufferImpl<'a, D, W>),
183+
#[cfg(wayland_platform)]
184+
Wayland(Rc<backends::wayland::WaylandDisplayImpl<D>>, backends::wayland::WaylandImpl<D, W>, backends::wayland::BufferImpl<'a, D, W>),
185+
#[cfg(kms_platform)]
186+
Kms(Rc<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_os = "macos")]
190+
CG(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+
}

src/backend_interface.rs

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
//! Interface implemented by backends
2+
3+
use crate::{InitError, Rect, SoftBufferError};
4+
5+
use raw_window_handle::{HasDisplayHandle, HasWindowHandle};
6+
use std::num::NonZeroU32;
7+
8+
pub(crate) trait ContextInterface<D: HasDisplayHandle + ?Sized> {
9+
fn new(display: D) -> Result<Self, InitError<D>>
10+
where
11+
D: Sized,
12+
Self: Sized;
13+
}
14+
15+
pub(crate) trait SurfaceInterface<D: HasDisplayHandle + ?Sized, W: HasWindowHandle + ?Sized> {
16+
type Context: ContextInterface<D>;
17+
type Buffer<'a>: BufferInterface
18+
where
19+
Self: 'a;
20+
21+
fn new(window: W, context: &Self::Context) -> Result<Self, InitError<W>>
22+
where
23+
W: Sized,
24+
Self: Sized;
25+
/// Get the inner window handle.
26+
fn window(&self) -> &W;
27+
/// Resize the internal buffer to the given width and height.
28+
fn resize(&mut self, width: NonZeroU32, height: NonZeroU32) -> Result<(), SoftBufferError>;
29+
/// Get a mutable reference to the buffer.
30+
fn buffer_mut(&mut self) -> Result<Self::Buffer<'_>, SoftBufferError>;
31+
/// Fetch the buffer from the window.
32+
fn fetch(&mut self) -> Result<Vec<u32>, SoftBufferError> {
33+
Err(SoftBufferError::Unimplemented)
34+
}
35+
}
36+
37+
pub(crate) trait BufferInterface {
38+
fn pixels(&self) -> &[u32];
39+
fn pixels_mut(&mut self) -> &mut [u32];
40+
fn age(&self) -> u8;
41+
fn present_with_damage(self, damage: &[Rect]) -> Result<(), SoftBufferError>;
42+
fn present(self) -> Result<(), SoftBufferError>;
43+
}

src/cg.rs renamed to src/backends/cg.rs

Lines changed: 15 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
use crate::backend_interface::*;
12
use crate::error::InitError;
23
use crate::{Rect, SoftBufferError};
34
use core_graphics::base::{
@@ -34,8 +35,11 @@ pub struct CGImpl<D, W> {
3435
_display: PhantomData<D>,
3536
}
3637

37-
impl<D: HasDisplayHandle, W: HasWindowHandle> CGImpl<D, W> {
38-
pub(crate) fn new(window_src: W) -> Result<Self, InitError<W>> {
38+
impl<D: HasDisplayHandle, W: HasWindowHandle> SurfaceInterface<D, W> for CGImpl<D, W> {
39+
type Context = D;
40+
type Buffer<'a> = BufferImpl<'a, D, W> where Self: 'a;
41+
42+
fn new(window_src: W, _display: &D) -> Result<Self, InitError<W>> {
3943
let raw = window_src.window_handle()?.as_raw();
4044
let handle = match raw {
4145
RawWindowHandle::AppKit(handle) => handle,
@@ -66,18 +70,17 @@ impl<D: HasDisplayHandle, W: HasWindowHandle> CGImpl<D, W> {
6670
})
6771
}
6872

69-
/// Get the inner window handle.
7073
#[inline]
71-
pub fn window(&self) -> &W {
74+
fn window(&self) -> &W {
7275
&self.window_handle
7376
}
7477

75-
pub fn resize(&mut self, width: NonZeroU32, height: NonZeroU32) -> Result<(), SoftBufferError> {
78+
fn resize(&mut self, width: NonZeroU32, height: NonZeroU32) -> Result<(), SoftBufferError> {
7679
self.size = Some((width, height));
7780
Ok(())
7881
}
7982

80-
pub fn buffer_mut(&mut self) -> Result<BufferImpl<'_, D, W>, SoftBufferError> {
83+
fn buffer_mut(&mut self) -> Result<BufferImpl<'_, D, W>, SoftBufferError> {
8184
let (width, height) = self
8285
.size
8386
.expect("Must set size of surface before calling `buffer_mut()`");
@@ -87,34 +90,29 @@ impl<D: HasDisplayHandle, W: HasWindowHandle> CGImpl<D, W> {
8790
imp: self,
8891
})
8992
}
90-
91-
/// Fetch the buffer from the window.
92-
pub fn fetch(&mut self) -> Result<Vec<u32>, SoftBufferError> {
93-
Err(SoftBufferError::Unimplemented)
94-
}
9593
}
9694

9795
pub struct BufferImpl<'a, D, W> {
9896
imp: &'a mut CGImpl<D, W>,
9997
buffer: Vec<u32>,
10098
}
10199

102-
impl<'a, D: HasDisplayHandle, W: HasWindowHandle> BufferImpl<'a, D, W> {
100+
impl<'a, D: HasDisplayHandle, W: HasWindowHandle> BufferInterface for BufferImpl<'a, D, W> {
103101
#[inline]
104-
pub fn pixels(&self) -> &[u32] {
102+
fn pixels(&self) -> &[u32] {
105103
&self.buffer
106104
}
107105

108106
#[inline]
109-
pub fn pixels_mut(&mut self) -> &mut [u32] {
107+
fn pixels_mut(&mut self) -> &mut [u32] {
110108
&mut self.buffer
111109
}
112110

113-
pub fn age(&self) -> u8 {
111+
fn age(&self) -> u8 {
114112
0
115113
}
116114

117-
pub fn present(self) -> Result<(), SoftBufferError> {
115+
fn present(self) -> Result<(), SoftBufferError> {
118116
let data_provider = CGDataProvider::from_buffer(Arc::new(Buffer(self.buffer)));
119117
let (width, height) = self.imp.size.unwrap();
120118
let image = CGImage::new(
@@ -148,7 +146,7 @@ impl<'a, D: HasDisplayHandle, W: HasWindowHandle> BufferImpl<'a, D, W> {
148146
Ok(())
149147
}
150148

151-
pub fn present_with_damage(self, _damage: &[Rect]) -> Result<(), SoftBufferError> {
149+
fn present_with_damage(self, _damage: &[Rect]) -> Result<(), SoftBufferError> {
152150
self.present()
153151
}
154152
}

0 commit comments

Comments
 (0)