azul_core/
task.rs

1#[cfg(not(feature = "std"))]
2use alloc::string::{String, ToString};
3use alloc::{
4    boxed::Box,
5    collections::btree_map::BTreeMap,
6    sync::{Arc, Weak},
7    vec::Vec,
8};
9use core::{
10    ffi::c_void,
11    fmt,
12    sync::atomic::{AtomicUsize, Ordering},
13};
14#[cfg(feature = "std")]
15use std::sync::mpsc::{Receiver, Sender};
16#[cfg(feature = "std")]
17use std::sync::Mutex;
18#[cfg(feature = "std")]
19use std::thread::{self, JoinHandle};
20#[cfg(feature = "std")]
21use std::time::Duration as StdDuration;
22#[cfg(feature = "std")]
23use std::time::Instant as StdInstant;
24
25use azul_css::{AzString, CssProperty};
26use rust_fontconfig::FcFontCache;
27
28use crate::{
29    app_resources::{ImageCache, ImageMask, ImageRef},
30    callbacks::{
31        CallbackInfo, DomNodeId, FocusTarget, OptionDomNodeId, RefAny, ScrollPosition,
32        ThreadCallback, TimerCallback, TimerCallbackInfo, TimerCallbackReturn, TimerCallbackType,
33        Update, WriteBackCallback, WriteBackCallbackType,
34    },
35    gl::OptionGlContextPtr,
36    id_tree::NodeId,
37    styled_dom::{DomId, NodeHierarchyItemId},
38    ui_solver::LayoutResult,
39    window::{
40        FullWindowState, LogicalPosition, OptionLogicalPosition, RawWindowHandle,
41        WindowCreateOptions, WindowState,
42    },
43    FastBTreeSet, FastHashMap,
44};
45
46/// Should a timer terminate or not - used to remove active timers
47#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
48#[repr(C)]
49pub enum TerminateTimer {
50    /// Remove the timer from the list of active timers
51    Terminate,
52    /// Do nothing and let the timers continue to run
53    Continue,
54}
55
56static MAX_TIMER_ID: AtomicUsize = AtomicUsize::new(5);
57
58/// ID for uniquely identifying a timer
59#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
60#[repr(C)]
61pub struct TimerId {
62    pub id: usize,
63}
64
65impl TimerId {
66    /// Generates a new, unique `TimerId`.
67    pub fn unique() -> Self {
68        TimerId {
69            id: MAX_TIMER_ID.fetch_add(1, Ordering::SeqCst),
70        }
71    }
72}
73
74impl_option!(
75    TimerId,
76    OptionTimerId,
77    [Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash]
78);
79
80static MAX_THREAD_ID: AtomicUsize = AtomicUsize::new(5);
81
82/// ID for uniquely identifying a timer
83#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
84#[repr(C)]
85pub struct ThreadId {
86    id: usize,
87}
88
89impl_option!(
90    ThreadId,
91    OptionThreadId,
92    [Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash]
93);
94
95impl ThreadId {
96    /// Generates a new, unique `ThreadId`.
97    pub fn unique() -> Self {
98        ThreadId {
99            id: MAX_THREAD_ID.fetch_add(1, Ordering::SeqCst),
100        }
101    }
102}
103
104#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
105#[repr(C, u8)]
106pub enum Instant {
107    System(AzInstantPtr),
108    Tick(SystemTick),
109}
110
111#[cfg(feature = "std")]
112impl From<StdInstant> for Instant {
113    fn from(s: StdInstant) -> Instant {
114        Instant::System(s.into())
115    }
116}
117
118impl Instant {
119    /// Returns a number from 0.0 to 1.0 indicating the current
120    /// linear interpolation value between (start, end)
121    pub fn linear_interpolate(&self, mut start: Self, mut end: Self) -> f32 {
122        use core::mem;
123
124        if end < start {
125            mem::swap(&mut start, &mut end);
126        }
127
128        if *self < start {
129            return 0.0;
130        }
131        if *self > end {
132            return 1.0;
133        }
134
135        let duration_total = end.duration_since(&start);
136        let duration_current = self.duration_since(&start);
137
138        duration_current.div(&duration_total).max(0.0).min(1.0)
139    }
140
141    /// Adds a duration to the instant, does nothing in undefined cases
142    /// (i.e. trying to add a Duration::Tick to an Instant::System)
143    pub fn add_optional_duration(&self, duration: Option<&Duration>) -> Self {
144        match duration {
145            Some(d) => match (self, d) {
146                (Instant::System(i), Duration::System(d)) => {
147                    #[cfg(feature = "std")]
148                    {
149                        let s: StdInstant = i.clone().into();
150                        let d: StdDuration = d.clone().into();
151                        let new: AzInstantPtr = (s + d).into();
152                        Instant::System(new)
153                    }
154                    #[cfg(not(feature = "std"))]
155                    {
156                        unreachable!()
157                    }
158                }
159                (Instant::Tick(s), Duration::Tick(d)) => Instant::Tick(SystemTick {
160                    tick_counter: s.tick_counter + d.tick_diff,
161                }),
162                _ => {
163                    panic!(
164                        "invalid: trying to add a duration {:?} to an instant {:?}",
165                        d, self
166                    );
167                }
168            },
169            None => self.clone(),
170        }
171    }
172
173    #[cfg(feature = "std")]
174    pub fn into_std_instant(self) -> StdInstant {
175        match self {
176            Instant::System(s) => s.into(),
177            Instant::Tick(_) => unreachable!(),
178        }
179    }
180
181    /// Calculates the duration since an earlier point in time
182    ///
183    /// - Panics if the earlier Instant was created after the current Instant
184    /// - Panics if the two enums do not have the same variant (tick / std)
185    pub fn duration_since(&self, earlier: &Instant) -> Duration {
186        match (earlier, self) {
187            (Instant::System(prev), Instant::System(now)) => {
188                #[cfg(feature = "std")]
189                {
190                    let prev_instant: StdInstant = prev.clone().into();
191                    let now_instant: StdInstant = now.clone().into();
192                    Duration::System((now_instant.duration_since(prev_instant)).into())
193                }
194                #[cfg(not(feature = "std"))]
195                {
196                    unreachable!() // cannot construct a SystemTime on no_std
197                }
198            }
199            (
200                Instant::Tick(SystemTick { tick_counter: prev }),
201                Instant::Tick(SystemTick { tick_counter: now }),
202            ) => {
203                if prev > now {
204                    panic!(
205                        "illegal: subtraction 'Instant - Instant' would result in a negative \
206                         duration"
207                    )
208                } else {
209                    Duration::Tick(SystemTickDiff {
210                        tick_diff: now - prev,
211                    })
212                }
213            }
214            _ => panic!(
215                "illegal: trying to calculate a Duration from a SystemTime and a Tick instant"
216            ),
217        }
218    }
219}
220
221#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
222#[repr(C)]
223pub struct SystemTick {
224    pub tick_counter: u64,
225}
226
227impl SystemTick {
228    pub const fn new(tick_counter: u64) -> Self {
229        Self { tick_counter }
230    }
231}
232
233#[repr(C)]
234pub struct AzInstantPtr {
235    #[cfg(feature = "std")]
236    pub ptr: Box<StdInstant>,
237    #[cfg(not(feature = "std"))]
238    pub ptr: *const c_void,
239    pub clone_fn: InstantPtrCloneCallback,
240    pub destructor: InstantPtrDestructorCallback,
241    pub run_destructor: bool,
242}
243
244pub type InstantPtrCloneCallbackType = extern "C" fn(*const AzInstantPtr) -> AzInstantPtr;
245#[repr(C)]
246pub struct InstantPtrCloneCallback {
247    pub cb: InstantPtrCloneCallbackType,
248}
249impl_callback!(InstantPtrCloneCallback);
250
251pub type InstantPtrDestructorCallbackType = extern "C" fn(*mut AzInstantPtr);
252#[repr(C)]
253pub struct InstantPtrDestructorCallback {
254    pub cb: InstantPtrDestructorCallbackType,
255}
256impl_callback!(InstantPtrDestructorCallback);
257
258// ----  LIBSTD implementation for AzInstantPtr BEGIN
259#[cfg(feature = "std")]
260impl core::fmt::Debug for AzInstantPtr {
261    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
262        write!(f, "{:?}", self.get())
263    }
264}
265
266#[cfg(not(feature = "std"))]
267impl core::fmt::Debug for AzInstantPtr {
268    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
269        write!(f, "{:?}", self.ptr as usize)
270    }
271}
272
273#[cfg(feature = "std")]
274impl core::hash::Hash for AzInstantPtr {
275    fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
276        self.get().hash(state);
277    }
278}
279
280#[cfg(not(feature = "std"))]
281impl core::hash::Hash for AzInstantPtr {
282    fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
283        (self.ptr as usize).hash(state);
284    }
285}
286
287#[cfg(feature = "std")]
288impl PartialEq for AzInstantPtr {
289    fn eq(&self, other: &AzInstantPtr) -> bool {
290        self.get() == other.get()
291    }
292}
293
294#[cfg(not(feature = "std"))]
295impl PartialEq for AzInstantPtr {
296    fn eq(&self, other: &AzInstantPtr) -> bool {
297        (self.ptr as usize).eq(&(other.ptr as usize))
298    }
299}
300
301impl Eq for AzInstantPtr {}
302
303#[cfg(feature = "std")]
304impl PartialOrd for AzInstantPtr {
305    fn partial_cmp(&self, other: &Self) -> Option<::core::cmp::Ordering> {
306        Some((self.get()).cmp(&(other.get())))
307    }
308}
309
310#[cfg(not(feature = "std"))]
311impl PartialOrd for AzInstantPtr {
312    fn partial_cmp(&self, other: &Self) -> Option<::core::cmp::Ordering> {
313        Some((self.ptr as usize).cmp(&(other.ptr as usize)))
314    }
315}
316
317#[cfg(feature = "std")]
318impl Ord for AzInstantPtr {
319    fn cmp(&self, other: &Self) -> ::core::cmp::Ordering {
320        (self.get()).cmp(&(other.get()))
321    }
322}
323
324#[cfg(not(feature = "std"))]
325impl Ord for AzInstantPtr {
326    fn cmp(&self, other: &Self) -> ::core::cmp::Ordering {
327        (self.ptr as usize).cmp(&(other.ptr as usize))
328    }
329}
330
331#[cfg(feature = "std")]
332impl AzInstantPtr {
333    fn get(&self) -> StdInstant {
334        *(self.ptr).clone()
335    }
336}
337
338impl Clone for AzInstantPtr {
339    fn clone(&self) -> Self {
340        (self.clone_fn.cb)(self)
341    }
342}
343
344#[cfg(feature = "std")]
345extern "C" fn std_instant_clone(ptr: *const AzInstantPtr) -> AzInstantPtr {
346    let az_instant_ptr = unsafe { &*ptr };
347    AzInstantPtr {
348        ptr: az_instant_ptr.ptr.clone(),
349        clone_fn: az_instant_ptr.clone_fn.clone(),
350        destructor: az_instant_ptr.destructor.clone(),
351        run_destructor: true,
352    }
353}
354
355#[cfg(feature = "std")]
356impl From<StdInstant> for AzInstantPtr {
357    fn from(s: StdInstant) -> AzInstantPtr {
358        Self {
359            ptr: Box::new(s),
360            clone_fn: InstantPtrCloneCallback {
361                cb: std_instant_clone,
362            },
363            destructor: InstantPtrDestructorCallback {
364                cb: std_instant_drop,
365            },
366            run_destructor: true,
367        }
368    }
369}
370
371#[cfg(feature = "std")]
372impl From<AzInstantPtr> for StdInstant {
373    fn from(s: AzInstantPtr) -> StdInstant {
374        s.get()
375    }
376}
377
378impl Drop for AzInstantPtr {
379    fn drop(&mut self) {
380        self.run_destructor = false;
381        (self.destructor.cb)(self);
382    }
383}
384
385#[cfg(feature = "std")]
386extern "C" fn std_instant_drop(_: *mut AzInstantPtr) {}
387
388// ----  LIBSTD implementation for AzInstantPtr END
389
390#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
391#[repr(C, u8)]
392pub enum Duration {
393    System(SystemTimeDiff),
394    Tick(SystemTickDiff),
395}
396
397impl core::fmt::Display for Duration {
398    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
399        match self {
400            #[cfg(feature = "std")]
401            Duration::System(s) => {
402                let s: StdDuration = s.clone().into();
403                write!(f, "{:?}", s)
404            }
405            #[cfg(not(feature = "std"))]
406            Duration::System(s) => write!(f, "({}s, {}ns)", s.secs, s.nanos),
407            Duration::Tick(tick) => write!(f, "{} ticks", tick.tick_diff),
408        }
409    }
410}
411
412#[cfg(feature = "std")]
413impl From<StdDuration> for Duration {
414    fn from(s: StdDuration) -> Self {
415        Duration::System(s.into())
416    }
417}
418
419impl Duration {
420    pub fn max() -> Self {
421        #[cfg(feature = "std")]
422        {
423            Duration::System(StdDuration::new(core::u64::MAX, NANOS_PER_SEC - 1).into())
424        }
425        #[cfg(not(feature = "std"))]
426        {
427            Duration::Tick(SystemTickDiff {
428                tick_diff: u64::MAX,
429            })
430        }
431    }
432
433    pub fn div(&self, other: &Self) -> f32 {
434        use self::Duration::*;
435        match (self, other) {
436            (System(s), System(s2)) => s.div(s2) as f32,
437            (Tick(t), Tick(t2)) => t.div(t2) as f32,
438            _ => 0.0,
439        }
440    }
441
442    pub fn min(self, other: Self) -> Self {
443        if self.smaller_than(&other) {
444            self
445        } else {
446            other
447        }
448    }
449
450    #[allow(unused_variables)]
451    pub fn greater_than(&self, other: &Self) -> bool {
452        match (self, other) {
453            // self > other
454            (Duration::System(s), Duration::System(o)) => {
455                #[cfg(feature = "std")]
456                {
457                    let s: StdDuration = s.clone().into();
458                    let o: StdDuration = o.clone().into();
459                    s > o
460                }
461                #[cfg(not(feature = "std"))]
462                {
463                    unreachable!()
464                }
465            }
466            (Duration::Tick(s), Duration::Tick(o)) => s.tick_diff > o.tick_diff,
467            _ => {
468                panic!("illegal: trying to compare a SystemDuration with a TickDuration");
469            }
470        }
471    }
472
473    #[allow(unused_variables)]
474    pub fn smaller_than(&self, other: &Self) -> bool {
475        // self < other
476        match (self, other) {
477            // self > other
478            (Duration::System(s), Duration::System(o)) => {
479                #[cfg(feature = "std")]
480                {
481                    let s: StdDuration = s.clone().into();
482                    let o: StdDuration = o.clone().into();
483                    s < o
484                }
485                #[cfg(not(feature = "std"))]
486                {
487                    unreachable!()
488                }
489            }
490            (Duration::Tick(s), Duration::Tick(o)) => s.tick_diff < o.tick_diff,
491            _ => {
492                panic!("illegal: trying to compare a SystemDuration with a TickDuration");
493            }
494        }
495    }
496}
497
498/// Represents a difference in ticks for systems that
499/// don't support timing
500#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
501#[repr(C)]
502pub struct SystemTickDiff {
503    pub tick_diff: u64,
504}
505
506impl SystemTickDiff {
507    /// Divide duration A by duration B
508    pub fn div(&self, other: &Self) -> f64 {
509        self.tick_diff as f64 / other.tick_diff as f64
510    }
511}
512
513#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
514#[repr(C)]
515pub struct SystemTimeDiff {
516    pub secs: u64,
517    pub nanos: u32,
518}
519
520impl SystemTimeDiff {
521    /// Divide duration A by duration B
522    pub fn div(&self, other: &Self) -> f64 {
523        self.as_secs_f64() / other.as_secs_f64()
524    }
525    fn as_secs_f64(&self) -> f64 {
526        (self.secs as f64) + ((self.nanos as f64) / (NANOS_PER_SEC as f64))
527    }
528}
529
530#[cfg(feature = "std")]
531impl From<StdDuration> for SystemTimeDiff {
532    fn from(d: StdDuration) -> SystemTimeDiff {
533        SystemTimeDiff {
534            secs: d.as_secs(),
535            nanos: d.subsec_nanos(),
536        }
537    }
538}
539
540#[cfg(feature = "std")]
541impl From<SystemTimeDiff> for StdDuration {
542    fn from(d: SystemTimeDiff) -> StdDuration {
543        StdDuration::new(d.secs, d.nanos)
544    }
545}
546
547const MILLIS_PER_SEC: u64 = 1_000;
548const NANOS_PER_MILLI: u32 = 1_000_000;
549const NANOS_PER_SEC: u32 = 1_000_000_000;
550
551impl SystemTimeDiff {
552    pub const fn from_secs(secs: u64) -> Self {
553        SystemTimeDiff { secs, nanos: 0 }
554    }
555    pub const fn from_millis(millis: u64) -> Self {
556        SystemTimeDiff {
557            secs: millis / MILLIS_PER_SEC,
558            nanos: ((millis % MILLIS_PER_SEC) as u32) * NANOS_PER_MILLI,
559        }
560    }
561    pub const fn from_nanos(nanos: u64) -> Self {
562        SystemTimeDiff {
563            secs: nanos / (NANOS_PER_SEC as u64),
564            nanos: (nanos % (NANOS_PER_SEC as u64)) as u32,
565        }
566    }
567    pub const fn checked_add(self, rhs: Self) -> Option<Self> {
568        if let Some(mut secs) = self.secs.checked_add(rhs.secs) {
569            let mut nanos = self.nanos + rhs.nanos;
570            if nanos >= NANOS_PER_SEC {
571                nanos -= NANOS_PER_SEC;
572                if let Some(new_secs) = secs.checked_add(1) {
573                    secs = new_secs;
574                } else {
575                    return None;
576                }
577            }
578            Some(SystemTimeDiff { secs, nanos })
579        } else {
580            None
581        }
582    }
583
584    pub fn millis(&self) -> u64 {
585        (self.secs * MILLIS_PER_SEC) + (self.nanos / NANOS_PER_MILLI) as u64
586    }
587
588    #[cfg(feature = "std")]
589    pub fn get(&self) -> StdDuration {
590        (*self).into()
591    }
592}
593
594impl_option!(
595    Instant,
596    OptionInstant,
597    copy = false,
598    [Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash]
599);
600impl_option!(
601    Duration,
602    OptionDuration,
603    [Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash]
604);
605
606/// A `Timer` is a function that is run on every frame.
607///
608/// There are often a lot of visual Threads such as animations or fetching the
609/// next frame for a GIF or video, etc. - that need to run every frame or every X milliseconds,
610/// but they aren't heavy enough to warrant creating a thread - otherwise the framework
611/// would create too many threads, which leads to a lot of context switching and bad performance.
612///
613/// The callback of a `Timer` should be fast enough to run under 16ms,
614/// otherwise running timers will block the main UI thread.
615#[derive(Debug, Clone, PartialEq, Eq, Hash)]
616#[repr(C)]
617pub struct Timer {
618    /// Data that is internal to the timer
619    pub data: RefAny,
620    /// Optional node that the timer is attached to - timers attached to a DOM node
621    /// will be automatically stopped when the UI is recreated.
622    pub node_id: OptionDomNodeId,
623    /// Stores when the timer was created (usually acquired by `Instant::now()`)
624    pub created: Instant,
625    /// When the timer was last called (`None` only when the timer hasn't been called yet).
626    pub last_run: OptionInstant,
627    /// How many times the callback was run
628    pub run_count: usize,
629    /// If the timer shouldn't start instantly, but rather be delayed by a certain timeframe
630    pub delay: OptionDuration,
631    /// How frequently the timer should run, i.e. set this to `Some(Duration::from_millis(16))`
632    /// to run the timer every 16ms. If this value is set to `None`, (the default), the timer
633    /// will execute the timer as-fast-as-possible (i.e. at a faster framerate
634    /// than the framework itself) - which might be  performance intensive.
635    pub interval: OptionDuration,
636    /// When to stop the timer (for example, you can stop the
637    /// execution after 5s using `Some(Duration::from_secs(5))`).
638    pub timeout: OptionDuration,
639    /// Callback to be called for this timer
640    pub callback: TimerCallback,
641}
642
643impl Timer {
644    /// Create a new timer
645    pub fn new(
646        data: RefAny,
647        callback: TimerCallbackType,
648        get_system_time_fn: GetSystemTimeCallback,
649    ) -> Self {
650        Timer {
651            data,
652            node_id: None.into(),
653            created: (get_system_time_fn.cb)(),
654            run_count: 0,
655            last_run: OptionInstant::None,
656            delay: OptionDuration::None,
657            interval: OptionDuration::None,
658            timeout: OptionDuration::None,
659            callback: TimerCallback { cb: callback },
660        }
661    }
662
663    pub fn tick_millis(&self) -> u64 {
664        match self.interval.as_ref() {
665            Some(Duration::System(s)) => s.millis(),
666            Some(Duration::Tick(s)) => s.tick_diff,
667            None => 10, // ms
668        }
669    }
670
671    /// Returns true ONCE on the LAST invocation of the timer
672    /// This is useful if you want to run some animation and then
673    /// when the timer finishes (i.e. all animations finish),
674    /// rebuild the UI / DOM (so that the user does not notice any dropped frames).
675    pub fn is_about_to_finish(&self, instant_now: &Instant) -> bool {
676        let mut finish = false;
677        if let OptionDuration::Some(timeout) = self.timeout {
678            finish = instant_now
679                .duration_since(&self.created)
680                .greater_than(&timeout);
681        }
682        finish
683    }
684
685    /// Returns when the timer needs to run again
686    pub fn instant_of_next_run(&self) -> Instant {
687        let last_run = match self.last_run.as_ref() {
688            Some(s) => s,
689            None => &self.created,
690        };
691
692        last_run
693            .clone()
694            .add_optional_duration(self.delay.as_ref())
695            .add_optional_duration(self.interval.as_ref())
696    }
697
698    /// Delays the timer to not start immediately but rather
699    /// start after a certain time frame has elapsed.
700    #[inline]
701    pub fn with_delay(mut self, delay: Duration) -> Self {
702        self.delay = OptionDuration::Some(delay);
703        self
704    }
705
706    /// Converts the timer into a timer, running the function only
707    /// if the given `Duration` has elapsed since the last run
708    #[inline]
709    pub fn with_interval(mut self, interval: Duration) -> Self {
710        self.interval = OptionDuration::Some(interval);
711        self
712    }
713
714    /// Converts the timer into a countdown, by giving it a maximum duration
715    /// (counted from the creation of the Timer, not the first use).
716    #[inline]
717    pub fn with_timeout(mut self, timeout: Duration) -> Self {
718        self.timeout = OptionDuration::Some(timeout);
719        self
720    }
721
722    /// Crate-internal: Invokes the timer if the timer should run. Otherwise returns
723    /// `Update::DoNothing`
724    pub fn invoke(
725        &mut self,
726        callback_info: CallbackInfo,
727        frame_start: Instant,
728        get_system_time_fn: GetSystemTimeCallback,
729    ) -> TimerCallbackReturn {
730        let instant_now = (get_system_time_fn.cb)();
731
732        if let OptionDuration::Some(interval) = self.interval {
733            let last_run = match self.last_run.as_ref() {
734                Some(s) => s.clone(),
735                None => self.created.add_optional_duration(self.delay.as_ref()),
736            };
737
738            if instant_now
739                .duration_since(&last_run)
740                .smaller_than(&interval)
741            {
742                return TimerCallbackReturn {
743                    should_update: Update::DoNothing,
744                    should_terminate: TerminateTimer::Continue,
745                };
746            }
747        }
748
749        let run_count = self.run_count;
750        let is_about_to_finish = self.is_about_to_finish(&instant_now);
751        let mut timer_callback_info = TimerCallbackInfo {
752            callback_info,
753            node_id: self.node_id,
754            frame_start,
755            call_count: run_count,
756            is_about_to_finish,
757            _abi_ref: core::ptr::null(),
758            _abi_mut: core::ptr::null_mut(),
759        };
760        let mut res = (self.callback.cb)(&mut self.data, &mut timer_callback_info);
761
762        // Check if the timers timeout is reached
763        if is_about_to_finish {
764            res.should_terminate = TerminateTimer::Terminate;
765        }
766
767        self.last_run = OptionInstant::Some(instant_now);
768        self.run_count += 1;
769
770        res
771    }
772}
773
774/// Message that can be sent from the main thread to the Thread using the ThreadId.
775///
776/// The thread can ignore the event.
777#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
778#[repr(C, u8)]
779pub enum ThreadSendMsg {
780    /// The thread should terminate at the nearest
781    TerminateThread,
782    /// Next frame tick
783    Tick,
784    /// Custom data
785    Custom(RefAny),
786}
787
788impl_option!(
789    ThreadSendMsg,
790    OptionThreadSendMsg,
791    copy = false,
792    [Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash]
793);
794
795// Message that is received from the running thread
796#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
797#[repr(C, u8)]
798pub enum ThreadReceiveMsg {
799    WriteBack(ThreadWriteBackMsg),
800    Update(Update),
801}
802
803impl_option!(
804    ThreadReceiveMsg,
805    OptionThreadReceiveMsg,
806    copy = false,
807    [Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash]
808);
809
810#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
811#[repr(C)]
812pub struct ThreadWriteBackMsg {
813    // The data to write back into. Will be passed as the second argument to the thread
814    pub data: RefAny,
815    // The callback to call on this data.
816    pub callback: WriteBackCallback,
817}
818
819impl ThreadWriteBackMsg {
820    pub fn new(callback: WriteBackCallbackType, data: RefAny) -> Self {
821        Self {
822            data,
823            callback: WriteBackCallback { cb: callback },
824        }
825    }
826}
827
828#[derive(Debug)]
829#[repr(C)]
830pub struct ThreadSender {
831    #[cfg(feature = "std")]
832    pub ptr: Box<Arc<Mutex<ThreadSenderInner>>>,
833    #[cfg(not(feature = "std"))]
834    pub ptr: *const c_void,
835    pub run_destructor: bool,
836}
837
838impl Clone for ThreadSender {
839    fn clone(&self) -> Self {
840        Self {
841            ptr: self.ptr.clone(),
842            run_destructor: true,
843        }
844    }
845}
846
847impl Drop for ThreadSender {
848    fn drop(&mut self) {
849        self.run_destructor = false;
850    }
851}
852
853impl ThreadSender {
854    #[cfg(not(feature = "std"))]
855    pub fn new(t: ThreadSenderInner) -> Self {
856        Self {
857            ptr: core::ptr::null(),
858            run_destructor: false,
859        }
860    }
861
862    #[cfg(feature = "std")]
863    pub fn new(t: ThreadSenderInner) -> Self {
864        Self {
865            ptr: Box::new(Arc::new(Mutex::new(t))),
866            run_destructor: true,
867        }
868    }
869
870    #[cfg(not(feature = "std"))]
871    pub fn send(&mut self, msg: ThreadReceiveMsg) -> bool {
872        false
873    }
874
875    // send data from the user thread to the main thread
876    #[cfg(feature = "std")]
877    pub fn send(&mut self, msg: ThreadReceiveMsg) -> bool {
878        let ts = match self.ptr.lock().ok() {
879            Some(s) => s,
880            None => return false,
881        };
882        (ts.send_fn.cb)(ts.ptr.as_ref() as *const _ as *const c_void, msg)
883    }
884}
885
886#[derive(Debug)]
887#[repr(C)]
888pub struct ThreadReceiver {
889    #[cfg(feature = "std")]
890    pub ptr: Box<Arc<Mutex<ThreadReceiverInner>>>,
891    #[cfg(not(feature = "std"))]
892    pub ptr: *const c_void,
893    pub run_destructor: bool,
894}
895
896impl Clone for ThreadReceiver {
897    fn clone(&self) -> Self {
898        Self {
899            ptr: self.ptr.clone(),
900            run_destructor: true,
901        }
902    }
903}
904
905impl Drop for ThreadReceiver {
906    fn drop(&mut self) {
907        self.run_destructor = false;
908    }
909}
910
911impl ThreadReceiver {
912    #[cfg(not(feature = "std"))]
913    pub fn new(t: ThreadReceiverInner) -> Self {
914        Self {
915            ptr: core::ptr::null(),
916            run_destructor: false,
917        }
918    }
919
920    #[cfg(feature = "std")]
921    pub fn new(t: ThreadReceiverInner) -> Self {
922        Self {
923            ptr: Box::new(Arc::new(Mutex::new(t))),
924            run_destructor: true,
925        }
926    }
927
928    #[cfg(not(feature = "std"))]
929    pub fn recv(&mut self) -> OptionThreadSendMsg {
930        None.into()
931    }
932
933    // receive data from the main thread
934    #[cfg(feature = "std")]
935    pub fn recv(&mut self) -> OptionThreadSendMsg {
936        let ts = match self.ptr.lock().ok() {
937            Some(s) => s,
938            None => return None.into(),
939        };
940        (ts.recv_fn.cb)(ts.ptr.as_ref() as *const _ as *const c_void)
941    }
942}
943
944#[derive(Debug)]
945#[cfg_attr(not(feature = "std"), derive(PartialEq, PartialOrd, Eq, Ord))]
946#[repr(C)]
947pub struct ThreadSenderInner {
948    #[cfg(feature = "std")]
949    pub ptr: Box<Sender<ThreadReceiveMsg>>,
950    #[cfg(not(feature = "std"))]
951    pub ptr: *const c_void,
952    pub send_fn: ThreadSendCallback,
953    pub destructor: ThreadSenderDestructorCallback,
954}
955
956#[cfg(not(feature = "std"))]
957unsafe impl Send for ThreadSenderInner {}
958
959#[cfg(feature = "std")]
960impl core::hash::Hash for ThreadSenderInner {
961    fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
962        (self.ptr.as_ref() as *const _ as usize).hash(state);
963    }
964}
965
966#[cfg(feature = "std")]
967impl PartialEq for ThreadSenderInner {
968    fn eq(&self, other: &Self) -> bool {
969        (self.ptr.as_ref() as *const _ as usize) == (other.ptr.as_ref() as *const _ as usize)
970    }
971}
972
973#[cfg(feature = "std")]
974impl Eq for ThreadSenderInner {}
975
976#[cfg(feature = "std")]
977impl PartialOrd for ThreadSenderInner {
978    fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
979        Some(
980            (self.ptr.as_ref() as *const _ as usize)
981                .cmp(&(other.ptr.as_ref() as *const _ as usize)),
982        )
983    }
984}
985
986#[cfg(feature = "std")]
987impl Ord for ThreadSenderInner {
988    fn cmp(&self, other: &Self) -> core::cmp::Ordering {
989        (self.ptr.as_ref() as *const _ as usize).cmp(&(other.ptr.as_ref() as *const _ as usize))
990    }
991}
992
993impl Drop for ThreadSenderInner {
994    fn drop(&mut self) {
995        (self.destructor.cb)(self);
996    }
997}
998
999#[derive(Debug)]
1000#[cfg_attr(not(feature = "std"), derive(PartialEq, PartialOrd, Eq, Ord))]
1001#[repr(C)]
1002pub struct ThreadReceiverInner {
1003    #[cfg(feature = "std")]
1004    pub ptr: Box<Receiver<ThreadSendMsg>>,
1005    #[cfg(not(feature = "std"))]
1006    pub ptr: *const c_void,
1007    pub recv_fn: ThreadRecvCallback,
1008    pub destructor: ThreadReceiverDestructorCallback,
1009}
1010
1011#[cfg(not(feature = "std"))]
1012unsafe impl Send for ThreadReceiverInner {}
1013
1014#[cfg(feature = "std")]
1015impl core::hash::Hash for ThreadReceiverInner {
1016    fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
1017        (self.ptr.as_ref() as *const _ as usize).hash(state);
1018    }
1019}
1020
1021#[cfg(feature = "std")]
1022impl PartialEq for ThreadReceiverInner {
1023    fn eq(&self, other: &Self) -> bool {
1024        (self.ptr.as_ref() as *const _ as usize) == (other.ptr.as_ref() as *const _ as usize)
1025    }
1026}
1027
1028#[cfg(feature = "std")]
1029impl Eq for ThreadReceiverInner {}
1030
1031#[cfg(feature = "std")]
1032impl PartialOrd for ThreadReceiverInner {
1033    fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
1034        Some(
1035            (self.ptr.as_ref() as *const _ as usize)
1036                .cmp(&(other.ptr.as_ref() as *const _ as usize)),
1037        )
1038    }
1039}
1040
1041#[cfg(feature = "std")]
1042impl Ord for ThreadReceiverInner {
1043    fn cmp(&self, other: &Self) -> core::cmp::Ordering {
1044        (self.ptr.as_ref() as *const _ as usize).cmp(&(other.ptr.as_ref() as *const _ as usize))
1045    }
1046}
1047
1048impl Drop for ThreadReceiverInner {
1049    fn drop(&mut self) {
1050        (self.destructor.cb)(self);
1051    }
1052}
1053
1054/// Config that is necessary so that threading + animations can compile on no_std
1055///
1056/// See the `default` implementations in this module for an example on how to
1057/// create a thread
1058#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
1059#[repr(C)]
1060pub struct ExternalSystemCallbacks {
1061    pub create_thread_fn: CreateThreadCallback,
1062    pub get_system_time_fn: GetSystemTimeCallback,
1063}
1064
1065impl ExternalSystemCallbacks {
1066    #[cfg(not(feature = "std"))]
1067    pub fn rust_internal() -> Self {
1068        Self {
1069            create_thread_fn: CreateThreadCallback {
1070                cb: create_thread_libstd,
1071            },
1072            get_system_time_fn: GetSystemTimeCallback {
1073                cb: get_system_time_libstd,
1074            },
1075        }
1076    }
1077
1078    #[cfg(feature = "std")]
1079    pub fn rust_internal() -> Self {
1080        Self {
1081            create_thread_fn: CreateThreadCallback {
1082                cb: create_thread_libstd,
1083            },
1084            get_system_time_fn: GetSystemTimeCallback {
1085                cb: get_system_time_libstd,
1086            },
1087        }
1088    }
1089}
1090
1091/// Function that creates a new `Thread` object
1092pub type CreateThreadCallbackType = extern "C" fn(RefAny, RefAny, ThreadCallback) -> Thread;
1093#[repr(C)]
1094pub struct CreateThreadCallback {
1095    pub cb: CreateThreadCallbackType,
1096}
1097impl_callback!(CreateThreadCallback);
1098
1099/// Get the current system type, equivalent to `std::time::Instant::now()`, except it
1100/// also works on systems that don't have a clock (such as embedded timers)
1101pub type GetSystemTimeCallbackType = extern "C" fn() -> Instant;
1102#[repr(C)]
1103pub struct GetSystemTimeCallback {
1104    pub cb: GetSystemTimeCallbackType,
1105}
1106impl_callback!(GetSystemTimeCallback);
1107
1108// function called to check if the thread has finished
1109pub type CheckThreadFinishedCallbackType =
1110    extern "C" fn(/* dropcheck */ *const c_void) -> bool;
1111#[repr(C)]
1112pub struct CheckThreadFinishedCallback {
1113    pub cb: CheckThreadFinishedCallbackType,
1114}
1115impl_callback!(CheckThreadFinishedCallback);
1116
1117// function to send a message to the thread
1118pub type LibrarySendThreadMsgCallbackType =
1119    extern "C" fn(/* Sender<ThreadSendMsg> */ *const c_void, ThreadSendMsg) -> bool; // return true / false on success / failure
1120#[repr(C)]
1121pub struct LibrarySendThreadMsgCallback {
1122    pub cb: LibrarySendThreadMsgCallbackType,
1123}
1124impl_callback!(LibrarySendThreadMsgCallback);
1125
1126// function to receive a message from the thread
1127pub type LibraryReceiveThreadMsgCallbackType =
1128    extern "C" fn(/* Receiver<ThreadReceiveMsg> */ *const c_void) -> OptionThreadReceiveMsg;
1129#[repr(C)]
1130pub struct LibraryReceiveThreadMsgCallback {
1131    pub cb: LibraryReceiveThreadMsgCallbackType,
1132}
1133impl_callback!(LibraryReceiveThreadMsgCallback);
1134
1135// function that the RUNNING THREAD can call to receive messages from the main thread
1136pub type ThreadRecvCallbackType =
1137    extern "C" fn(/* receiver.ptr */ *const c_void) -> OptionThreadSendMsg;
1138#[repr(C)]
1139pub struct ThreadRecvCallback {
1140    pub cb: ThreadRecvCallbackType,
1141}
1142impl_callback!(ThreadRecvCallback);
1143
1144// function that the RUNNING THREAD can call to send messages to the main thread
1145pub type ThreadSendCallbackType =
1146    extern "C" fn(/* sender.ptr */ *const c_void, ThreadReceiveMsg) -> bool; // return false on error
1147#[repr(C)]
1148pub struct ThreadSendCallback {
1149    pub cb: ThreadSendCallbackType,
1150}
1151impl_callback!(ThreadSendCallback);
1152
1153// function called on Thread::drop()
1154pub type ThreadDestructorCallbackType = extern "C" fn(*mut ThreadInner);
1155#[repr(C)]
1156pub struct ThreadDestructorCallback {
1157    pub cb: ThreadDestructorCallbackType,
1158}
1159impl_callback!(ThreadDestructorCallback);
1160
1161// destructor of the ThreadReceiver
1162pub type ThreadReceiverDestructorCallbackType = extern "C" fn(*mut ThreadReceiverInner);
1163#[repr(C)]
1164pub struct ThreadReceiverDestructorCallback {
1165    pub cb: ThreadReceiverDestructorCallbackType,
1166}
1167impl_callback!(ThreadReceiverDestructorCallback);
1168
1169// destructor of the ThreadSender
1170pub type ThreadSenderDestructorCallbackType = extern "C" fn(*mut ThreadSenderInner);
1171#[repr(C)]
1172pub struct ThreadSenderDestructorCallback {
1173    pub cb: ThreadSenderDestructorCallbackType,
1174}
1175impl_callback!(ThreadSenderDestructorCallback);
1176
1177/// Wrapper around Thread because Thread needs to be clone-able for Python
1178#[derive(Debug)]
1179#[repr(C)]
1180pub struct Thread {
1181    #[cfg(feature = "std")]
1182    pub ptr: Box<Arc<Mutex<ThreadInner>>>,
1183    #[cfg(not(feature = "std"))]
1184    pub ptr: *const c_void,
1185    pub run_destructor: bool,
1186}
1187
1188impl Clone for Thread {
1189    fn clone(&self) -> Self {
1190        Self {
1191            ptr: self.ptr.clone(),
1192            run_destructor: true,
1193        }
1194    }
1195}
1196
1197impl Drop for Thread {
1198    fn drop(&mut self) {
1199        self.run_destructor = false;
1200    }
1201}
1202
1203impl Thread {
1204    #[cfg(feature = "std")]
1205    pub fn new(ti: ThreadInner) -> Self {
1206        Self {
1207            ptr: Box::new(Arc::new(Mutex::new(ti))),
1208            run_destructor: true,
1209        }
1210    }
1211    #[cfg(not(feature = "std"))]
1212    pub fn new(ti: ThreadInner) -> Self {
1213        Self {
1214            ptr: core::ptr::null(),
1215            run_destructor: false,
1216        }
1217    }
1218}
1219
1220#[cfg(feature = "std")]
1221impl ThreadInner {
1222    /// Returns true if the Thread has been finished, false otherwise
1223    pub(crate) fn is_finished(&self) -> bool {
1224        (self.check_thread_finished_fn.cb)(self.dropcheck.as_ref() as *const _ as *const c_void)
1225    }
1226
1227    pub(crate) fn sender_send(&mut self, msg: ThreadSendMsg) -> bool {
1228        (self.send_thread_msg_fn.cb)(self.sender.as_ref() as *const _ as *const c_void, msg)
1229    }
1230
1231    pub(crate) fn receiver_try_recv(&mut self) -> OptionThreadReceiveMsg {
1232        (self.receive_thread_msg_fn.cb)(self.receiver.as_ref() as *const _ as *const c_void)
1233    }
1234}
1235
1236#[cfg(not(feature = "std"))]
1237impl ThreadInner {
1238    /// Returns true if the Thread has been finished, false otherwise
1239    pub(crate) fn is_finished(&self) -> bool {
1240        true
1241    }
1242
1243    pub(crate) fn sender_send(&mut self, msg: ThreadSendMsg) -> bool {
1244        false
1245    }
1246
1247    pub(crate) fn receiver_try_recv(&mut self) -> OptionThreadReceiveMsg {
1248        None.into()
1249    }
1250}
1251
1252/// A `Thread` is a seperate thread that is owned by the framework.
1253///
1254/// In difference to a `Thread`, you don't have to `await()` the result of a `Thread`,
1255/// you can just hand the Thread to the framework (via `RendererResources::add_Thread`) and
1256/// the framework will automatically update the UI when the Thread is finished.
1257/// This is useful to offload actions such as loading long files, etc. to a background thread.
1258///
1259/// Azul will join the thread automatically after it is finished (joining won't block the UI).
1260#[derive(Debug)]
1261#[repr(C)]
1262pub struct ThreadInner {
1263    // Thread handle of the currently in-progress Thread
1264    #[cfg(feature = "std")]
1265    pub thread_handle: Box<Option<JoinHandle<()>>>,
1266    #[cfg(not(feature = "std"))]
1267    pub thread_handle: *const c_void,
1268
1269    #[cfg(feature = "std")]
1270    pub sender: Box<Sender<ThreadSendMsg>>,
1271    #[cfg(not(feature = "std"))]
1272    pub sender: *const c_void,
1273
1274    #[cfg(feature = "std")]
1275    pub receiver: Box<Receiver<ThreadReceiveMsg>>,
1276    #[cfg(not(feature = "std"))]
1277    pub receiver: *const c_void,
1278
1279    #[cfg(feature = "std")]
1280    pub dropcheck: Box<Weak<()>>,
1281    #[cfg(not(feature = "std"))]
1282    pub dropcheck: *const c_void,
1283
1284    pub writeback_data: RefAny,
1285    pub check_thread_finished_fn: CheckThreadFinishedCallback,
1286    pub send_thread_msg_fn: LibrarySendThreadMsgCallback,
1287    pub receive_thread_msg_fn: LibraryReceiveThreadMsgCallback,
1288    pub thread_destructor_fn: ThreadDestructorCallback,
1289}
1290
1291#[cfg(feature = "std")]
1292pub extern "C" fn get_system_time_libstd() -> Instant {
1293    StdInstant::now().into()
1294}
1295
1296#[cfg(not(feature = "std"))]
1297pub extern "C" fn get_system_time_libstd() -> Instant {
1298    Instant::Tick(SystemTick::new(0))
1299}
1300
1301#[cfg(feature = "std")]
1302pub extern "C" fn create_thread_libstd(
1303    thread_initialize_data: RefAny,
1304    writeback_data: RefAny,
1305    callback: ThreadCallback,
1306) -> Thread {
1307    let (sender_receiver, receiver_receiver) = std::sync::mpsc::channel::<ThreadReceiveMsg>();
1308    let sender_receiver = ThreadSender::new(ThreadSenderInner {
1309        ptr: Box::new(sender_receiver),
1310        send_fn: ThreadSendCallback {
1311            cb: default_send_thread_msg_fn,
1312        },
1313        destructor: ThreadSenderDestructorCallback {
1314            cb: thread_sender_drop,
1315        },
1316    });
1317
1318    let (sender_sender, receiver_sender) = std::sync::mpsc::channel::<ThreadSendMsg>();
1319    let receiver_sender = ThreadReceiver::new(ThreadReceiverInner {
1320        ptr: Box::new(receiver_sender),
1321        recv_fn: ThreadRecvCallback {
1322            cb: default_receive_thread_msg_fn,
1323        },
1324        destructor: ThreadReceiverDestructorCallback {
1325            cb: thread_receiver_drop,
1326        },
1327    });
1328
1329    let thread_check = Arc::new(());
1330    let dropcheck = Arc::downgrade(&thread_check);
1331
1332    let thread_handle = Some(thread::spawn(move || {
1333        let _ = thread_check;
1334        (callback.cb)(thread_initialize_data, sender_receiver, receiver_sender);
1335        // thread_check gets dropped here, signals that the thread has finished
1336    }));
1337
1338    let thread_handle: Box<Option<JoinHandle<()>>> = Box::new(thread_handle);
1339    let sender: Box<Sender<ThreadSendMsg>> = Box::new(sender_sender);
1340    let receiver: Box<Receiver<ThreadReceiveMsg>> = Box::new(receiver_receiver);
1341    let dropcheck: Box<Weak<()>> = Box::new(dropcheck);
1342
1343    Thread::new(ThreadInner {
1344        thread_handle,
1345        sender,
1346        receiver,
1347        writeback_data,
1348        dropcheck,
1349        thread_destructor_fn: ThreadDestructorCallback {
1350            cb: default_thread_destructor_fn,
1351        },
1352        check_thread_finished_fn: CheckThreadFinishedCallback {
1353            cb: default_check_thread_finished,
1354        },
1355        send_thread_msg_fn: LibrarySendThreadMsgCallback {
1356            cb: library_send_thread_msg_fn,
1357        },
1358        receive_thread_msg_fn: LibraryReceiveThreadMsgCallback {
1359            cb: library_receive_thread_msg_fn,
1360        },
1361    })
1362}
1363
1364impl Drop for ThreadInner {
1365    fn drop(&mut self) {
1366        (self.thread_destructor_fn.cb)(self);
1367    }
1368}
1369
1370#[cfg(not(feature = "std"))]
1371pub extern "C" fn create_thread_libstd(
1372    thread_initialize_data: RefAny,
1373    writeback_data: RefAny,
1374    callback: ThreadCallback,
1375) -> Thread {
1376    Thread {
1377        ptr: core::ptr::null(),
1378        run_destructor: false,
1379    }
1380}
1381
1382#[cfg(feature = "std")]
1383extern "C" fn default_thread_destructor_fn(thread: *mut ThreadInner) {
1384    let thread = unsafe { &mut *thread };
1385
1386    if let Some(thread_handle) = thread.thread_handle.take() {
1387        let _ = thread.sender.send(ThreadSendMsg::TerminateThread);
1388        let _ = thread_handle.join(); // ignore the result, don't panic
1389    }
1390}
1391
1392#[cfg(not(feature = "std"))]
1393extern "C" fn default_thread_destructor_fn(thread: *mut ThreadInner) {}
1394
1395#[cfg(feature = "std")]
1396extern "C" fn library_send_thread_msg_fn(sender: *const c_void, msg: ThreadSendMsg) -> bool {
1397    unsafe { &*(sender as *const Sender<ThreadSendMsg>) }
1398        .send(msg)
1399        .is_ok()
1400}
1401
1402#[cfg(not(feature = "std"))]
1403extern "C" fn library_send_thread_msg_fn(sender: *const c_void, msg: ThreadSendMsg) -> bool {
1404    false
1405}
1406
1407#[cfg(feature = "std")]
1408extern "C" fn library_receive_thread_msg_fn(receiver: *const c_void) -> OptionThreadReceiveMsg {
1409    unsafe { &*(receiver as *const Receiver<ThreadReceiveMsg>) }
1410        .try_recv()
1411        .ok()
1412        .into()
1413}
1414
1415#[cfg(not(feature = "std"))]
1416extern "C" fn library_receive_thread_msg_fn(receiver: *const c_void) -> OptionThreadReceiveMsg {
1417    None.into()
1418}
1419
1420#[cfg(feature = "std")]
1421extern "C" fn default_send_thread_msg_fn(sender: *const c_void, msg: ThreadReceiveMsg) -> bool {
1422    unsafe { &*(sender as *const Sender<ThreadReceiveMsg>) }
1423        .send(msg)
1424        .is_ok()
1425}
1426
1427#[cfg(not(feature = "std"))]
1428extern "C" fn default_send_thread_msg_fn(sender: *const c_void, msg: ThreadReceiveMsg) -> bool {
1429    false
1430}
1431
1432#[cfg(feature = "std")]
1433extern "C" fn default_receive_thread_msg_fn(receiver: *const c_void) -> OptionThreadSendMsg {
1434    unsafe { &*(receiver as *const Receiver<ThreadSendMsg>) }
1435        .try_recv()
1436        .ok()
1437        .into()
1438}
1439
1440#[cfg(not(feature = "std"))]
1441extern "C" fn default_receive_thread_msg_fn(receiver: *const c_void) -> OptionThreadSendMsg {
1442    None.into()
1443}
1444
1445#[cfg(feature = "std")]
1446extern "C" fn default_check_thread_finished(dropcheck: *const c_void) -> bool {
1447    unsafe { &*(dropcheck as *const Weak<()>) }
1448        .upgrade()
1449        .is_none()
1450}
1451
1452#[cfg(not(feature = "std"))]
1453extern "C" fn default_check_thread_finished(dropcheck: *const c_void) -> bool {
1454    true
1455}
1456
1457#[cfg(feature = "std")]
1458extern "C" fn thread_sender_drop(_: *mut ThreadSenderInner) {}
1459
1460#[cfg(not(feature = "std"))]
1461extern "C" fn thread_sender_drop(_: *mut ThreadSenderInner) {}
1462
1463#[cfg(feature = "std")]
1464extern "C" fn thread_receiver_drop(_: *mut ThreadReceiverInner) {}
1465
1466#[cfg(not(feature = "std"))]
1467extern "C" fn thread_receiver_drop(_: *mut ThreadReceiverInner) {}