#[cfg(not(feature = "std"))]
use alloc::string::{String, ToString};
use alloc::{
boxed::Box,
collections::btree_map::BTreeMap,
sync::{Arc, Weak},
vec::Vec,
};
use core::{
ffi::c_void,
fmt,
mem::ManuallyDrop,
sync::atomic::{AtomicUsize, Ordering},
};
#[cfg(feature = "std")]
use std::sync::mpsc::{Receiver, Sender};
#[cfg(feature = "std")]
use std::sync::Mutex;
#[cfg(feature = "std")]
use std::thread::{self, JoinHandle};
#[cfg(feature = "std")]
use std::time::Duration as StdDuration;
#[cfg(feature = "std")]
use std::time::Instant as StdInstant;
use azul_css::{props::property::CssProperty, AzString};
use rust_fontconfig::FcFontCache;
use crate::{
callbacks::{FocusTarget, TimerCallbackReturn, Update},
dom::{DomId, DomNodeId, OptionDomNodeId},
geom::{LogicalPosition, OptionLogicalPosition},
gl::OptionGlContextPtr,
hit_test::ScrollPosition,
id::NodeId,
refany::{OptionRefAny, RefAny},
resources::{ImageCache, ImageMask, ImageRef},
styled_dom::NodeHierarchyItemId,
window::RawWindowHandle,
FastBTreeSet, OrderedMap,
};
#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[repr(C)]
pub enum TerminateTimer {
Terminate,
Continue,
}
pub const CURSOR_BLINK_TIMER_ID: TimerId = TimerId { id: 0x0001 };
pub const SCROLL_MOMENTUM_TIMER_ID: TimerId = TimerId { id: 0x0002 };
pub const DRAG_AUTOSCROLL_TIMER_ID: TimerId = TimerId { id: 0x0003 };
pub const TOOLTIP_DELAY_TIMER_ID: TimerId = TimerId { id: 0x0004 };
pub const CAPABILITY_PUMP_TIMER_ID: TimerId = TimerId { id: 0x0005 };
pub const LONG_PRESS_TIMER_ID: TimerId = TimerId { id: 0x0006 };
pub const CARET_TWEEN_TIMER_ID: TimerId = TimerId { id: 0x0007 };
pub const USER_TIMER_ID_START: usize = 0x0100;
static MAX_TIMER_ID: AtomicUsize = AtomicUsize::new(USER_TIMER_ID_START);
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[repr(C)]
pub struct TimerId {
pub id: usize,
}
impl TimerId {
#[must_use]
pub fn unique() -> Self {
Self {
id: MAX_TIMER_ID.fetch_add(1, Ordering::SeqCst),
}
}
}
impl_option!(
TimerId,
OptionTimerId,
[Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash]
);
impl_vec!(
TimerId,
TimerIdVec,
TimerIdVecDestructor,
TimerIdVecDestructorType,
TimerIdVecSlice,
OptionTimerId
);
impl_vec_debug!(TimerId, TimerIdVec);
impl_vec_clone!(TimerId, TimerIdVec, TimerIdVecDestructor);
impl_vec_partialeq!(TimerId, TimerIdVec);
impl_vec_partialord!(TimerId, TimerIdVec);
const RESERVED_THREAD_ID_COUNT: usize = 5;
static MAX_THREAD_ID: AtomicUsize = AtomicUsize::new(RESERVED_THREAD_ID_COUNT);
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[repr(C)]
pub struct ThreadId {
id: usize,
}
impl_option!(
ThreadId,
OptionThreadId,
[Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash]
);
impl_vec!(
ThreadId,
ThreadIdVec,
ThreadIdVecDestructor,
ThreadIdVecDestructorType,
ThreadIdVecSlice,
OptionThreadId
);
impl_vec_debug!(ThreadId, ThreadIdVec);
impl_vec_clone!(ThreadId, ThreadIdVec, ThreadIdVecDestructor);
impl_vec_partialeq!(ThreadId, ThreadIdVec);
impl_vec_partialord!(ThreadId, ThreadIdVec);
impl ThreadId {
#[must_use]
pub fn unique() -> Self {
Self {
id: MAX_THREAD_ID.fetch_add(1, Ordering::SeqCst),
}
}
}
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[repr(C, u8)]
pub enum Instant {
System(InstantPtr),
Tick(SystemTick),
}
#[cfg(feature = "std")]
impl From<StdInstant> for Instant {
fn from(s: StdInstant) -> Self {
Self::System(s.into())
}
}
#[cfg(feature = "std")]
std::thread_local! {
static TEST_CLOCK_OFFSET_MS: core::cell::Cell<u64> = const { core::cell::Cell::new(0) };
}
#[cfg(feature = "std")]
#[must_use]
pub fn advance_test_clock_ms(ms: u64) -> u64 {
TEST_CLOCK_OFFSET_MS.with(|c| {
let next = c.get().saturating_add(ms);
c.set(next);
next
})
}
#[cfg(feature = "std")]
#[must_use]
pub fn test_clock_offset_ms() -> u64 {
TEST_CLOCK_OFFSET_MS.with(core::cell::Cell::get)
}
#[cfg(feature = "std")]
#[cfg(all(feature = "std", not(target_arch = "wasm32")))]
std::thread_local! {
static TEST_CLOCK_BASE: core::cell::Cell<Option<StdInstant>> =
const { core::cell::Cell::new(None) };
}
#[cfg(all(feature = "std", not(target_arch = "wasm32")))]
pub fn freeze_test_clock() {
TEST_CLOCK_BASE.with(|c| {
if c.get().is_none() {
c.set(Some(StdInstant::now()));
}
});
}
#[cfg(all(feature = "std", not(target_arch = "wasm32")))]
#[must_use]
pub fn test_clock_is_frozen() -> bool {
TEST_CLOCK_BASE.with(core::cell::Cell::get).is_some()
}
#[cfg(all(feature = "std", not(target_arch = "wasm32")))]
pub fn reset_test_clock() {
TEST_CLOCK_OFFSET_MS.with(|c| c.set(0));
TEST_CLOCK_BASE.with(|c| c.set(None));
}
#[cfg(feature = "std")]
static SYSTEM_TICK: core::sync::atomic::AtomicU64 = core::sync::atomic::AtomicU64::new(0);
#[cfg(feature = "std")]
pub fn advance_system_tick() {
SYSTEM_TICK.fetch_add(1, Ordering::Relaxed);
}
#[cfg(feature = "std")]
#[must_use]
pub fn system_tick_now() -> u64 {
SYSTEM_TICK.load(Ordering::Relaxed)
}
#[cfg(all(feature = "std", not(target_arch = "wasm32")))]
fn std_now_with_test_offset() -> StdInstant {
let offset = test_clock_offset_ms();
if let Some(base) = TEST_CLOCK_BASE.with(core::cell::Cell::get) {
return base + core::time::Duration::from_millis(offset);
}
if offset == 0 {
StdInstant::now()
} else {
StdInstant::now() + core::time::Duration::from_millis(offset)
}
}
impl Instant {
#[cfg(all(feature = "std", not(target_arch = "wasm32")))]
#[must_use]
pub fn now() -> Self {
std_now_with_test_offset().into()
}
#[cfg(all(feature = "std", target_arch = "wasm32"))]
#[must_use]
pub fn now() -> Self {
Instant::Tick(SystemTick::new(system_tick_now()))
}
#[cfg(not(feature = "std"))]
pub fn now() -> Self {
Instant::Tick(SystemTick::new(0))
}
#[must_use]
pub fn linear_interpolate(&self, mut start: Self, mut end: Self) -> f32 {
use core::mem;
if end < start {
mem::swap(&mut start, &mut end);
}
if *self < start {
return 0.0;
}
if *self > end {
return 1.0;
}
if start == end {
return 1.0;
}
let duration_total = end.duration_since(&start);
let duration_current = self.duration_since(&start);
let ratio = duration_current.div(&duration_total);
if ratio.is_nan() {
return 1.0;
}
ratio.clamp(0.0, 1.0)
}
#[must_use]
pub fn add_optional_duration(&self, duration: Option<&Duration>) -> Self {
duration.map_or_else(
|| self.clone(),
|d| match (self, d) {
(Self::System(i), Duration::System(d)) => {
#[cfg(feature = "std")]
{
let s: StdInstant = i.clone().into();
let d: StdDuration = (*d).into();
let new: InstantPtr = (s + d).into();
Self::System(new)
}
#[cfg(not(feature = "std"))]
{
let _ = (i, d);
self.clone()
}
}
(Self::Tick(s), Duration::Tick(d)) => Self::Tick(SystemTick {
tick_counter: s.tick_counter.saturating_add(d.tick_diff),
}),
(Self::System(_), Duration::Tick(_)) => self.add_optional_duration(Some(
&Duration::System(SystemTimeDiff::from_nanos_u128(d.as_nanos())),
)),
(Self::Tick(s), Duration::System(_)) => Self::Tick(SystemTick {
tick_counter: s.tick_counter.saturating_add(d.as_ticks()),
}),
},
)
}
#[cfg(feature = "std")]
#[must_use]
pub fn into_std_instant(self) -> StdInstant {
match self {
Self::System(s) => s.into(),
Self::Tick(_) => unreachable!(),
}
}
#[must_use]
pub fn duration_since(&self, earlier: &Self) -> Duration {
match (earlier, self) {
(Self::System(prev), Self::System(now)) => {
#[cfg(feature = "std")]
{
let prev_instant: StdInstant = prev.clone().into();
let now_instant: StdInstant = now.clone().into();
Duration::System(now_instant.saturating_duration_since(prev_instant).into())
}
#[cfg(not(feature = "std"))]
{
let _ = (prev, now);
Duration::Tick(SystemTickDiff { tick_diff: 0 })
}
}
(
Self::Tick(SystemTick { tick_counter: prev }),
Self::Tick(SystemTick { tick_counter: now }),
) => Duration::Tick(SystemTickDiff {
tick_diff: now.saturating_sub(*prev),
}),
_ => Duration::Tick(SystemTickDiff { tick_diff: 0 }),
}
}
}
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[repr(C)]
pub struct SystemTick {
pub tick_counter: u64,
}
impl SystemTick {
#[must_use]
pub const fn new(tick_counter: u64) -> Self {
Self { tick_counter }
}
}
#[repr(C)]
pub struct InstantPtr {
#[cfg(feature = "std")]
pub ptr: ManuallyDrop<Box<StdInstant>>,
#[cfg(not(feature = "std"))]
pub ptr: *const c_void,
pub clone_fn: InstantPtrCloneCallback,
pub destructor: InstantPtrDestructorCallback,
pub run_destructor: bool,
}
pub type InstantPtrCloneCallbackType = extern "C" fn(*const InstantPtr) -> InstantPtr;
#[repr(C)]
pub struct InstantPtrCloneCallback {
pub cb: InstantPtrCloneCallbackType,
}
impl_callback_simple!(InstantPtrCloneCallback);
pub type InstantPtrDestructorCallbackType = extern "C" fn(*mut InstantPtr);
#[repr(C)]
pub struct InstantPtrDestructorCallback {
pub cb: InstantPtrDestructorCallbackType,
}
impl_callback_simple!(InstantPtrDestructorCallback);
#[cfg(feature = "std")]
impl fmt::Debug for InstantPtr {
fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result {
write!(f, "{:?}", self.get())
}
}
#[cfg(not(feature = "std"))]
impl core::fmt::Debug for InstantPtr {
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
write!(f, "{:?}", self.ptr as usize)
}
}
#[cfg(feature = "std")]
impl core::hash::Hash for InstantPtr {
fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
self.get().hash(state);
}
}
#[cfg(not(feature = "std"))]
impl core::hash::Hash for InstantPtr {
fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
(self.ptr as usize).hash(state);
}
}
#[cfg(feature = "std")]
impl PartialEq for InstantPtr {
fn eq(&self, other: &Self) -> bool {
self.get() == other.get()
}
}
#[cfg(not(feature = "std"))]
impl PartialEq for InstantPtr {
fn eq(&self, other: &InstantPtr) -> bool {
(self.ptr as usize).eq(&(other.ptr as usize))
}
}
impl Eq for InstantPtr {}
#[cfg(feature = "std")]
impl PartialOrd for InstantPtr {
fn partial_cmp(&self, other: &Self) -> Option<::core::cmp::Ordering> {
Some((self.get()).cmp(&(other.get())))
}
}
#[cfg(not(feature = "std"))]
impl PartialOrd for InstantPtr {
fn partial_cmp(&self, other: &Self) -> Option<::core::cmp::Ordering> {
Some((self.ptr as usize).cmp(&(other.ptr as usize)))
}
}
#[cfg(feature = "std")]
impl Ord for InstantPtr {
fn cmp(&self, other: &Self) -> ::core::cmp::Ordering {
(self.get()).cmp(&(other.get()))
}
}
#[cfg(not(feature = "std"))]
impl Ord for InstantPtr {
fn cmp(&self, other: &Self) -> ::core::cmp::Ordering {
(self.ptr as usize).cmp(&(other.ptr as usize))
}
}
#[cfg(feature = "std")]
impl InstantPtr {
fn get(&self) -> StdInstant {
(**self.ptr)
}
}
impl Clone for InstantPtr {
fn clone(&self) -> Self {
(self.clone_fn.cb)(self)
}
}
#[cfg(feature = "std")]
extern "C" fn std_instant_clone(ptr: *const InstantPtr) -> InstantPtr {
let az_instant_ptr = unsafe { &*ptr };
InstantPtr {
ptr: ManuallyDrop::new((*az_instant_ptr.ptr).clone()),
clone_fn: az_instant_ptr.clone_fn,
destructor: az_instant_ptr.destructor,
run_destructor: true,
}
}
#[cfg(feature = "std")]
impl From<StdInstant> for InstantPtr {
fn from(s: StdInstant) -> Self {
Self {
ptr: ManuallyDrop::new(Box::new(s)),
clone_fn: InstantPtrCloneCallback {
cb: std_instant_clone,
},
destructor: InstantPtrDestructorCallback {
cb: std_instant_drop,
},
run_destructor: true,
}
}
}
#[cfg(feature = "std")]
impl From<InstantPtr> for StdInstant {
fn from(s: InstantPtr) -> Self {
s.get()
}
}
impl Drop for InstantPtr {
fn drop(&mut self) {
if self.run_destructor {
self.run_destructor = false;
(self.destructor.cb)(self);
#[cfg(feature = "std")]
unsafe {
ManuallyDrop::drop(&mut self.ptr);
}
}
}
}
#[cfg(feature = "std")]
const extern "C" fn std_instant_drop(_: *mut InstantPtr) {}
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[repr(C, u8)]
pub enum Duration {
System(SystemTimeDiff),
Tick(SystemTickDiff),
}
impl fmt::Display for Duration {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
#[cfg(feature = "std")]
Self::System(s) => {
let s: StdDuration = (*s).into();
write!(f, "{s:?}")
}
#[cfg(not(feature = "std"))]
Duration::System(s) => write!(f, "({}s, {}ns)", s.secs, s.nanos),
Self::Tick(tick) => write!(f, "{} ticks", tick.tick_diff),
}
}
}
#[cfg(feature = "std")]
impl From<StdDuration> for Duration {
fn from(s: StdDuration) -> Self {
Self::System(s.into())
}
}
pub use azul_css::props::basic::time::TICKS_PER_SECOND;
impl Duration {
#[allow(clippy::cast_lossless)]
#[must_use]
pub const fn as_nanos(&self) -> u128 {
match self {
Self::System(s) => (s.secs as u128) * (NANOS_PER_SEC as u128) + (s.nanos as u128),
Self::Tick(t) => {
(t.tick_diff as u128) * (NANOS_PER_SEC as u128) / (TICKS_PER_SECOND as u128)
}
}
}
#[must_use]
pub const fn from_millis(ms: u64) -> Self {
Self::System(SystemTimeDiff::from_millis(ms))
}
#[must_use]
pub const fn from_ticks(ticks: u64) -> Self {
Self::Tick(SystemTickDiff { tick_diff: ticks })
}
#[allow(clippy::cast_lossless, clippy::cast_possible_truncation)]
#[must_use]
pub const fn as_ticks(&self) -> u64 {
match self {
Self::Tick(t) => t.tick_diff,
Self::System(_) => {
let ticks = self.as_nanos() * (TICKS_PER_SECOND as u128) / (NANOS_PER_SEC as u128);
if ticks > u64::MAX as u128 {
u64::MAX
} else {
ticks as u64
}
}
}
}
#[allow(clippy::cast_lossless, clippy::cast_possible_truncation)]
#[must_use]
pub const fn as_millis_u64(&self) -> u64 {
let ms = self.as_nanos() / (NANOS_PER_MILLI as u128);
if ms > u64::MAX as u128 {
u64::MAX
} else {
ms as u64
}
}
#[must_use]
pub fn max() -> Self {
#[cfg(feature = "std")]
{
Self::System(StdDuration::new(core::u64::MAX, NANOS_PER_SEC - 1).into())
}
#[cfg(not(feature = "std"))]
{
Duration::Tick(SystemTickDiff {
tick_diff: u64::MAX,
})
}
}
#[allow(clippy::cast_possible_truncation, clippy::cast_precision_loss)]
#[must_use]
pub fn div(&self, other: &Self) -> f32 {
use self::Duration::{System, Tick};
match (self, other) {
(System(s), System(s2)) => s.div(s2) as f32,
(Tick(t), Tick(t2)) => t.div(t2) as f32,
_ => (self.as_nanos() as f64 / other.as_nanos() as f64) as f32,
}
}
#[must_use]
pub const fn min(self, other: Self) -> Self {
if self.smaller_than(&other) {
self
} else {
other
}
}
#[must_use]
pub const fn greater_than(&self, other: &Self) -> bool {
self.as_nanos() > other.as_nanos()
}
#[must_use]
pub const fn smaller_than(&self, other: &Self) -> bool {
self.as_nanos() < other.as_nanos()
}
}
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[repr(C)]
pub struct SystemTickDiff {
pub tick_diff: u64,
}
impl SystemTickDiff {
#[allow(clippy::cast_precision_loss)]
#[must_use]
pub fn div(&self, other: &Self) -> f64 {
self.tick_diff as f64 / other.tick_diff as f64
}
}
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[repr(C)]
pub struct SystemTimeDiff {
pub secs: u64,
pub nanos: u32,
}
impl SystemTimeDiff {
#[must_use]
pub fn div(&self, other: &Self) -> f64 {
self.as_secs_f64() / other.as_secs_f64()
}
#[allow(clippy::cast_precision_loss)]
fn as_secs_f64(&self) -> f64 {
(self.secs as f64) + (f64::from(self.nanos) / f64::from(NANOS_PER_SEC))
}
}
#[cfg(feature = "std")]
impl From<StdDuration> for SystemTimeDiff {
fn from(d: StdDuration) -> Self {
Self {
secs: d.as_secs(),
nanos: d.subsec_nanos(),
}
}
}
#[cfg(feature = "std")]
impl From<SystemTimeDiff> for StdDuration {
fn from(d: SystemTimeDiff) -> Self {
Self::new(d.secs, d.nanos)
}
}
const MILLIS_PER_SEC: u64 = 1_000;
const NANOS_PER_MILLI: u32 = 1_000_000;
const NANOS_PER_SEC: u32 = 1_000_000_000;
impl SystemTimeDiff {
#[must_use]
pub const fn from_secs(secs: u64) -> Self {
Self { secs, nanos: 0 }
}
#[must_use]
pub const fn from_millis(millis: u64) -> Self {
Self {
secs: millis / MILLIS_PER_SEC,
nanos: ((millis % MILLIS_PER_SEC) as u32) * NANOS_PER_MILLI,
}
}
#[allow(clippy::cast_possible_truncation)]
#[must_use]
pub const fn from_nanos(nanos: u64) -> Self {
Self {
secs: nanos / (NANOS_PER_SEC as u64),
nanos: (nanos % (NANOS_PER_SEC as u64)) as u32,
}
}
#[allow(clippy::cast_possible_truncation, clippy::cast_lossless)]
#[must_use]
pub const fn from_nanos_u128(nanos: u128) -> Self {
let secs = nanos / (NANOS_PER_SEC as u128);
if secs > u64::MAX as u128 {
Self {
secs: u64::MAX,
nanos: NANOS_PER_SEC - 1,
}
} else {
Self {
secs: secs as u64,
nanos: (nanos % (NANOS_PER_SEC as u128)) as u32,
}
}
}
#[must_use]
pub const fn checked_add(self, rhs: Self) -> Option<Self> {
if let Some(mut secs) = self.secs.checked_add(rhs.secs) {
let mut nanos = self.nanos + rhs.nanos;
if nanos >= NANOS_PER_SEC {
nanos -= NANOS_PER_SEC;
if let Some(new_secs) = secs.checked_add(1) {
secs = new_secs;
} else {
return None;
}
}
Some(Self { secs, nanos })
} else {
None
}
}
#[must_use]
pub const fn millis(&self) -> u64 {
self.secs
.saturating_mul(MILLIS_PER_SEC)
.saturating_add((self.nanos / NANOS_PER_MILLI) as u64)
}
#[cfg(feature = "std")]
#[must_use]
pub fn get(&self) -> StdDuration {
(*self).into()
}
}
impl From<azul_css::props::basic::time::CssDuration> for Duration {
fn from(d: azul_css::props::basic::time::CssDuration) -> Self {
use azul_css::props::basic::time::CssDurationUnit;
match d.unit {
CssDurationUnit::Milliseconds => Self::from_millis(u64::from(d.inner)),
CssDurationUnit::Ticks => Self::from_ticks(u64::from(d.inner)),
}
}
}
impl_option!(
Instant,
OptionInstant,
copy = false,
[Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash]
);
impl_option!(
Duration,
OptionDuration,
[Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash]
);
#[allow(variant_size_differences)]
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
#[repr(C, u8)]
pub enum ThreadSendMsg {
TerminateThread,
Tick,
Custom(RefAny),
}
impl_option!(
ThreadSendMsg,
OptionThreadSendMsg,
copy = false,
[Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash]
);
#[derive(Debug)]
#[repr(C)]
pub struct ThreadReceiver {
#[cfg(feature = "std")]
pub ptr: Box<Arc<Mutex<ThreadReceiverInner>>>,
#[cfg(not(feature = "std"))]
pub ptr: *const c_void,
pub run_destructor: bool,
pub ctx: OptionRefAny,
}
impl Clone for ThreadReceiver {
fn clone(&self) -> Self {
Self {
ptr: self.ptr.clone(),
run_destructor: true,
ctx: self.ctx.clone(),
}
}
}
impl Drop for ThreadReceiver {
fn drop(&mut self) {
self.run_destructor = false;
}
}
impl ThreadReceiver {
#[cfg(not(feature = "std"))]
pub fn new(_t: ThreadReceiverInner) -> Self {
Self {
ptr: core::ptr::null(),
run_destructor: false,
ctx: OptionRefAny::None,
}
}
#[cfg(feature = "std")]
#[must_use]
pub fn new(t: ThreadReceiverInner) -> Self {
Self {
ptr: Box::new(Arc::new(Mutex::new(t))),
run_destructor: true,
ctx: OptionRefAny::None,
}
}
#[must_use]
pub fn get_ctx(&self) -> OptionRefAny {
self.ctx.clone()
}
#[cfg(not(feature = "std"))]
pub fn recv(&mut self) -> OptionThreadSendMsg {
None.into()
}
#[cfg(feature = "std")]
pub fn recv(&mut self) -> OptionThreadSendMsg {
let Some(ts) = self.ptr.lock().ok() else {
return None.into();
};
(ts.recv_fn.cb)(std::ptr::from_ref(ts.ptr.as_ref()) as *const c_void)
}
}
#[derive(Debug)]
#[cfg_attr(not(feature = "std"), derive(PartialEq, PartialOrd, Eq, Ord))]
#[repr(C)]
pub struct ThreadReceiverInner {
#[cfg(feature = "std")]
pub ptr: Box<Receiver<ThreadSendMsg>>,
#[cfg(not(feature = "std"))]
pub ptr: *const c_void,
pub recv_fn: ThreadRecvCallback,
pub destructor: ThreadReceiverDestructorCallback,
}
#[cfg(not(feature = "std"))]
unsafe impl Send for ThreadReceiverInner {}
#[cfg(feature = "std")]
impl core::hash::Hash for ThreadReceiverInner {
fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
(std::ptr::from_ref(self.ptr.as_ref()) as usize).hash(state);
}
}
#[cfg(feature = "std")]
impl PartialEq for ThreadReceiverInner {
fn eq(&self, other: &Self) -> bool {
std::ptr::eq(self.ptr.as_ref(), other.ptr.as_ref())
}
}
#[cfg(feature = "std")]
impl Eq for ThreadReceiverInner {}
#[cfg(feature = "std")]
impl PartialOrd for ThreadReceiverInner {
fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
Some(
(std::ptr::from_ref(self.ptr.as_ref()) as usize)
.cmp(&(std::ptr::from_ref(other.ptr.as_ref()) as usize)),
)
}
}
#[cfg(feature = "std")]
impl Ord for ThreadReceiverInner {
fn cmp(&self, other: &Self) -> core::cmp::Ordering {
(std::ptr::from_ref(self.ptr.as_ref()) as usize)
.cmp(&(std::ptr::from_ref(other.ptr.as_ref()) as usize))
}
}
impl Drop for ThreadReceiverInner {
fn drop(&mut self) {
(self.destructor.cb)(self);
}
}
pub type GetSystemTimeCallbackType = extern "C" fn() -> Instant;
#[repr(C)]
pub struct GetSystemTimeCallback {
pub cb: GetSystemTimeCallbackType,
}
impl_callback_simple!(GetSystemTimeCallback);
#[cfg(all(feature = "std", not(target_arch = "wasm32")))]
#[must_use]
pub extern "C" fn get_system_time_libstd() -> Instant {
std_now_with_test_offset().into()
}
#[cfg(any(not(feature = "std"), target_arch = "wasm32"))]
pub extern "C" fn get_system_time_libstd() -> Instant {
Instant::Tick(SystemTick::new(0))
}
pub type CheckThreadFinishedCallbackType =
extern "C" fn( *const c_void) -> bool;
#[repr(C)]
pub struct CheckThreadFinishedCallback {
pub cb: CheckThreadFinishedCallbackType,
}
impl_callback_simple!(CheckThreadFinishedCallback);
pub type LibrarySendThreadMsgCallbackType =
extern "C" fn( *const c_void, ThreadSendMsg) -> bool;
#[repr(C)]
pub struct LibrarySendThreadMsgCallback {
pub cb: LibrarySendThreadMsgCallbackType,
}
impl_callback_simple!(LibrarySendThreadMsgCallback);
pub type ThreadRecvCallbackType =
extern "C" fn( *const c_void) -> OptionThreadSendMsg;
#[repr(C)]
pub struct ThreadRecvCallback {
pub cb: ThreadRecvCallbackType,
}
impl_callback_simple!(ThreadRecvCallback);
pub type ThreadReceiverDestructorCallbackType = extern "C" fn(*mut ThreadReceiverInner);
#[repr(C)]
pub struct ThreadReceiverDestructorCallback {
pub cb: ThreadReceiverDestructorCallbackType,
}
impl_callback_simple!(ThreadReceiverDestructorCallback);
#[cfg(test)]
#[path = "task_test.rs"]
mod task_test;