#![cfg_attr(feature = "futures", feature(async_await))]
#![allow(unused_variables)]
#![allow(dead_code)]
#[macro_use]
extern crate lazy_static;
#[cfg(feature = "glib")]
mod glib;
#[cfg(feature = "win32")]
mod winmsg;
#[cfg(feature = "web")]
mod web;
#[cfg(not(any(feature = "win32", feature = "glib", feature = "web")))]
mod ruststd;
#[cfg(not(feature = "web"))]
mod mainloop;
#[cfg(not(feature = "web"))]
pub use crate::mainloop::MainLoop;
use std::time::Duration;
use std::thread::ThreadId;
#[derive(Debug)]
pub enum MainLoopError {
TooManyMainLoops,
NoMainLoop,
Unsupported,
DurationTooLong,
Other(Box<std::error::Error>),
}
#[derive(Clone, Debug, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct CbId(u64);
use boxfnonce::BoxFnOnce;
#[cfg(windows)]
#[derive(Copy, Clone, Debug, PartialEq, Eq, Ord, PartialOrd, Hash)]
pub struct CbHandle(pub std::os::windows::io::RawSocket);
#[cfg(unix)]
#[derive(Copy, Clone, Debug, PartialEq, Eq, Ord, PartialOrd, Hash)]
pub struct CbHandle(pub std::os::unix::io::RawFd);
#[cfg(not(any(windows, unix)))]
#[derive(Copy, Clone, Debug, PartialEq, Eq, Ord, PartialOrd, Hash)]
pub struct CbHandle(pub i32);
enum CbKind<'a> {
Asap(BoxFnOnce<'a, ()>),
After(BoxFnOnce<'a, ()>, Duration),
Interval(Box<dyn FnMut() -> bool + 'a>, Duration),
IO(Box<IOAble + 'a>),
}
impl<'a> CbKind<'a> {
pub fn asap<F: FnOnce() + 'a>(f: F) -> Self { CbKind::Asap(BoxFnOnce::from(f)) }
pub fn after<F: FnOnce() + 'a>(f: F, d: Duration) -> Self { CbKind::After(BoxFnOnce::from(f), d) }
pub fn interval<F: FnMut() -> bool + 'a>(f: F, d: Duration) -> Self { CbKind::Interval(Box::new(f), d) }
pub fn io<IO: IOAble + 'a>(io: IO) -> Self { CbKind::IO(Box::new(io)) }
pub fn duration(&self) -> Option<Duration> {
match self {
CbKind::IO(_) => None,
CbKind::Asap(_) => None,
CbKind::After(_, d) => Some(*d),
CbKind::Interval(_, d) => Some(*d),
}
}
pub fn duration_millis(&self) -> Result<Option<u32>, MainLoopError> {
if let Some(d) = self.duration() {
let m = (u32::max_value() / 1000) - 1;
let s = d.as_secs();
if s >= m as u64 { return Err(MainLoopError::DurationTooLong) }
Ok(Some((s as u32) * 1000 + d.subsec_millis()))
} else { Ok(None) }
}
pub fn handle(&self) -> Option<(CbHandle, IODirection)> {
match self {
CbKind::IO(io) => Some((io.handle(), io.direction())),
CbKind::Asap(_) => None,
CbKind::After(_, _) => None,
CbKind::Interval(_, _) => None,
}
}
pub (crate) fn call_mut(&mut self, io_dir: Option<Result<IODirection, std::io::Error>>) -> bool {
match self {
CbKind::Interval(f, _) => f(),
CbKind::IO(io) => io.on_rw(io_dir.unwrap()),
CbKind::After(_, _) => false,
CbKind::Asap(_) => false,
}
}
pub (crate) fn post_call_mut(self) {
match self {
CbKind::After(f, _) => f.call(),
CbKind::Asap(f) => f.call(),
CbKind::Interval(_, _) => {},
CbKind::IO(_) => {},
}
}
}
fn call_internal(cb: CbKind<'static>) -> Result<(), MainLoopError> {
#[cfg(not(feature = "web"))]
let r = mainloop::call_internal(cb);
#[cfg(feature = "web")]
let r = web::call_internal(cb);
r
}
pub fn call_asap<F: FnOnce() + 'static>(f: F) -> Result<(), MainLoopError> {
let cb = CbKind::asap(f);
call_internal(cb)
}
pub fn call_after<F: FnOnce() + 'static>(d: Duration, f: F) -> Result<(), MainLoopError> {
let cb = CbKind::after(f, d);
call_internal(cb)
}
pub fn call_interval<F: FnMut() -> bool + 'static>(d: Duration, f: F) -> Result<(), MainLoopError> {
let cb = CbKind::interval(f, d);
call_internal(cb)
}
#[cfg(not(feature = "web"))]
pub fn call_thread<F: FnOnce() + Send + 'static>(thread: ThreadId, f: F) -> Result<(), MainLoopError> {
mainloop::call_thread_internal(thread, boxfnonce::SendBoxFnOnce::from(f))
}
#[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd)]
pub enum IODirection {
None,
Read,
Write,
Both,
}
pub trait IOAble {
fn handle(&self) -> CbHandle;
fn direction(&self) -> IODirection;
fn on_rw(&mut self, _: Result<IODirection, std::io::Error>) -> bool;
}
pub struct IOReader<IO, F: FnMut(&mut IO, Result<IODirection, std::io::Error>)>{
pub io: IO,
pub f: F,
}
#[cfg(unix)]
impl<IO, F> IOAble for IOReader<IO, F>
where IO: std::os::unix::io::AsRawFd,
F: FnMut(&mut IO, Result<IODirection, std::io::Error>)
{
fn handle(&self) -> CbHandle { CbHandle(self.io.as_raw_fd()) }
fn direction(&self) -> IODirection { IODirection::Read }
fn on_rw(&mut self, r: Result<IODirection, std::io::Error>) -> bool {
(self.f)(&mut self.io, r);
true
}
}
#[cfg(windows)]
impl<IO, F> IOAble for IOReader<IO, F>
where IO: std::os::windows::io::AsRawSocket,
F: FnMut(&mut IO, Result<IODirection, std::io::Error>)
{
fn handle(&self) -> CbHandle { CbHandle(self.io.as_raw_socket()) }
fn direction(&self) -> IODirection { IODirection::Read }
fn on_rw(&mut self, r: Result<IODirection, std::io::Error>) -> bool {
(self.f)(&mut self.io, r);
true
}
}
pub fn call_io<IO: IOAble + 'static>(io: IO) -> Result<(), MainLoopError> {
let cb = CbKind::io(io);
call_internal(cb)
}
pub fn terminate() {
#[cfg(not(feature = "web"))]
mainloop::terminate();
}
#[cfg(feature = "futures")]
pub mod future;