Skip to content

Commit dc6fc47

Browse files
committed
Added better error handling
1 parent e4b1917 commit dc6fc47

File tree

8 files changed

+135
-104
lines changed

8 files changed

+135
-104
lines changed

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ authors = ["David Johnson <[email protected]>"]
66
license = "MIT OR Apache-2.0"
77

88
[dependencies]
9+
thiserror = "1.0.30"
910
raw-window-handle = "0.4.2"
1011

1112
[target.'cfg(target_os = "linux")'.dependencies]

README.md

Lines changed: 15 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -52,15 +52,15 @@ For now, the priority for new platforms is:
5252
Example
5353
==
5454
```no_run
55+
use softbuffer::GraphicsContext;
5556
use winit::event::{Event, WindowEvent};
5657
use winit::event_loop::{ControlFlow, EventLoop};
5758
use winit::window::WindowBuilder;
58-
use softbuffer::GraphicsContext;
5959
6060
fn main() {
6161
let event_loop = EventLoop::new();
6262
let window = WindowBuilder::new().build(&event_loop).unwrap();
63-
let mut graphics_context = unsafe { GraphicsContext::new(window) };
63+
let mut graphics_context = unsafe { GraphicsContext::new(window) }.unwrap();
6464
6565
event_loop.run(move |event, _, control_flow| {
6666
*control_flow = ControlFlow::Wait;
@@ -71,26 +71,28 @@ fn main() {
7171
let size = graphics_context.window().inner_size();
7272
(size.width, size.height)
7373
};
74-
let buffer = (0..((width*height) as usize)).map(|index|{
75-
let y = index / (width as usize);
76-
let x = index % (width as usize);
77-
let red = x % 255;
78-
let green = y % 255;
79-
let blue = (x*y) % 255;
74+
let buffer = (0..((width * height) as usize))
75+
.map(|index| {
76+
let y = index / (width as usize);
77+
let x = index % (width as usize);
78+
let red = x % 255;
79+
let green = y % 255;
80+
let blue = (x * y) % 255;
8081
81-
let color = blue | (green << 8) | (red << 16);
82+
let color = blue | (green << 8) | (red << 16);
8283
83-
color as u32
84-
}).collect::<Vec<_>>();
84+
color as u32
85+
})
86+
.collect::<Vec<_>>();
8587
8688
graphics_context.set_buffer(&buffer, width as u16, height as u16);
8789
}
8890
Event::WindowEvent {
8991
event: WindowEvent::CloseRequested,
90-
window_id
92+
window_id,
9193
} if window_id == graphics_context.window().id() => {
9294
*control_flow = ControlFlow::Exit;
93-
},
95+
}
9496
_ => {}
9597
}
9698
});

examples/winit.rs

Lines changed: 16 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
1+
use softbuffer::GraphicsContext;
12
use winit::event::{Event, WindowEvent};
23
use winit::event_loop::{ControlFlow, EventLoop};
34
use winit::window::WindowBuilder;
4-
use softbuffer::GraphicsContext;
55

66
fn main() {
77
let event_loop = EventLoop::new();
88
let window = WindowBuilder::new().build(&event_loop).unwrap();
9-
let mut graphics_context = unsafe { GraphicsContext::new(window) };
9+
let mut graphics_context = unsafe { GraphicsContext::new(window) }.unwrap();
1010

1111
event_loop.run(move |event, _, control_flow| {
1212
*control_flow = ControlFlow::Wait;
@@ -17,27 +17,29 @@ fn main() {
1717
let size = graphics_context.window().inner_size();
1818
(size.width, size.height)
1919
};
20-
let buffer = (0..((width*height) as usize)).map(|index|{
21-
let y = index / (width as usize);
22-
let x = index % (width as usize);
23-
let red = x % 255;
24-
let green = y % 255;
25-
let blue = (x*y) % 255;
20+
let buffer = (0..((width * height) as usize))
21+
.map(|index| {
22+
let y = index / (width as usize);
23+
let x = index % (width as usize);
24+
let red = x % 255;
25+
let green = y % 255;
26+
let blue = (x * y) % 255;
2627

27-
let color = blue | (green << 8) | (red << 16);
28+
let color = blue | (green << 8) | (red << 16);
2829

29-
color as u32
30-
}).collect::<Vec<_>>();
30+
color as u32
31+
})
32+
.collect::<Vec<_>>();
3133

3234
graphics_context.set_buffer(&buffer, width as u16, height as u16);
3335
}
3436
Event::WindowEvent {
3537
event: WindowEvent::CloseRequested,
36-
window_id
38+
window_id,
3739
} if window_id == graphics_context.window().id() => {
3840
*control_flow = ControlFlow::Exit;
39-
},
41+
}
4042
_ => {}
4143
}
4244
});
43-
}
45+
}

examples/winit_wrong_sized_buffer.rs

Lines changed: 16 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,42 +1,44 @@
1+
use softbuffer::GraphicsContext;
12
use winit::event::{Event, WindowEvent};
23
use winit::event_loop::{ControlFlow, EventLoop};
34
use winit::window::WindowBuilder;
4-
use softbuffer::GraphicsContext;
55

66
const BUFFER_WIDTH: usize = 256;
77
const BUFFER_HEIGHT: usize = 128;
88

99
fn main() {
1010
let event_loop = EventLoop::new();
1111
let window = WindowBuilder::new().build(&event_loop).unwrap();
12-
let mut graphics_context = unsafe { GraphicsContext::new(window) };
12+
let mut graphics_context = unsafe { GraphicsContext::new(window) }.unwrap();
1313

1414
event_loop.run(move |event, _, control_flow| {
1515
*control_flow = ControlFlow::Wait;
1616

1717
match event {
1818
Event::RedrawRequested(window_id) if window_id == graphics_context.window().id() => {
19-
let buffer = (0..((BUFFER_WIDTH*BUFFER_HEIGHT) as usize)).map(|index|{
20-
let y = index / (BUFFER_WIDTH as usize);
21-
let x = index % (BUFFER_WIDTH as usize);
22-
let red = x % 255;
23-
let green = y % 255;
24-
let blue = (x*y) % 255;
19+
let buffer = (0..((BUFFER_WIDTH * BUFFER_HEIGHT) as usize))
20+
.map(|index| {
21+
let y = index / (BUFFER_WIDTH as usize);
22+
let x = index % (BUFFER_WIDTH as usize);
23+
let red = x % 255;
24+
let green = y % 255;
25+
let blue = (x * y) % 255;
2526

26-
let color = blue | (green << 8) | (red << 16);
27+
let color = blue | (green << 8) | (red << 16);
2728

28-
color as u32
29-
}).collect::<Vec<_>>();
29+
color as u32
30+
})
31+
.collect::<Vec<_>>();
3032

3133
graphics_context.set_buffer(&buffer, BUFFER_WIDTH as u16, BUFFER_HEIGHT as u16);
3234
}
3335
Event::WindowEvent {
3436
event: WindowEvent::CloseRequested,
35-
window_id
37+
window_id,
3638
} if window_id == graphics_context.window().id() => {
3739
*control_flow = ControlFlow::Exit;
38-
},
40+
}
3941
_ => {}
4042
}
4143
});
42-
}
44+
}

src/error.rs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
use std::error::Error;
2+
use raw_window_handle::{HasRawWindowHandle, RawWindowHandle};
3+
use thiserror::Error;
4+
5+
#[derive(Error, Debug)]
6+
pub enum SoftBufferError<W: HasRawWindowHandle> {
7+
#[error(
8+
"The provided window returned an unsupported platform: {human_readable_platform_name}."
9+
)]
10+
UnsupportedPlatform {
11+
window: W,
12+
human_readable_platform_name: &'static str,
13+
handle: RawWindowHandle,
14+
},
15+
#[error("Platform error")]
16+
PlatformError(Option<String>, Option<Box<dyn Error>>)
17+
}

src/lib.rs

Lines changed: 28 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,53 +1,59 @@
11
#![doc = include_str!("../README.md")]
22

3-
#[cfg(target_os = "linux")]
4-
mod x11;
53
#[cfg(target_os = "windows")]
64
mod win32;
5+
#[cfg(target_os = "linux")]
6+
mod x11;
7+
8+
mod error;
9+
pub use error::SoftBufferError;
710

811
use raw_window_handle::{HasRawWindowHandle, RawWindowHandle};
912

1013
/// An instance of this struct contains the platform-specific data that must be managed in order to
1114
/// write to a window on that platform. This struct owns the window that this data corresponds to
1215
/// to ensure safety, as that data must be destroyed before the window itself is destroyed. You may
1316
/// access the underlying window via [`window`](Self::window) and [`window_mut`](Self::window_mut).
14-
pub struct GraphicsContext<W: HasRawWindowHandle>{
17+
pub struct GraphicsContext<W: HasRawWindowHandle> {
1518
window: W,
16-
graphics_context_impl: Box<dyn GraphicsContextImpl>
19+
graphics_context_impl: Box<dyn GraphicsContextImpl>,
1720
}
1821

1922
impl<W: HasRawWindowHandle> GraphicsContext<W> {
20-
2123
/// Creates a new instance of this struct, consuming the given window.
2224
///
2325
/// # Safety
2426
///
2527
/// - Ensure that the passed object is valid to draw a 2D buffer to
26-
pub unsafe fn new(window: W) -> Self{
28+
pub unsafe fn new(window: W) -> Result<Self, SoftBufferError<W>> {
2729
let raw_handle = window.raw_window_handle();
28-
let imple = match raw_handle{
30+
let imple = match raw_handle {
2931
#[cfg(target_os = "linux")]
30-
RawWindowHandle::Xlib(xlib_handle) => Box::new(x11::X11Impl::new(xlib_handle)),
32+
RawWindowHandle::Xlib(xlib_handle) => Box::new(x11::X11Impl::new(xlib_handle)?),
3133
#[cfg(target_os = "windows")]
32-
RawWindowHandle::Win32(win32_handle) => Box::new(win32::Win32Impl::new(&win32_handle)),
33-
unimplemented_handle_type => unimplemented!("Unsupported window handle type: {}.", window_handle_type_name(&unimplemented_handle_type))
34+
RawWindowHandle::Win32(win32_handle) => Box::new(win32::Win32Impl::new(&win32_handle)?),
35+
unimplemented_handle_type => return Err(SoftBufferError::UnsupportedPlatform {
36+
window,
37+
human_readable_platform_name: window_handle_type_name(&unimplemented_handle_type),
38+
handle: unimplemented_handle_type,
39+
}),
3440
};
3541

36-
Self{
42+
Ok(Self {
3743
window,
38-
graphics_context_impl: imple
39-
}
44+
graphics_context_impl: imple,
45+
})
4046
}
4147

4248
/// Gets shared access to the underlying window
4349
#[inline]
44-
pub fn window(&self) -> &W{
50+
pub fn window(&self) -> &W {
4551
&self.window
4652
}
4753

4854
/// Gets mut/exclusive access to the underlying window
4955
#[inline]
50-
pub fn window_mut(&mut self) -> &mut W{
56+
pub fn window_mut(&mut self) -> &mut W {
5157
&mut self.window
5258
}
5359

@@ -75,24 +81,23 @@ impl<W: HasRawWindowHandle> GraphicsContext<W> {
7581
/// G: Green channel
7682
/// B: Blue channel
7783
#[inline]
78-
pub fn set_buffer(&mut self, buffer: &[u32], width: u16, height: u16){
79-
if (width as usize)*(height as usize) != buffer.len(){
84+
pub fn set_buffer(&mut self, buffer: &[u32], width: u16, height: u16) {
85+
if (width as usize) * (height as usize) != buffer.len() {
8086
panic!("The size of the passed buffer is not the correct size. Its length must be exactly width*height.");
8187
}
8288

8389
unsafe {
8490
self.graphics_context_impl.set_buffer(buffer, width, height);
8591
}
8692
}
87-
8893
}
8994

90-
trait GraphicsContextImpl{
95+
trait GraphicsContextImpl {
9196
unsafe fn set_buffer(&mut self, buffer: &[u32], width: u16, height: u16);
9297
}
9398

94-
fn window_handle_type_name(handle: &RawWindowHandle) -> &'static str{
95-
match handle{
99+
fn window_handle_type_name(handle: &RawWindowHandle) -> &'static str {
100+
match handle {
96101
RawWindowHandle::Xlib(_) => "Xlib",
97102
RawWindowHandle::Win32(_) => "Win32",
98103
RawWindowHandle::WinRt(_) => "WinRt",
@@ -102,6 +107,6 @@ fn window_handle_type_name(handle: &RawWindowHandle) -> &'static str{
102107
RawWindowHandle::AppKit(_) => "AppKit",
103108
RawWindowHandle::Orbital(_) => "Orbital",
104109
RawWindowHandle::UiKit(_) => "UiKit",
105-
_ => "Unknown Name" //don't completely fail to compile if there is a new raw window handle type that's added at some point
110+
_ => "Unknown Name", //don't completely fail to compile if there is a new raw window handle type that's added at some point
106111
}
107-
}
112+
}

src/win32.rs

Lines changed: 20 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
1+
use crate::{GraphicsContextImpl, SoftBufferError};
2+
use raw_window_handle::{HasRawWindowHandle, Win32Handle};
13
use std::os::raw::c_int;
2-
use raw_window_handle::Win32Handle;
3-
use crate::GraphicsContextImpl;
4-
use winapi::um::wingdi::{BITMAPINFOHEADER, BI_BITFIELDS, RGBQUAD, StretchDIBits};
5-
use winapi::um::winuser::{ValidateRect, GetDC};
6-
use winapi::shared::windef::{HWND, HDC};
4+
use winapi::shared::windef::{HDC, HWND};
5+
use winapi::um::wingdi::{StretchDIBits, BITMAPINFOHEADER, BI_BITFIELDS, RGBQUAD};
6+
use winapi::um::winuser::{GetDC, ValidateRect};
77

8-
pub struct Win32Impl{
8+
pub struct Win32Impl {
99
window: HWND,
10-
dc: HDC
10+
dc: HDC,
1111
}
1212

1313
// Wrap this so we can have a proper number of bmiColors to write in
@@ -19,15 +19,20 @@ struct BitmapInfo {
1919
}
2020

2121
impl Win32Impl {
22-
23-
pub unsafe fn new(handle: &Win32Handle) -> Self{
22+
pub unsafe fn new<W: HasRawWindowHandle>(handle: &Win32Handle) -> Result<Self, crate::SoftBufferError<W>> {
2423
let dc = GetDC(handle.hwnd as HWND);
25-
Self{
26-
dc,
27-
window: handle.hwnd as HWND
24+
25+
if dc.is_null(){
26+
return Err(SoftBufferError::PlatformError(Some("Device Context is null".into()), None));
2827
}
29-
}
3028

29+
Ok(
30+
Self {
31+
dc,
32+
window: handle.hwnd as HWND,
33+
}
34+
)
35+
}
3136
}
3237

3338
impl GraphicsContextImpl for Win32Impl {
@@ -57,9 +62,9 @@ impl GraphicsContextImpl for Win32Impl {
5762
std::mem::transmute(buffer.as_ptr()),
5863
std::mem::transmute(&bitmap_info),
5964
winapi::um::wingdi::DIB_RGB_COLORS,
60-
winapi::um::wingdi::SRCCOPY
65+
winapi::um::wingdi::SRCCOPY,
6166
);
6267

6368
ValidateRect(self.window, std::ptr::null_mut());
6469
}
65-
}
70+
}

0 commit comments

Comments
 (0)