Skip to content

Commit

Permalink
feat: no vcall callbacks
Browse files Browse the repository at this point in the history
  • Loading branch information
JarvisCraft committed Jan 2, 2023
1 parent 164eb82 commit 3f4c26b
Show file tree
Hide file tree
Showing 7 changed files with 322 additions and 144 deletions.
5 changes: 1 addition & 4 deletions crates/gui/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,4 @@ test = false
[dependencies]
flipperzero-sys = { path = "../sys", version = "0.6.0-alpha" }
# FIXME: this is only required for access to `Align` enum which may be mvoved to this crate
flipperzero = { path = "../flipperzero", version = "0.6.0-alpha" }

[features]
alloc = ["flipperzero/alloc"]
flipperzero = { path = "../flipperzero", version = "0.6.0-alpha", features = ["alloc"] }
20 changes: 12 additions & 8 deletions crates/gui/src/gui.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
//! GUI APIs
use crate::canvas::Canvas;
use crate::view_port::ViewPort;
use crate::view_port::{ViewPort, ViewPortCallbacks};
use core::ffi::c_char;
use core::fmt::Debug;
use flipperzero_sys::{self as sys, furi::UnsafeRecord, Gui as SysGui, GuiLayer as SysGuiLayer};
Expand All @@ -22,7 +22,11 @@ impl Gui {
Self { gui }
}

pub fn add_view_port(&mut self, view_port: ViewPort, layer: GuiLayer) -> GuiViewPort<'_> {
pub fn add_view_port<VPC: ViewPortCallbacks>(
&mut self,
view_port: ViewPort<VPC>,
layer: GuiLayer,
) -> GuiViewPort<'_, VPC> {
// SAFETY: `self.gui` is owned by this `Gui`
let gui = unsafe { self.gui.as_raw() }.as_ptr();
// SAFETY: `view_port` should outlive this `Gui`
Expand Down Expand Up @@ -78,17 +82,17 @@ impl Default for Gui {
}

/// `ViewPort` bound to a `Gui`.
pub struct GuiViewPort<'a> {
pub struct GuiViewPort<'a, VPC: ViewPortCallbacks> {
parent: &'a Gui,
view_port: ViewPort,
view_port: ViewPort<VPC>,
}

impl<'a> GuiViewPort<'a> {
pub fn view_port(&self) -> &ViewPort {
impl<'a, VPC: ViewPortCallbacks> GuiViewPort<'a, VPC> {
pub fn view_port(&self) -> &ViewPort<VPC> {
&self.view_port
}

pub fn view_port_mut(&mut self) -> &mut ViewPort {
pub fn view_port_mut(&mut self) -> &mut ViewPort<VPC> {
&mut self.view_port
}

Expand All @@ -112,7 +116,7 @@ impl<'a> GuiViewPort<'a> {
// }
}

impl Drop for GuiViewPort<'_> {
impl<VPC: ViewPortCallbacks> Drop for GuiViewPort<'_, VPC> {
fn drop(&mut self) {
// # SAFETY: `self.parent` outlives this `GuiVewPort`
let gui = unsafe { self.parent.gui.as_raw() }.as_ptr();
Expand Down
2 changes: 1 addition & 1 deletion crates/gui/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
//! Safe wrappers for Flipper GUI APIs.
#![no_std]
#![feature(thin_box)]

#[cfg(feature = "alloc")]
extern crate alloc;

pub mod canvas;
Expand Down
108 changes: 108 additions & 0 deletions crates/gui/src/view.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
use core::ptr::{null_mut, NonNull};
use flipperzero_sys::{self as sys, View as SysView};

pub struct View {
raw: *mut SysView,
}

impl View {
/// Creates a new `View`.
///
/// # Example
///
/// Basic usage:
///
/// ```
/// use flipperzero_gui::view::View;
///
/// let view = View::new();
/// ```
pub fn new() -> View {
// SAFETY: allocation either succeeds producing the valid pointer
// or stops the system on OOM
let view = unsafe { sys::view_alloc() };
Self { raw: view }
}

/// Construct a `View` from a raw non-null pointer.
///
/// After calling this function, the raw pointer is owned by the resulting `View`.
/// Specifically, the `View` destructor will free the allocated memory.
///
/// # Safety
///
/// `raw` should be a valid pointer to [`SysView`].
///
/// # Examples
///
/// Recreate a `View`
/// which vas previously converted to a raw pointer using [`View::into_raw`].
///
/// ```
/// use flipperzero_gui::view::View;
///
/// let view = View::new();
/// let ptr = view.into_raw();
/// let view = unsafe { View::from_raw(ptr) };
/// ```
pub unsafe fn from_raw(raw: NonNull<SysView>) -> Self {
Self { raw: raw.as_ptr() }
}

/// Consumes this wrapper, returning a non-null raw pointer.
///
/// After calling this function, the caller is responsible
/// for the memory previously managed by the `View`.
/// In particular, the caller should properly destroy `SysView` and release the memory
/// such as by calling [`sys::view_free`].
/// The easiest way to do this is to convert the raw pointer
/// back into a `View` with the [View::from_raw] function,
/// allowing the `View` destructor to perform the cleanup.
///
/// # Example
///
/// Converting the raw pointer back into a `ViewPort`
/// with [`View::from_raw`] for automatic cleanup:
///
/// ```
/// use flipperzero_gui::view::View;
///
/// let view = View::new();
/// let ptr = view.into_raw();
/// let view = unsafe { View::from_raw(ptr) };
/// ```
pub fn into_raw(mut self) -> NonNull<SysView> {
let raw_pointer = core::mem::replace(&mut self.raw, null_mut());
// SAFETY: `self.raw` is guaranteed to be non-null
// since it only becomes null after call to this function
// which consumes the wrapper
unsafe { NonNull::new_unchecked(raw_pointer) }
}

/// Creates a copy of the non-null raw pointer to the [`SysView`].
///
/// # Safety
///
/// Caller must ensure that the provided pointer does not outlive this wrapper.
pub unsafe fn as_raw(&self) -> NonNull<SysView> {
// SAFETY: the pointer is guaranteed to be non-null
unsafe { NonNull::new_unchecked(self.raw) }
}
}

impl Default for View {
fn default() -> Self {
Self::new()
}
}

impl Drop for View {
fn drop(&mut self) {
// `self.raw` is `null` iff it has been taken by call to `into_raw()`
if !self.raw.is_null() {
// SAFETY: `self.raw` is always valid
// and it should have been unregistered from the system by now
unsafe { sys::view_free(self.raw) }
}
}
}
Loading

0 comments on commit 3f4c26b

Please sign in to comment.