use crate::{
standard_c::{CStr, NotStack},
Box, Handle, SpecialDrop,
};
use core::{
marker::PhantomData,
mem::ManuallyDrop,
ops::{Deref, DerefMut},
};
#[allow(clippy::wildcard_imports)]
use pebble_sys::{
prelude::*,
standard_c::memory::void,
user_interface::window::number_window::{NumberWindow as sysNumberWindow, *},
};
use super::{WindowRef, WindowRefMut};
pub struct NumberWindow<'a, T: ?Sized>(
pub(crate) Handle<'a, sysNumberWindow<'a>>,
PhantomData<T>,
*mut NumberWindowDataWrapper<'a>,
);
pub struct NumberWindowData<
I: FnMut(&NumberWindow<void>, &mut T),
D: FnMut(&NumberWindow<void>, &mut T),
S: FnMut(&NumberWindow<void>, &mut T),
T,
> {
pub incremented: I,
pub decremented: D,
pub selected: S,
pub context: T,
}
trait NumberWindowDataTrait {
fn incremented(&mut self, number_window: &NumberWindow<void>);
fn decremented(&mut self, number_window: &NumberWindow<void>);
fn selected(&mut self, number_window: &NumberWindow<void>);
}
impl<
I: FnMut(&NumberWindow<void>, &mut T),
D: FnMut(&NumberWindow<void>, &mut T),
S: FnMut(&NumberWindow<void>, &mut T),
T,
> NumberWindowDataTrait for NumberWindowData<I, D, S, T>
{
fn incremented(&mut self, number_window: &NumberWindow<void>) {
(self.incremented)(number_window, &mut self.context)
}
fn decremented(&mut self, number_window: &NumberWindow<void>) {
(self.decremented)(number_window, &mut self.context)
}
fn selected(&mut self, number_window: &NumberWindow<void>) {
(self.selected)(number_window, &mut self.context)
}
}
pub struct NumberWindowDataWrapper<'a>(Box<'a, dyn 'a + NumberWindowDataTrait>);
impl<'a, T> NumberWindow<'a, T> {
pub fn new<
I: 'a + FnMut(&NumberWindow<void>, &mut T),
D: 'a + FnMut(&NumberWindow<void>, &mut T),
S: 'a + FnMut(&NumberWindow<void>, &mut T),
>(
label: &'a CStr<impl NotStack>,
number_window_data: NumberWindowData<I, D, S, T>,
) -> Result<Self, NumberWindowData<I, D, S, T>>
where
T: 'a,
{
#![allow(clippy::items_after_statements)]
let window_data_wrapper = Box::leak(
Box::new(NumberWindowDataWrapper(Box::new(number_window_data)?)).map_err(
|wrapper| Box::into_inner(unsafe { Box::downcast_unchecked(wrapper.0) }),
)?,
) as *mut NumberWindowDataWrapper;
extern "C" fn raw_incremented<'a>(
raw_window: &'a mut sysNumberWindow<'a>,
context: &mut void,
) {
let context = context as *mut void; let fake_window = unsafe {
#[allow(clippy::cast_ptr_alignment)]
NumberWindow::<void>::from_raw_unsized(
raw_window,
context as *mut _ as *mut NumberWindowDataWrapper,
)
};
unsafe {
let context = &mut *context;
context
.cast_unchecked_mut::<NumberWindowDataWrapper>()
.0
.incremented(&fake_window)
}
fake_window.abandon();
}
extern "C" fn raw_decremented<'a>(
raw_window: &'a mut sysNumberWindow<'a>,
context: &mut void,
) {
let context = context as *mut void; let fake_window = unsafe {
#[allow(clippy::cast_ptr_alignment)]
NumberWindow::<void>::from_raw_unsized(
raw_window,
context as *mut _ as *mut NumberWindowDataWrapper,
)
};
unsafe {
let context = &mut *context;
context
.cast_unchecked_mut::<NumberWindowDataWrapper>()
.0
.decremented(&fake_window)
}
fake_window.abandon();
}
extern "C" fn raw_selected<'a>(
raw_window: &'a mut sysNumberWindow<'a>,
context: &mut void,
) {
let context = context as *mut void; let fake_window = unsafe {
#[allow(clippy::cast_ptr_alignment)]
NumberWindow::<void>::from_raw_unsized(
raw_window,
context as *mut _ as *mut NumberWindowDataWrapper,
)
};
unsafe {
let context = &mut *context;
context
.cast_unchecked_mut::<NumberWindowDataWrapper>()
.0
.selected(&fake_window)
}
fake_window.abandon();
}
match unsafe {
number_window_create(
label.as_c_str(),
NumberWindowCallbacks {
incremented: Some(raw_incremented),
decremented: Some(raw_decremented),
selected: Some(raw_selected),
},
&mut *(window_data_wrapper as *mut _ as *mut void),
)
} {
Some(raw_window) => Ok(Self(
Handle::new(raw_window),
PhantomData,
window_data_wrapper,
)),
None => Err(Box::into_inner(unsafe {
Box::downcast_unchecked(
Box::into_inner(Box::<NumberWindowDataWrapper>::from_raw(
&mut *window_data_wrapper,
))
.0,
)
})),
}
}
pub unsafe fn from_raw(
raw_window: &'a mut sysNumberWindow<'a>,
number_window_data_wrapper: *mut NumberWindowDataWrapper<'a>,
) -> Self {
Self(
Handle::new(raw_window),
PhantomData,
number_window_data_wrapper,
)
}
#[must_use = "Not reassembling the `NumberWindow` later causes a memory leak."]
pub fn leak(
self,
) -> (
&'a mut sysNumberWindow<'a>,
*mut NumberWindowDataWrapper<'a>,
)
where
T: 'a,
{
let undropped = ManuallyDrop::new(self);
unsafe { (undropped.0.duplicate().unwrap(), undropped.2) }
}
}
impl<'a, T: ?Sized> NumberWindow<'a, T> {
#[must_use]
pub fn window(&self) -> WindowRef<'_> {
WindowRef(Handle::new(unsafe {
number_window_get_window_mut(&mut *(self.0.as_mut_unchecked() as *mut _))
}))
}
#[must_use]
pub fn window_mut<'b: 'a>(&'b mut self) -> WindowRefMut<'b> {
WindowRefMut(Handle::new(unsafe {
number_window_get_window_mut(self.0.as_mut_unchecked())
}))
}
pub fn set_label(&self, label: &'a CStr<impl NotStack>) {
unsafe { number_window_set_label(self.0.as_mut_unchecked(), label.as_c_str()) }
}
pub fn set_max(&self, max: i32) {
unsafe { number_window_set_max(self.0.as_mut_unchecked(), max) }
}
pub fn set_min(&self, min: i32) {
unsafe { number_window_set_min(self.0.as_mut_unchecked(), min) }
}
pub fn set_value(&self, value: i32) {
unsafe { number_window_set_value(self.0.as_mut_unchecked(), value) }
}
pub fn set_step_size(&self, step_size: i32) {
unsafe { number_window_set_step_size(self.0.as_mut_unchecked(), step_size) }
}
#[must_use]
pub fn get_value(&self) -> i32 {
unsafe { number_window_get_value(&*self.0) }
}
unsafe fn from_raw_unsized(
raw_window: &'a mut sysNumberWindow<'a>,
number_window_data_wrapper: *mut NumberWindowDataWrapper<'a>,
) -> Self {
Self(
Handle::new(raw_window),
PhantomData,
number_window_data_wrapper,
)
}
fn abandon(self) {
let _ = ManuallyDrop::new(self);
}
}
impl<'a, T> Deref for NumberWindow<'a, T> {
type Target = NumberWindow<'a, void>;
fn deref(&self) -> &Self::Target {
unsafe {
&*(self as *const _ as *const Self::Target)
}
}
}
impl<'a, T> DerefMut for NumberWindow<'a, T> {
fn deref_mut(&mut self) -> &mut Self::Target {
unsafe {
&mut *(self as *mut _ as *mut Self::Target)
}
}
}
impl<'a, T: ?Sized> Drop for NumberWindow<'a, T> {
fn drop(&mut self) {
self.special_drop()
}
}
impl<'a, T: ?Sized> SpecialDrop for NumberWindow<'a, T> {
default fn special_drop(&mut self) {
panic!("Dropping unsized `NumberWindow<T>`s is illegal")
}
}
impl<'a, T: Sized> SpecialDrop for NumberWindow<'a, T> {
fn special_drop(&mut self) {
unsafe {
let data_wrapper = self.2;
let sys_number_window = self.0.duplicate().unwrap() as *mut _ as *mut void as *mut _;
number_window_destroy(&mut *sys_number_window);
Box::<NumberWindowDataWrapper>::from_raw(&mut *data_wrapper);
}
}
}