1#[cfg(feature = "std")]
7use alloc::sync::Arc;
8#[cfg(feature = "std")]
9use std::sync::{
10 mpsc::{channel, Receiver, Sender},
11 Mutex,
12};
13#[cfg(feature = "std")]
14use std::thread::{self, JoinHandle};
15
16use azul_core::{
17 callbacks::Update,
18 refany::{OptionRefAny, RefAny},
19 task::{
20 CheckThreadFinishedCallback, CheckThreadFinishedCallbackType, LibrarySendThreadMsgCallback,
21 LibrarySendThreadMsgCallbackType, OptionThreadSendMsg, ThreadId, ThreadReceiver,
22 ThreadReceiverDestructorCallback, ThreadReceiverInner, ThreadRecvCallback, ThreadSendMsg,
23 },
24};
25
26use crate::callbacks::CallbackInfo;
27
28macro_rules! impl_callback_traits {
29 ($name:ident) => {
30 impl core::fmt::Debug for $name {
31 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
32 write!(f, concat!(stringify!($name), " {{ cb: {:p} }}"), self.cb as *const ())
33 }
34 }
35 #[allow(clippy::expl_impl_clone_on_copy, clippy::non_canonical_clone_impl)]
38 impl Clone for $name {
39 fn clone(&self) -> Self { Self { cb: self.cb } }
40 }
41 impl PartialEq for $name {
42 fn eq(&self, other: &Self) -> bool {
43 self.cb as *const () as usize == other.cb as *const () as usize
44 }
45 }
46 impl Eq for $name {}
47 impl PartialOrd for $name {
48 fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
49 Some(self.cmp(other))
50 }
51 }
52 impl Ord for $name {
53 fn cmp(&self, other: &Self) -> core::cmp::Ordering {
54 (self.cb as *const () as usize).cmp(&(other.cb as *const () as usize))
55 }
56 }
57 impl core::hash::Hash for $name {
58 fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
59 (self.cb as *const () as usize).hash(state);
60 }
61 }
62 };
63}
64
65#[allow(variant_size_differences)] #[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
69#[repr(C, u8)]
70pub enum ThreadReceiveMsg {
71 WriteBack(ThreadWriteBackMsg),
72 Update(Update),
73}
74#[allow(variant_size_differences)] #[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
76#[repr(C, u8)]
77pub enum OptionThreadReceiveMsg {
78 None,
79 Some(ThreadReceiveMsg),
80}
81
82impl From<Option<ThreadReceiveMsg>> for OptionThreadReceiveMsg {
83 fn from(inner: Option<ThreadReceiveMsg>) -> Self {
84 inner.map_or_else(|| Self::None, Self::Some)
85 }
86}
87
88impl OptionThreadReceiveMsg {
89 #[must_use] pub fn into_option(self) -> Option<ThreadReceiveMsg> {
90 match self {
91 Self::None => None,
92 Self::Some(v) => Some(v),
93 }
94 }
95
96 #[must_use] pub const fn as_ref(&self) -> Option<&ThreadReceiveMsg> {
97 match self {
98 Self::None => None,
99 Self::Some(v) => Some(v),
100 }
101 }
102}
103
104#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
106#[repr(C)]
107pub struct ThreadWriteBackMsg {
108 pub refany: RefAny,
109 pub callback: WriteBackCallback,
110}
111
112impl ThreadWriteBackMsg {
113 pub fn new<C: Into<WriteBackCallback>>(callback: C, data: RefAny) -> Self {
114 Self {
115 refany: data,
116 callback: callback.into(),
117 }
118 }
119}
120
121#[derive(Debug)]
123#[repr(C)]
124pub struct ThreadSender {
125 #[cfg(feature = "std")]
126 pub ptr: Box<Arc<Mutex<ThreadSenderInner>>>,
127 #[cfg(not(feature = "std"))]
128 pub ptr: *const core::ffi::c_void,
129 pub run_destructor: bool,
130 pub ctx: OptionRefAny,
132}
133
134impl Clone for ThreadSender {
135 fn clone(&self) -> Self {
136 Self {
137 ptr: self.ptr.clone(),
138 run_destructor: true,
139 ctx: self.ctx.clone(),
140 }
141 }
142}
143
144impl Drop for ThreadSender {
145 fn drop(&mut self) {
146 self.run_destructor = false;
147 }
148}
149
150impl ThreadSender {
151 #[cfg(not(feature = "std"))]
152 pub fn new(_t: ThreadSenderInner) -> Self {
153 Self {
154 ptr: core::ptr::null(),
155 run_destructor: false,
156 ctx: OptionRefAny::None,
157 }
158 }
159
160 #[cfg(feature = "std")]
161 #[must_use] pub fn new(t: ThreadSenderInner) -> Self {
162 Self {
163 ptr: Box::new(Arc::new(Mutex::new(t))),
164 run_destructor: true,
165 ctx: OptionRefAny::None,
166 }
167 }
168
169 #[must_use] pub fn get_ctx(&self) -> OptionRefAny {
171 self.ctx.clone()
172 }
173
174 #[cfg(not(feature = "std"))]
175 pub fn send(&mut self, _msg: ThreadReceiveMsg) -> bool {
176 false
177 }
178
179 #[cfg(feature = "std")]
180 pub fn send(&mut self, msg: ThreadReceiveMsg) -> bool {
181 let Some(ts) = self.ptr.lock().ok() else {
182 return false;
183 };
184 (ts.send_fn.cb)(std::ptr::from_ref(ts.ptr.as_ref()).cast::<core::ffi::c_void>(), msg)
185 }
186}
187
188#[derive(Debug)]
190#[cfg_attr(not(feature = "std"), derive(PartialEq, PartialOrd, Eq, Ord))]
191#[repr(C)]
192pub struct ThreadSenderInner {
193 #[cfg(feature = "std")]
194 pub ptr: Box<Sender<ThreadReceiveMsg>>,
195 #[cfg(not(feature = "std"))]
196 pub ptr: *const core::ffi::c_void,
197 pub send_fn: ThreadSendCallback,
198 pub destructor: ThreadSenderDestructorCallback,
199}
200
201#[cfg(not(feature = "std"))]
202unsafe impl Send for ThreadSenderInner {}
203
204#[cfg(feature = "std")]
205impl core::hash::Hash for ThreadSenderInner {
206 fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
207 (std::ptr::from_ref(self.ptr.as_ref()) as usize).hash(state);
208 }
209}
210
211#[cfg(feature = "std")]
212impl PartialEq for ThreadSenderInner {
213 fn eq(&self, other: &Self) -> bool {
214 std::ptr::eq(self.ptr.as_ref(), other.ptr.as_ref())
215 }
216}
217
218#[cfg(feature = "std")]
219impl Eq for ThreadSenderInner {}
220
221#[cfg(feature = "std")]
222impl PartialOrd for ThreadSenderInner {
223 fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
224 Some(
225 (std::ptr::from_ref(self.ptr.as_ref()) as usize)
226 .cmp(&(std::ptr::from_ref(other.ptr.as_ref()) as usize)),
227 )
228 }
229}
230
231#[cfg(feature = "std")]
232impl Ord for ThreadSenderInner {
233 fn cmp(&self, other: &Self) -> core::cmp::Ordering {
234 (std::ptr::from_ref(self.ptr.as_ref()) as usize).cmp(&(std::ptr::from_ref(other.ptr.as_ref()) as usize))
235 }
236}
237
238impl Drop for ThreadSenderInner {
239 fn drop(&mut self) {
240 (self.destructor.cb)(self);
241 }
242}
243
244pub type ThreadSendCallbackType = extern "C" fn(*const core::ffi::c_void, ThreadReceiveMsg) -> bool;
246
247#[allow(missing_copy_implementations)] #[repr(C)]
249pub struct ThreadSendCallback {
250 pub cb: ThreadSendCallbackType,
251}
252
253impl_callback_traits!(ThreadSendCallback);
254
255pub type ThreadSenderDestructorCallbackType = extern "C" fn(*mut ThreadSenderInner);
257
258#[allow(missing_copy_implementations)] #[repr(C)]
260pub struct ThreadSenderDestructorCallback {
261 pub cb: ThreadSenderDestructorCallbackType,
262}
263
264impl_callback_traits!(ThreadSenderDestructorCallback);
265
266pub type WriteBackCallbackType = extern "C" fn(
273 RefAny,
274 RefAny,
275 CallbackInfo,
276) -> Update;
277
278#[repr(C)]
280pub struct WriteBackCallback {
281 pub cb: WriteBackCallbackType,
282 pub ctx: OptionRefAny,
285}
286
287impl WriteBackCallback {
288 pub fn new(cb: WriteBackCallbackType) -> Self {
290 Self {
291 cb,
292 ctx: OptionRefAny::None,
293 }
294 }
295
296 #[must_use] pub fn invoke(
298 &self,
299 thread_data: RefAny,
300 writeback_data: RefAny,
301 callback_info: CallbackInfo,
302 ) -> Update {
303 (self.cb)(thread_data, writeback_data, callback_info)
304 }
305}
306
307impl core::fmt::Debug for WriteBackCallback {
308 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
309 write!(f, "WriteBackCallback {{ cb: {:p} }}", self.cb as *const ())
310 }
311}
312
313impl Clone for WriteBackCallback {
314 fn clone(&self) -> Self {
315 Self {
316 cb: self.cb,
317 ctx: self.ctx.clone(),
318 }
319 }
320}
321
322impl From<WriteBackCallbackType> for WriteBackCallback {
323 fn from(cb: WriteBackCallbackType) -> Self {
324 Self {
325 cb,
326 ctx: OptionRefAny::None,
327 }
328 }
329}
330
331impl PartialEq for WriteBackCallback {
332 fn eq(&self, other: &Self) -> bool {
333 std::ptr::eq(self.cb as *const (), other.cb as *const ())
334 }
335}
336
337impl Eq for WriteBackCallback {}
338
339impl PartialOrd for WriteBackCallback {
340 fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
341 Some(self.cmp(other))
342 }
343}
344
345impl Ord for WriteBackCallback {
346 fn cmp(&self, other: &Self) -> core::cmp::Ordering {
347 (self.cb as *const () as usize).cmp(&(other.cb as *const () as usize))
348 }
349}
350
351impl core::hash::Hash for WriteBackCallback {
352 fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
353 (self.cb as *const () as usize).hash(state);
354 }
355}
356
357pub type ThreadCallbackType = extern "C" fn(RefAny, ThreadSender, ThreadReceiver);
359
360#[repr(C)]
361pub struct ThreadCallback {
362 pub cb: ThreadCallbackType,
363 pub ctx: OptionRefAny,
366}
367
368impl ThreadCallback {
369 pub fn new(cb: ThreadCallbackType) -> Self {
371 Self {
372 cb,
373 ctx: OptionRefAny::None,
374 }
375 }
376}
377
378impl core::fmt::Debug for ThreadCallback {
379 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
380 write!(f, "ThreadCallback {{ cb: {:p} }}", self.cb as *const ())
381 }
382}
383
384impl Clone for ThreadCallback {
385 fn clone(&self) -> Self {
386 Self {
387 cb: self.cb,
388 ctx: self.ctx.clone(),
389 }
390 }
391}
392
393impl From<ThreadCallbackType> for ThreadCallback {
394 fn from(cb: ThreadCallbackType) -> Self {
395 Self {
396 cb,
397 ctx: OptionRefAny::None,
398 }
399 }
400}
401
402impl PartialEq for ThreadCallback {
403 fn eq(&self, other: &Self) -> bool {
404 std::ptr::eq(self.cb as *const (), other.cb as *const ())
405 }
406}
407
408impl Eq for ThreadCallback {}
409
410impl PartialOrd for ThreadCallback {
411 fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
412 Some(self.cmp(other))
413 }
414}
415
416impl Ord for ThreadCallback {
417 fn cmp(&self, other: &Self) -> core::cmp::Ordering {
418 (self.cb as *const () as usize).cmp(&(other.cb as *const () as usize))
419 }
420}
421
422impl core::hash::Hash for ThreadCallback {
423 fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
424 (self.cb as *const () as usize).hash(state);
425 }
426}
427
428azul_core::impl_managed_callback! {
444 wrapper: ThreadCallback,
445 info_ty: ThreadSender,
446 return_ty: (),
447 default_ret: Default::default(),
450 invoker_static: THREAD_CALLBACK_INVOKER,
451 invoker_ty: AzThreadCallbackInvoker,
452 thunk_fn: az_thread_callback_thunk,
453 setter_fn: AzApp_setThreadCallbackInvoker,
454 from_handle_fn: AzThreadCallback_createFromHostHandle,
455 extra_args: [receiver: ThreadReceiver],
456}
457
458pub type LibraryReceiveThreadMsgCallbackType =
460 extern "C" fn(*const core::ffi::c_void) -> OptionThreadReceiveMsg;
461
462#[allow(missing_copy_implementations)] #[repr(C)]
464pub struct LibraryReceiveThreadMsgCallback {
465 pub cb: LibraryReceiveThreadMsgCallbackType,
466}
467
468impl_callback_traits!(LibraryReceiveThreadMsgCallback);
469
470pub type ThreadDestructorCallbackType = extern "C" fn(*mut ThreadInner);
472
473#[allow(missing_copy_implementations)] #[repr(C)]
475pub struct ThreadDestructorCallback {
476 pub cb: ThreadDestructorCallbackType,
477}
478
479impl_callback_traits!(ThreadDestructorCallback);
480
481#[derive(Debug)]
483#[repr(C)]
484pub struct Thread {
485 #[cfg(feature = "std")]
486 pub ptr: Box<Arc<Mutex<ThreadInner>>>,
487 #[cfg(not(feature = "std"))]
488 pub ptr: *const core::ffi::c_void,
489 pub run_destructor: bool,
490}
491
492impl Clone for Thread {
493 fn clone(&self) -> Self {
494 Self {
495 ptr: self.ptr.clone(),
496 run_destructor: true,
497 }
498 }
499}
500
501impl Drop for Thread {
502 fn drop(&mut self) {
503 self.run_destructor = false;
504 }
505}
506
507impl Thread {
508 #[cfg(feature = "std")]
509 #[must_use] pub fn new(ti: ThreadInner) -> Self {
510 Self {
511 ptr: Box::new(Arc::new(Mutex::new(ti))),
512 run_destructor: true,
513 }
514 }
515
516 #[cfg(not(feature = "std"))]
517 pub fn new(_ti: ThreadInner) -> Self {
518 Self {
519 ptr: core::ptr::null(),
520 run_destructor: false,
521 }
522 }
523
524 pub fn create<C: Into<ThreadCallback>>(
534 thread_initialize_data: RefAny,
535 writeback_data: RefAny,
536 callback: C,
537 ) -> Self {
538 create_thread_libstd(thread_initialize_data, writeback_data, callback.into())
539 }
540
541 #[cfg(feature = "std")]
547 #[must_use] pub fn send_message(&self, msg: ThreadSendMsg) -> bool {
548 self.ptr.lock().is_ok_and(|inner| inner.sender.send(msg).is_ok())
549 }
550 #[cfg(not(feature = "std"))]
551 pub fn send_message(&self, _msg: ThreadSendMsg) -> bool {
552 false
553 }
554
555 #[cfg(feature = "std")]
560 #[must_use] pub fn clone_sender(&self) -> Option<Sender<ThreadSendMsg>> {
561 self.ptr.lock().ok().map(|inner| (*inner.sender).clone())
562 }
563 #[cfg(not(feature = "std"))]
564 pub fn clone_sender(&self) -> Option<Sender<ThreadSendMsg>> {
565 None
566 }
567}
568
569#[derive(Debug)]
575#[repr(C)]
576pub struct ThreadInner {
577 #[cfg(feature = "std")]
578 pub thread_handle: Box<Option<JoinHandle<()>>>,
579 #[cfg(not(feature = "std"))]
580 pub thread_handle: *const core::ffi::c_void,
581
582 #[cfg(feature = "std")]
583 pub sender: Box<Sender<ThreadSendMsg>>,
584 #[cfg(not(feature = "std"))]
585 pub sender: *const core::ffi::c_void,
586
587 #[cfg(feature = "std")]
588 pub receiver: Box<Receiver<ThreadReceiveMsg>>,
589 #[cfg(not(feature = "std"))]
590 pub receiver: *const core::ffi::c_void,
591
592 #[cfg(feature = "std")]
593 pub dropcheck: Box<alloc::sync::Weak<()>>,
594 #[cfg(not(feature = "std"))]
595 pub dropcheck: *const core::ffi::c_void,
596
597 pub writeback_data: RefAny,
598 pub check_thread_finished_fn: CheckThreadFinishedCallback,
599 pub send_thread_msg_fn: LibrarySendThreadMsgCallback,
600 pub receive_thread_msg_fn: LibraryReceiveThreadMsgCallback,
601 pub thread_destructor_fn: ThreadDestructorCallback,
602}
603
604#[cfg(feature = "std")]
605impl ThreadInner {
606 #[must_use] pub fn is_finished(&self) -> bool {
608 (self.check_thread_finished_fn.cb)(
609 std::ptr::from_ref(self.dropcheck.as_ref()).cast::<core::ffi::c_void>()
610 )
611 }
612
613 pub fn sender_send(&mut self, msg: ThreadSendMsg) -> bool {
615 (self.send_thread_msg_fn.cb)(
616 std::ptr::from_ref(self.sender.as_ref()).cast::<core::ffi::c_void>(),
617 msg,
618 )
619 }
620
621 pub fn receiver_try_recv(&mut self) -> OptionThreadReceiveMsg {
623 (self.receive_thread_msg_fn.cb)(
624 std::ptr::from_ref(self.receiver.as_ref()).cast::<core::ffi::c_void>()
625 )
626 }
627}
628
629#[cfg(not(feature = "std"))]
630impl ThreadInner {
631 pub fn is_finished(&self) -> bool {
633 true
634 }
635
636 pub fn sender_send(&mut self, _msg: ThreadSendMsg) -> bool {
638 false
639 }
640
641 pub fn receiver_try_recv(&mut self) -> OptionThreadReceiveMsg {
643 None.into()
644 }
645}
646
647impl Drop for ThreadInner {
648 fn drop(&mut self) {
649 (self.thread_destructor_fn.cb)(self);
650 }
651}
652
653#[cfg(feature = "std")]
655extern "C" fn default_thread_destructor_fn(thread: *mut ThreadInner) {
656 let thread = unsafe { &mut *thread };
657
658 if let Some(thread_handle) = thread.thread_handle.take() {
659 drop(thread.sender.send(ThreadSendMsg::TerminateThread));
660 drop(thread_handle.join()); }
662}
663
664#[cfg(not(feature = "std"))]
665extern "C" fn default_thread_destructor_fn(_thread: *mut ThreadInner) {}
666
667#[cfg(feature = "std")]
668extern "C" fn library_send_thread_msg_fn(
669 sender: *const core::ffi::c_void,
670 msg: ThreadSendMsg,
671) -> bool {
672 unsafe { &*sender.cast::<Sender<ThreadSendMsg>>() }
673 .send(msg)
674 .is_ok()
675}
676
677#[cfg(not(feature = "std"))]
678extern "C" fn library_send_thread_msg_fn(
679 _sender: *const core::ffi::c_void,
680 _msg: ThreadSendMsg,
681) -> bool {
682 false
683}
684
685#[cfg(feature = "std")]
686extern "C" fn library_receive_thread_msg_fn(
687 receiver: *const core::ffi::c_void,
688) -> OptionThreadReceiveMsg {
689 unsafe { &*receiver.cast::<Receiver<ThreadReceiveMsg>>() }
690 .try_recv()
691 .ok()
692 .into()
693}
694
695#[cfg(not(feature = "std"))]
696extern "C" fn library_receive_thread_msg_fn(
697 _receiver: *const core::ffi::c_void,
698) -> OptionThreadReceiveMsg {
699 None.into()
700}
701
702#[cfg(feature = "std")]
703extern "C" fn default_send_thread_msg_fn(
704 sender: *const core::ffi::c_void,
705 msg: ThreadReceiveMsg,
706) -> bool {
707 unsafe { &*sender.cast::<Sender<ThreadReceiveMsg>>() }
708 .send(msg)
709 .is_ok()
710}
711
712#[cfg(not(feature = "std"))]
713extern "C" fn default_send_thread_msg_fn(
714 _sender: *const core::ffi::c_void,
715 _msg: ThreadReceiveMsg,
716) -> bool {
717 false
718}
719
720#[cfg(feature = "std")]
721extern "C" fn default_receive_thread_msg_fn(
722 receiver: *const core::ffi::c_void,
723) -> OptionThreadSendMsg {
724 unsafe { &*receiver.cast::<Receiver<ThreadSendMsg>>() }
725 .try_recv()
726 .ok()
727 .into()
728}
729
730#[cfg(not(feature = "std"))]
731extern "C" fn default_receive_thread_msg_fn(
732 _receiver: *const core::ffi::c_void,
733) -> OptionThreadSendMsg {
734 None.into()
735}
736
737#[cfg(feature = "std")]
738extern "C" fn default_check_thread_finished(dropcheck: *const core::ffi::c_void) -> bool {
739 let weak = unsafe { &*dropcheck.cast::<alloc::sync::Weak<()>>() };
740 weak.upgrade().is_none()
741}
742
743#[cfg(not(feature = "std"))]
744extern "C" fn default_check_thread_finished(_dropcheck: *const core::ffi::c_void) -> bool {
745 true
746}
747
748#[cfg(feature = "std")]
749const extern "C" fn thread_sender_drop(_: *mut ThreadSenderInner) {}
750
751#[cfg(not(feature = "std"))]
752extern "C" fn thread_sender_drop(_: *mut ThreadSenderInner) {}
753
754#[cfg(feature = "std")]
755const extern "C" fn thread_receiver_drop(_: *mut ThreadReceiverInner) {}
756
757#[cfg(not(feature = "std"))]
758extern "C" fn thread_receiver_drop(_: *mut ThreadReceiverInner) {}
759
760pub type CreateThreadCallbackType = extern "C" fn(RefAny, RefAny, ThreadCallback) -> Thread;
762
763#[repr(C)]
764pub struct CreateThreadCallback {
765 pub cb: CreateThreadCallbackType,
766}
767
768impl_callback_traits!(CreateThreadCallback);
769impl Copy for CreateThreadCallback {}
770
771#[cfg(feature = "std")]
773#[must_use] pub extern "C" fn create_thread_libstd(
774 thread_initialize_data: RefAny,
775 writeback_data: RefAny,
776 callback: ThreadCallback,
777) -> Thread {
778 let (sender_receiver, receiver_receiver) = channel::<ThreadReceiveMsg>();
779 let mut sender_receiver = ThreadSender::new(ThreadSenderInner {
780 ptr: Box::new(sender_receiver),
781 send_fn: ThreadSendCallback {
782 cb: default_send_thread_msg_fn,
783 },
784 destructor: ThreadSenderDestructorCallback {
785 cb: thread_sender_drop,
786 },
787 });
788 sender_receiver.ctx = callback.ctx.clone();
790
791 let (sender_sender, receiver_sender) = channel::<ThreadSendMsg>();
792 let mut receiver_sender = ThreadReceiver::new(ThreadReceiverInner {
793 ptr: Box::new(receiver_sender),
794 recv_fn: ThreadRecvCallback {
795 cb: default_receive_thread_msg_fn,
796 },
797 destructor: ThreadReceiverDestructorCallback {
798 cb: thread_receiver_drop,
799 },
800 });
801 receiver_sender.ctx = callback.ctx.clone();
803
804 let thread_check = Arc::new(());
805 let dropcheck = Arc::downgrade(&thread_check);
806
807 let thread_handle = Some(thread::spawn(move || {
808 let _thread_check_guard = thread_check;
811 (callback.cb)(thread_initialize_data, sender_receiver, receiver_sender);
812 }));
814
815 let thread_handle: Box<Option<JoinHandle<()>>> =
816 Box::new(thread_handle);
817 let sender: Box<Sender<ThreadSendMsg>> = Box::new(sender_sender);
818 let receiver: Box<Receiver<ThreadReceiveMsg>> =
819 Box::new(receiver_receiver);
820 let dropcheck: Box<alloc::sync::Weak<()>> = Box::new(dropcheck);
821
822 Thread::new(ThreadInner {
823 thread_handle,
824 sender,
825 receiver,
826 writeback_data,
827 dropcheck,
828 thread_destructor_fn: ThreadDestructorCallback {
829 cb: default_thread_destructor_fn,
830 },
831 check_thread_finished_fn: CheckThreadFinishedCallback {
832 cb: default_check_thread_finished,
833 },
834 send_thread_msg_fn: LibrarySendThreadMsgCallback {
835 cb: library_send_thread_msg_fn,
836 },
837 receive_thread_msg_fn: LibraryReceiveThreadMsgCallback {
838 cb: library_receive_thread_msg_fn,
839 },
840 })
841}
842
843#[cfg(not(feature = "std"))]
844pub extern "C" fn create_thread_libstd(
845 _thread_initialize_data: RefAny,
846 _writeback_data: RefAny,
847 _callback: ThreadCallback,
848) -> Thread {
849 Thread {
850 ptr: core::ptr::null(),
851 run_destructor: false,
852 }
853}
854
855#[cfg(test)]
856mod tests {
857 use super::*;
858
859 extern "C" fn test_writeback_callback(
860 _thread_data: RefAny,
861 _writeback_data: RefAny,
862 _callback_info: CallbackInfo,
863 ) -> Update {
864 Update::DoNothing
865 }
866
867 #[test]
868 fn test_writeback_callback_creation() {
869 let callback = WriteBackCallback::new(test_writeback_callback);
870 assert_eq!(callback.cb as *const () as usize, test_writeback_callback as *const () as usize);
871 }
872
873 #[test]
874 fn test_writeback_callback_clone() {
875 let callback = WriteBackCallback::new(test_writeback_callback);
876 let cloned = callback.clone();
877 assert_eq!(callback, cloned);
878 }
879}
880#[allow(variant_size_differences)] #[derive(Debug, Clone)]
883#[repr(C, u8)]
884pub enum OptionThread {
885 None,
886 Some(Thread),
887}
888
889impl From<Option<Thread>> for OptionThread {
890 fn from(o: Option<Thread>) -> Self {
891 o.map_or_else(|| Self::None, Self::Some)
892 }
893}
894
895impl OptionThread {
896 #[must_use] pub fn into_option(self) -> Option<Thread> {
897 match self {
898 Self::None => None,
899 Self::Some(t) => Some(t),
900 }
901 }
902}
903
904#[cfg(feature = "std")]
915#[must_use] pub fn thread_sleep_ms(milliseconds: u64) -> azul_css::corety::EmptyStruct {
916 thread::sleep(std::time::Duration::from_millis(milliseconds));
917 azul_css::corety::EmptyStruct::new()
918}
919
920#[cfg(not(feature = "std"))]
922pub fn thread_sleep_ms(_milliseconds: u64) -> azul_css::corety::EmptyStruct {
923 azul_css::corety::EmptyStruct::new()
925}
926
927#[cfg(feature = "std")]
932#[must_use] pub fn thread_sleep_us(microseconds: u64) -> azul_css::corety::EmptyStruct {
933 thread::sleep(std::time::Duration::from_micros(microseconds));
934 azul_css::corety::EmptyStruct::new()
935}
936
937#[cfg(not(feature = "std"))]
939pub fn thread_sleep_us(_microseconds: u64) -> azul_css::corety::EmptyStruct {
940 azul_css::corety::EmptyStruct::new()
942}
943
944#[cfg(feature = "std")]
949#[must_use] pub fn thread_sleep_ns(nanoseconds: u64) -> azul_css::corety::EmptyStruct {
950 thread::sleep(std::time::Duration::from_nanos(nanoseconds));
951 azul_css::corety::EmptyStruct::new()
952}
953
954#[cfg(not(feature = "std"))]
956pub fn thread_sleep_ns(_nanoseconds: u64) -> azul_css::corety::EmptyStruct {
957 azul_css::corety::EmptyStruct::new()
959}