use browser_window_ffi::*;
use lazy_static::lazy_static;
use std::env;
use std::ffi::{c_void, CString};
use std::future::Future;
use std::ops::Deref;
use std::os::raw::{c_int};
use std::pin::Pin;
use std::ptr;
use std::task::{Context, Poll, Waker, RawWaker, RawWakerVTable};
use super::common::*;
pub struct Application {
pub(in super) handle: ApplicationHandle
}
#[derive(Clone, Copy)]
pub struct ApplicationHandleThreaded {
pub(in super) handle: ApplicationHandle
}
unsafe impl Send for ApplicationHandleThreaded {}
unsafe impl Sync for ApplicationHandleThreaded {}
#[derive(Clone, Copy)]
pub struct ApplicationHandle {
pub(in super) ffi_handle: *mut bw_Application
}
struct ApplicationDispatchData<'a> {
handle: ApplicationHandle,
func: Box<dyn FnOnce(ApplicationHandle) + Send + 'a>
}
pub struct Runtime {
pub(in super) handle: ApplicationHandle
}
struct WakerData<'a> {
handle: ApplicationHandle,
future: Pin<Box<dyn Future<Output=()> + 'a>>
}
pub type ApplicationDelegateFuture<'a,R> = DelegateFuture<'a, ApplicationHandle, R>;
lazy_static! {
static ref WAKER_VTABLE: RawWakerVTable = {
RawWakerVTable::new(
waker_clone,
waker_wake,
waker_wake_by_ref,
waker_drop
)
};
}
impl Application {
fn args_ptr_vec() -> (Vec<CString>, Vec<*mut u8>) {
let args = env::args_os();
let mut vec = Vec::with_capacity( args.len() );
let mut vec_ptrs = Vec::with_capacity( args.len() );
for arg in args {
let string = CString::new( arg.to_string_lossy().to_string() ).expect("Unable to convert OsString into CString!");
vec_ptrs.push( string.as_ptr() as _ );
vec.push(
string
);
}
( vec, vec_ptrs )
}
pub fn initialize() -> Application {
let (args_vec, mut ptrs_vec) = Self::args_ptr_vec();
let argc: c_int = args_vec.len() as _;
let argv = ptrs_vec.as_mut_ptr();
let ffi_handle = unsafe { bw_Application_initialize( argc, argv as _ ) };
Application::from_ffi_handle( ffi_handle )
}
pub fn start( &self ) -> Runtime {
Runtime {
handle: self.handle
}
}
}
impl Drop for Application {
fn drop( &mut self ) {
unsafe { bw_Application_free( self.handle.ffi_handle ) };
}
}
impl Runtime {
unsafe fn poll_future( data: *mut WakerData ) {
debug_assert!( data != ptr::null_mut(), "WakerData pointer can't be zero!" );
#[cfg(debug_assertions)]
bw_Application_assertCorrectThread( (*data).handle.ffi_handle );
let waker = Self::new_waker( data );
let mut ctx = Context::from_waker( &waker );
let result = (*data).future.as_mut().poll( &mut ctx );
match result {
Poll::Ready(_) => {
Box::from_raw( data );
},
Poll::Pending => {}
}
}
unsafe fn new_waker( data: *mut WakerData ) -> Waker {
debug_assert!( data != ptr::null_mut(), "WakerData pointer can't be zero!" );
Waker::from_raw(
RawWaker::new( data as _, &WAKER_VTABLE )
)
}
pub fn run<H>( &self, on_ready: H ) -> i32 where
H: FnOnce( ApplicationHandle )
{
return self._run( |handle| {
on_ready( handle )
} )
}
pub fn run_async<'a,C,F>( &'a self, func: C ) -> i32 where
C: FnOnce( ApplicationHandle ) -> F + 'a,
F: Future<Output=()> + 'a
{
self._run(|handle| {
self.spawn( async move {
func( handle.into() ).await;
} );
})
}
pub fn spawn<'a,F>( &'a self, future: F ) where
F: Future<Output=()> + 'a
{
let waker_data = Box::into_raw( Box::new(
WakerData {
handle: self.handle.clone(),
future: Box::pin( future )
}
) );
unsafe { Runtime::poll_future( waker_data ) };
}
fn _run<'a,H>( &self, on_ready: H ) -> i32 where
H: FnOnce( ApplicationHandle ) + 'a
{
let ready_data = Box::into_raw( Box::new( on_ready ) );
unsafe {
let exit_code = bw_Application_run( self.handle.ffi_handle, ffi_ready_handler::<H>, ready_data as _ );
return exit_code;
}
}
}
impl Application {
pub(in super) fn from_ffi_handle( ffi_handle: *mut bw_Application ) -> Self {
Self {
handle: ApplicationHandle::new( ffi_handle )
}
}
}
impl From<ApplicationHandle> for Application {
fn from( other: ApplicationHandle ) -> Self {
Self {
handle: other
}
}
}
impl ApplicationHandle {
pub fn exit( &self, exit_code: i32 ) {
unsafe { bw_Application_exit( self.ffi_handle, exit_code as _ ); }
}
pub(in super) fn new( ffi_handle: *mut bw_Application ) -> Self {
Self {
ffi_handle: ffi_handle
}
}
pub fn spawn<F>( &self, future: F ) where
F: Future<Output=()> + 'static
{
let waker_data = Box::into_raw( Box::new(
WakerData {
handle: self.clone(),
future: Box::pin( future )
}
) );
unsafe { Runtime::poll_future( waker_data ) };
}
}
impl ApplicationHandleThreaded {
pub fn delegate<'a,F,R>( &self, func: F ) -> ApplicationDelegateFuture<'a,R> where
F: FnOnce( ApplicationHandle ) -> R + Send + 'a,
R: Send
{
ApplicationDelegateFuture::<'a,R>::new( self.handle.clone(), |handle| {
func( handle.into() )
} )
}
pub fn delegate_future<F,R>( &self, future: F ) -> DelegateFutureFuture<R> where
F: Future<Output=R> + 'static,
R: Send + 'static
{
DelegateFutureFuture::new( self.handle.clone(), future )
}
pub fn delegate_async<'a,C,F,R>( &self, func: C ) -> DelegateFutureFuture<'a,R> where
C: FnOnce( ApplicationHandle ) -> F + Send + 'a,
F: Future<Output=R>,
R: Send + 'static
{
let handle = self.handle.clone();
DelegateFutureFuture::new( self.handle.clone(),async move {
func( handle.into() ).await
})
}
pub fn dispatch<'a,F>( &self, func: F ) -> bool where
F: FnOnce( ApplicationHandle ) + Send + 'a
{
let data = Box::into_raw( Box::new( ApplicationDispatchData {
handle: self.handle,
func: Box::new( func )
} ) );
unsafe {
bw_Application_dispatch(
self.handle.ffi_handle,
ffi_dispatch_handler,
data as _
)
}
}
pub fn dispatch_async<'a,C,F>( &self, func: C ) -> bool where
C: FnOnce( ApplicationHandle ) -> F + Send + 'a,
F: Future<Output=()> + 'static
{
self.dispatch(|handle| {
let future = func( handle );
handle.spawn( future );
})
}
pub fn exit( &self, exit_code: i32 ) {
unsafe { bw_Application_exitAsync( self.handle.ffi_handle, exit_code as _ ); }
}
pub(in super) fn from_ffi_handle( ffi_handle: *mut bw_Application ) -> Self {
Self {
handle: ApplicationHandle::new( ffi_handle )
}
}
pub fn spawn<F>( &self, future: F ) where
F: Future<Output=()> + 'static
{
self.handle.spawn( future );
}
}
impl From<ApplicationHandle> for ApplicationHandleThreaded {
fn from( other: ApplicationHandle ) -> Self {
Self {
handle: other.clone()
}
}
}
impl HasAppHandle for ApplicationHandle {
fn app_handle( &self ) -> ApplicationHandle {
self.clone()
}
}
unsafe extern "C" fn ffi_dispatch_handler(_app: *mut bw_Application, _data: *mut c_void ) {
let data_ptr = _data as *mut ApplicationDispatchData<'static>;
let data = Box::from_raw( data_ptr );
(data.func)( data.handle.into() );
}
unsafe extern "C" fn ffi_ready_handler<H>( ffi_handle: *mut bw_Application, user_data: *mut c_void ) where
H: FnOnce( ApplicationHandle )
{
let app = ApplicationHandle::new( ffi_handle );
let closure = Box::from_raw( user_data as *mut H );
closure( app );
}
unsafe extern "C" fn ffi_wakeup( _ffi_handle: *mut bw_Application, user_data: *mut c_void ) {
let data = user_data as *mut WakerData;
Runtime::poll_future( data );
}
unsafe fn waker_clone( data: *const () ) -> RawWaker {
RawWaker::new( data, &WAKER_VTABLE )
}
unsafe fn waker_wake( data: *const () ) {
let data_ptr = data as *const WakerData;
bw_Application_dispatch(
(*data_ptr).handle.ffi_handle,
ffi_wakeup,
data_ptr as _
);
}
unsafe fn waker_wake_by_ref( data: *const () ) {
waker_wake( data );
}
fn waker_drop( _data: *const () ) {}