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#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
48#[repr(C)]
49pub enum TerminateTimer {
50 Terminate,
52 Continue,
54}
55
56static MAX_TIMER_ID: AtomicUsize = AtomicUsize::new(5);
57
58#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
60#[repr(C)]
61pub struct TimerId {
62 pub id: usize,
63}
64
65impl TimerId {
66 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#[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 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 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 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 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!() }
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#[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#[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 (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 match (self, other) {
477 (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#[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 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 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#[derive(Debug, Clone, PartialEq, Eq, Hash)]
616#[repr(C)]
617pub struct Timer {
618 pub data: RefAny,
620 pub node_id: OptionDomNodeId,
623 pub created: Instant,
625 pub last_run: OptionInstant,
627 pub run_count: usize,
629 pub delay: OptionDuration,
631 pub interval: OptionDuration,
636 pub timeout: OptionDuration,
639 pub callback: TimerCallback,
641}
642
643impl Timer {
644 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, }
669 }
670
671 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 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 #[inline]
701 pub fn with_delay(mut self, delay: Duration) -> Self {
702 self.delay = OptionDuration::Some(delay);
703 self
704 }
705
706 #[inline]
709 pub fn with_interval(mut self, interval: Duration) -> Self {
710 self.interval = OptionDuration::Some(interval);
711 self
712 }
713
714 #[inline]
717 pub fn with_timeout(mut self, timeout: Duration) -> Self {
718 self.timeout = OptionDuration::Some(timeout);
719 self
720 }
721
722 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 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#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
778#[repr(C, u8)]
779pub enum ThreadSendMsg {
780 TerminateThread,
782 Tick,
784 Custom(RefAny),
786}
787
788impl_option!(
789 ThreadSendMsg,
790 OptionThreadSendMsg,
791 copy = false,
792 [Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash]
793);
794
795#[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 pub data: RefAny,
815 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 #[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 #[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#[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
1091pub type CreateThreadCallbackType = extern "C" fn(RefAny, RefAny, ThreadCallback) -> Thread;
1093#[repr(C)]
1094pub struct CreateThreadCallback {
1095 pub cb: CreateThreadCallbackType,
1096}
1097impl_callback!(CreateThreadCallback);
1098
1099pub type GetSystemTimeCallbackType = extern "C" fn() -> Instant;
1102#[repr(C)]
1103pub struct GetSystemTimeCallback {
1104 pub cb: GetSystemTimeCallbackType,
1105}
1106impl_callback!(GetSystemTimeCallback);
1107
1108pub type CheckThreadFinishedCallbackType =
1110 extern "C" fn(*const c_void) -> bool;
1111#[repr(C)]
1112pub struct CheckThreadFinishedCallback {
1113 pub cb: CheckThreadFinishedCallbackType,
1114}
1115impl_callback!(CheckThreadFinishedCallback);
1116
1117pub type LibrarySendThreadMsgCallbackType =
1119 extern "C" fn(*const c_void, ThreadSendMsg) -> bool; #[repr(C)]
1121pub struct LibrarySendThreadMsgCallback {
1122 pub cb: LibrarySendThreadMsgCallbackType,
1123}
1124impl_callback!(LibrarySendThreadMsgCallback);
1125
1126pub type LibraryReceiveThreadMsgCallbackType =
1128 extern "C" fn(*const c_void) -> OptionThreadReceiveMsg;
1129#[repr(C)]
1130pub struct LibraryReceiveThreadMsgCallback {
1131 pub cb: LibraryReceiveThreadMsgCallbackType,
1132}
1133impl_callback!(LibraryReceiveThreadMsgCallback);
1134
1135pub type ThreadRecvCallbackType =
1137 extern "C" fn(*const c_void) -> OptionThreadSendMsg;
1138#[repr(C)]
1139pub struct ThreadRecvCallback {
1140 pub cb: ThreadRecvCallbackType,
1141}
1142impl_callback!(ThreadRecvCallback);
1143
1144pub type ThreadSendCallbackType =
1146 extern "C" fn(*const c_void, ThreadReceiveMsg) -> bool; #[repr(C)]
1148pub struct ThreadSendCallback {
1149 pub cb: ThreadSendCallbackType,
1150}
1151impl_callback!(ThreadSendCallback);
1152
1153pub type ThreadDestructorCallbackType = extern "C" fn(*mut ThreadInner);
1155#[repr(C)]
1156pub struct ThreadDestructorCallback {
1157 pub cb: ThreadDestructorCallbackType,
1158}
1159impl_callback!(ThreadDestructorCallback);
1160
1161pub type ThreadReceiverDestructorCallbackType = extern "C" fn(*mut ThreadReceiverInner);
1163#[repr(C)]
1164pub struct ThreadReceiverDestructorCallback {
1165 pub cb: ThreadReceiverDestructorCallbackType,
1166}
1167impl_callback!(ThreadReceiverDestructorCallback);
1168
1169pub type ThreadSenderDestructorCallbackType = extern "C" fn(*mut ThreadSenderInner);
1171#[repr(C)]
1172pub struct ThreadSenderDestructorCallback {
1173 pub cb: ThreadSenderDestructorCallbackType,
1174}
1175impl_callback!(ThreadSenderDestructorCallback);
1176
1177#[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 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 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#[derive(Debug)]
1261#[repr(C)]
1262pub struct ThreadInner {
1263 #[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 }));
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(); }
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) {}