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
28#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
32#[repr(C, u8)]
33pub enum ThreadReceiveMsg {
34 WriteBack(ThreadWriteBackMsg),
35 Update(Update),
36}
37
38#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
39#[repr(C, u8)]
40pub enum OptionThreadReceiveMsg {
41 None,
42 Some(ThreadReceiveMsg),
43}
44
45impl From<Option<ThreadReceiveMsg>> for OptionThreadReceiveMsg {
46 fn from(inner: Option<ThreadReceiveMsg>) -> Self {
47 match inner {
48 None => OptionThreadReceiveMsg::None,
49 Some(v) => OptionThreadReceiveMsg::Some(v),
50 }
51 }
52}
53
54impl OptionThreadReceiveMsg {
55 pub fn into_option(self) -> Option<ThreadReceiveMsg> {
56 match self {
57 OptionThreadReceiveMsg::None => None,
58 OptionThreadReceiveMsg::Some(v) => Some(v),
59 }
60 }
61
62 pub fn as_ref(&self) -> Option<&ThreadReceiveMsg> {
63 match self {
64 OptionThreadReceiveMsg::None => None,
65 OptionThreadReceiveMsg::Some(v) => Some(v),
66 }
67 }
68}
69
70#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
72#[repr(C)]
73pub struct ThreadWriteBackMsg {
74 pub refany: RefAny,
75 pub callback: WriteBackCallback,
76}
77
78impl ThreadWriteBackMsg {
79 pub fn new<C: Into<WriteBackCallback>>(callback: C, data: RefAny) -> Self {
80 Self {
81 refany: data,
82 callback: callback.into(),
83 }
84 }
85}
86
87#[derive(Debug)]
89#[repr(C)]
90pub struct ThreadSender {
91 #[cfg(feature = "std")]
92 pub ptr: alloc::boxed::Box<Arc<Mutex<ThreadSenderInner>>>,
93 #[cfg(not(feature = "std"))]
94 pub ptr: *const core::ffi::c_void,
95 pub run_destructor: bool,
96 pub ctx: OptionRefAny,
98}
99
100impl Clone for ThreadSender {
101 fn clone(&self) -> Self {
102 Self {
103 ptr: self.ptr.clone(),
104 run_destructor: true,
105 ctx: self.ctx.clone(),
106 }
107 }
108}
109
110impl Drop for ThreadSender {
111 fn drop(&mut self) {
112 self.run_destructor = false;
113 }
114}
115
116impl ThreadSender {
117 #[cfg(not(feature = "std"))]
118 pub fn new(_t: ThreadSenderInner) -> Self {
119 Self {
120 ptr: core::ptr::null(),
121 run_destructor: false,
122 ctx: OptionRefAny::None,
123 }
124 }
125
126 #[cfg(feature = "std")]
127 pub fn new(t: ThreadSenderInner) -> Self {
128 Self {
129 ptr: alloc::boxed::Box::new(Arc::new(Mutex::new(t))),
130 run_destructor: true,
131 ctx: OptionRefAny::None,
132 }
133 }
134
135 pub fn get_ctx(&self) -> OptionRefAny {
137 self.ctx.clone()
138 }
139
140 #[cfg(not(feature = "std"))]
141 pub fn send(&mut self, _msg: ThreadReceiveMsg) -> bool {
142 false
143 }
144
145 #[cfg(feature = "std")]
146 pub fn send(&mut self, msg: ThreadReceiveMsg) -> bool {
147 let ts = match self.ptr.lock().ok() {
148 Some(s) => s,
149 None => return false,
150 };
151 (ts.send_fn.cb)(ts.ptr.as_ref() as *const _ as *const core::ffi::c_void, msg)
152 }
153}
154
155#[derive(Debug)]
157#[cfg_attr(not(feature = "std"), derive(PartialEq, PartialOrd, Eq, Ord))]
158#[repr(C)]
159pub struct ThreadSenderInner {
160 #[cfg(feature = "std")]
161 pub ptr: alloc::boxed::Box<Sender<ThreadReceiveMsg>>,
162 #[cfg(not(feature = "std"))]
163 pub ptr: *const core::ffi::c_void,
164 pub send_fn: ThreadSendCallback,
165 pub destructor: ThreadSenderDestructorCallback,
166}
167
168#[cfg(not(feature = "std"))]
169unsafe impl Send for ThreadSenderInner {}
170
171#[cfg(feature = "std")]
172impl core::hash::Hash for ThreadSenderInner {
173 fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
174 (self.ptr.as_ref() as *const _ as usize).hash(state);
175 }
176}
177
178#[cfg(feature = "std")]
179impl PartialEq for ThreadSenderInner {
180 fn eq(&self, other: &Self) -> bool {
181 (self.ptr.as_ref() as *const _ as usize) == (other.ptr.as_ref() as *const _ as usize)
182 }
183}
184
185#[cfg(feature = "std")]
186impl Eq for ThreadSenderInner {}
187
188#[cfg(feature = "std")]
189impl PartialOrd for ThreadSenderInner {
190 fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
191 Some(
192 (self.ptr.as_ref() as *const _ as usize)
193 .cmp(&(other.ptr.as_ref() as *const _ as usize)),
194 )
195 }
196}
197
198#[cfg(feature = "std")]
199impl Ord for ThreadSenderInner {
200 fn cmp(&self, other: &Self) -> core::cmp::Ordering {
201 (self.ptr.as_ref() as *const _ as usize).cmp(&(other.ptr.as_ref() as *const _ as usize))
202 }
203}
204
205impl Drop for ThreadSenderInner {
206 fn drop(&mut self) {
207 (self.destructor.cb)(self);
208 }
209}
210
211pub type ThreadSendCallbackType = extern "C" fn(*const core::ffi::c_void, ThreadReceiveMsg) -> bool;
213
214#[repr(C)]
215pub struct ThreadSendCallback {
216 pub cb: ThreadSendCallbackType,
217}
218
219impl core::fmt::Debug for ThreadSendCallback {
220 fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
221 write!(f, "ThreadSendCallback {{ cb: {:p} }}", self.cb as *const ())
222 }
223}
224
225impl Clone for ThreadSendCallback {
226 fn clone(&self) -> Self {
227 Self { cb: self.cb }
228 }
229}
230
231impl PartialEq for ThreadSendCallback {
232 fn eq(&self, other: &Self) -> bool {
233 self.cb as usize == other.cb as usize
234 }
235}
236
237impl Eq for ThreadSendCallback {}
238
239impl PartialOrd for ThreadSendCallback {
240 fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
241 Some(self.cmp(other))
242 }
243}
244
245impl Ord for ThreadSendCallback {
246 fn cmp(&self, other: &Self) -> core::cmp::Ordering {
247 (self.cb as usize).cmp(&(other.cb as usize))
248 }
249}
250
251pub type ThreadSenderDestructorCallbackType = extern "C" fn(*mut ThreadSenderInner);
253
254#[repr(C)]
255pub struct ThreadSenderDestructorCallback {
256 pub cb: ThreadSenderDestructorCallbackType,
257}
258
259impl core::fmt::Debug for ThreadSenderDestructorCallback {
260 fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
261 write!(
262 f,
263 "ThreadSenderDestructorCallback {{ cb: {:p} }}",
264 self.cb as *const ()
265 )
266 }
267}
268
269impl Clone for ThreadSenderDestructorCallback {
270 fn clone(&self) -> Self {
271 Self { cb: self.cb }
272 }
273}
274
275impl PartialEq for ThreadSenderDestructorCallback {
276 fn eq(&self, other: &Self) -> bool {
277 self.cb as usize == other.cb as usize
278 }
279}
280
281impl Eq for ThreadSenderDestructorCallback {}
282
283impl PartialOrd for ThreadSenderDestructorCallback {
284 fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
285 Some(self.cmp(other))
286 }
287}
288
289impl Ord for ThreadSenderDestructorCallback {
290 fn cmp(&self, other: &Self) -> core::cmp::Ordering {
291 (self.cb as usize).cmp(&(other.cb as usize))
292 }
293}
294
295pub type WriteBackCallbackType = extern "C" fn(
302 RefAny,
303 RefAny,
304 CallbackInfo,
305) -> Update;
306
307#[repr(C)]
309pub struct WriteBackCallback {
310 pub cb: WriteBackCallbackType,
311 pub ctx: OptionRefAny,
314}
315
316impl WriteBackCallback {
317 pub fn new(cb: WriteBackCallbackType) -> Self {
319 Self {
320 cb,
321 ctx: OptionRefAny::None,
322 }
323 }
324
325 pub fn invoke(
327 &self,
328 thread_data: RefAny,
329 writeback_data: RefAny,
330 callback_info: CallbackInfo,
331 ) -> Update {
332 (self.cb)(thread_data, writeback_data, callback_info)
333 }
334}
335
336impl core::fmt::Debug for WriteBackCallback {
337 fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
338 write!(f, "WriteBackCallback {{ cb: {:p} }}", self.cb as *const ())
339 }
340}
341
342impl Clone for WriteBackCallback {
343 fn clone(&self) -> Self {
344 Self {
345 cb: self.cb,
346 ctx: self.ctx.clone(),
347 }
348 }
349}
350
351impl From<WriteBackCallbackType> for WriteBackCallback {
352 fn from(cb: WriteBackCallbackType) -> Self {
353 Self {
354 cb,
355 ctx: OptionRefAny::None,
356 }
357 }
358}
359
360impl PartialEq for WriteBackCallback {
361 fn eq(&self, other: &Self) -> bool {
362 self.cb as usize == other.cb as usize
363 }
364}
365
366impl Eq for WriteBackCallback {}
367
368impl PartialOrd for WriteBackCallback {
369 fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
370 (self.cb as usize).partial_cmp(&(other.cb as usize))
371 }
372}
373
374impl Ord for WriteBackCallback {
375 fn cmp(&self, other: &Self) -> core::cmp::Ordering {
376 (self.cb as usize).cmp(&(other.cb as usize))
377 }
378}
379
380impl core::hash::Hash for WriteBackCallback {
381 fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
382 (self.cb as usize).hash(state);
383 }
384}
385
386pub type ThreadCallbackType = extern "C" fn(RefAny, ThreadSender, ThreadReceiver);
388
389#[repr(C)]
390pub struct ThreadCallback {
391 pub cb: ThreadCallbackType,
392 pub ctx: OptionRefAny,
395}
396
397impl ThreadCallback {
398 pub fn new(cb: ThreadCallbackType) -> Self {
400 Self {
401 cb,
402 ctx: OptionRefAny::None,
403 }
404 }
405}
406
407impl core::fmt::Debug for ThreadCallback {
408 fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
409 write!(f, "ThreadCallback {{ cb: {:p} }}", self.cb as *const ())
410 }
411}
412
413impl Clone for ThreadCallback {
414 fn clone(&self) -> Self {
415 Self {
416 cb: self.cb,
417 ctx: self.ctx.clone(),
418 }
419 }
420}
421
422impl From<ThreadCallbackType> for ThreadCallback {
423 fn from(cb: ThreadCallbackType) -> Self {
424 Self {
425 cb,
426 ctx: OptionRefAny::None,
427 }
428 }
429}
430
431impl PartialEq for ThreadCallback {
432 fn eq(&self, other: &Self) -> bool {
433 self.cb as usize == other.cb as usize
434 }
435}
436
437impl Eq for ThreadCallback {}
438
439impl PartialOrd for ThreadCallback {
440 fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
441 (self.cb as usize).partial_cmp(&(other.cb as usize))
442 }
443}
444
445impl Ord for ThreadCallback {
446 fn cmp(&self, other: &Self) -> core::cmp::Ordering {
447 (self.cb as usize).cmp(&(other.cb as usize))
448 }
449}
450
451impl core::hash::Hash for ThreadCallback {
452 fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
453 (self.cb as usize).hash(state);
454 }
455}
456
457azul_core::impl_managed_callback! {
473 wrapper: ThreadCallback,
474 info_ty: ThreadSender,
475 return_ty: (),
476 default_ret: (),
477 invoker_static: THREAD_CALLBACK_INVOKER,
478 invoker_ty: AzThreadCallbackInvoker,
479 thunk_fn: az_thread_callback_thunk,
480 setter_fn: AzApp_setThreadCallbackInvoker,
481 from_handle_fn: AzThreadCallback_createFromHostHandle,
482 extra_args: [receiver: ThreadReceiver],
483}
484
485pub type LibraryReceiveThreadMsgCallbackType =
487 extern "C" fn(*const core::ffi::c_void) -> OptionThreadReceiveMsg;
488
489#[repr(C)]
490pub struct LibraryReceiveThreadMsgCallback {
491 pub cb: LibraryReceiveThreadMsgCallbackType,
492}
493
494impl core::fmt::Debug for LibraryReceiveThreadMsgCallback {
495 fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
496 write!(
497 f,
498 "LibraryReceiveThreadMsgCallback {{ cb: {:p} }}",
499 self.cb as *const ()
500 )
501 }
502}
503
504impl Clone for LibraryReceiveThreadMsgCallback {
505 fn clone(&self) -> Self {
506 Self { cb: self.cb }
507 }
508}
509
510pub type ThreadDestructorCallbackType = extern "C" fn(*mut ThreadInner);
512
513#[repr(C)]
514pub struct ThreadDestructorCallback {
515 pub cb: ThreadDestructorCallbackType,
516}
517
518impl core::fmt::Debug for ThreadDestructorCallback {
519 fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
520 write!(
521 f,
522 "ThreadDestructorCallback {{ cb: {:p} }}",
523 self.cb as *const ()
524 )
525 }
526}
527
528impl Clone for ThreadDestructorCallback {
529 fn clone(&self) -> Self {
530 Self { cb: self.cb }
531 }
532}
533
534#[derive(Debug)]
536#[repr(C)]
537pub struct Thread {
538 #[cfg(feature = "std")]
539 pub ptr: alloc::boxed::Box<Arc<Mutex<ThreadInner>>>,
540 #[cfg(not(feature = "std"))]
541 pub ptr: *const core::ffi::c_void,
542 pub run_destructor: bool,
543}
544
545impl Clone for Thread {
546 fn clone(&self) -> Self {
547 Self {
548 ptr: self.ptr.clone(),
549 run_destructor: true,
550 }
551 }
552}
553
554impl Drop for Thread {
555 fn drop(&mut self) {
556 self.run_destructor = false;
557 }
558}
559
560impl Thread {
561 #[cfg(feature = "std")]
562 pub fn new(ti: ThreadInner) -> Self {
563 Self {
564 ptr: alloc::boxed::Box::new(Arc::new(Mutex::new(ti))),
565 run_destructor: true,
566 }
567 }
568
569 #[cfg(not(feature = "std"))]
570 pub fn new(_ti: ThreadInner) -> Self {
571 Self {
572 ptr: core::ptr::null(),
573 run_destructor: false,
574 }
575 }
576
577 pub fn create<C: Into<ThreadCallback>>(
587 thread_initialize_data: RefAny,
588 writeback_data: RefAny,
589 callback: C,
590 ) -> Self {
591 create_thread_libstd(thread_initialize_data, writeback_data, callback.into())
592 }
593}
594
595#[derive(Debug)]
601#[repr(C)]
602pub struct ThreadInner {
603 #[cfg(feature = "std")]
604 pub thread_handle: alloc::boxed::Box<Option<JoinHandle<()>>>,
605 #[cfg(not(feature = "std"))]
606 pub thread_handle: *const core::ffi::c_void,
607
608 #[cfg(feature = "std")]
609 pub sender: alloc::boxed::Box<Sender<ThreadSendMsg>>,
610 #[cfg(not(feature = "std"))]
611 pub sender: *const core::ffi::c_void,
612
613 #[cfg(feature = "std")]
614 pub receiver: alloc::boxed::Box<Receiver<ThreadReceiveMsg>>,
615 #[cfg(not(feature = "std"))]
616 pub receiver: *const core::ffi::c_void,
617
618 #[cfg(feature = "std")]
619 pub dropcheck: alloc::boxed::Box<alloc::sync::Weak<()>>,
620 #[cfg(not(feature = "std"))]
621 pub dropcheck: *const core::ffi::c_void,
622
623 pub writeback_data: RefAny,
624 pub check_thread_finished_fn: CheckThreadFinishedCallback,
625 pub send_thread_msg_fn: LibrarySendThreadMsgCallback,
626 pub receive_thread_msg_fn: LibraryReceiveThreadMsgCallback,
627 pub thread_destructor_fn: ThreadDestructorCallback,
628}
629
630#[cfg(feature = "std")]
631impl ThreadInner {
632 pub fn is_finished(&self) -> bool {
634 (self.check_thread_finished_fn.cb)(
635 self.dropcheck.as_ref() as *const _ as *const core::ffi::c_void
636 )
637 }
638
639 pub fn sender_send(&mut self, msg: ThreadSendMsg) -> bool {
641 (self.send_thread_msg_fn.cb)(
642 self.sender.as_ref() as *const _ as *const core::ffi::c_void,
643 msg,
644 )
645 }
646
647 pub fn receiver_try_recv(&mut self) -> OptionThreadReceiveMsg {
649 (self.receive_thread_msg_fn.cb)(
650 self.receiver.as_ref() as *const _ as *const core::ffi::c_void
651 )
652 }
653}
654
655#[cfg(not(feature = "std"))]
656impl ThreadInner {
657 pub fn is_finished(&self) -> bool {
659 true
660 }
661
662 pub fn sender_send(&mut self, _msg: ThreadSendMsg) -> bool {
664 false
665 }
666
667 pub fn receiver_try_recv(&mut self) -> OptionThreadReceiveMsg {
669 None.into()
670 }
671}
672
673impl Drop for ThreadInner {
674 fn drop(&mut self) {
675 (self.thread_destructor_fn.cb)(self);
676 }
677}
678
679#[cfg(feature = "std")]
681extern "C" fn default_thread_destructor_fn(thread: *mut ThreadInner) {
682 let thread = unsafe { &mut *thread };
683
684 if let Some(thread_handle) = thread.thread_handle.take() {
685 let _ = thread.sender.send(ThreadSendMsg::TerminateThread);
686 let _ = thread_handle.join(); }
688}
689
690#[cfg(not(feature = "std"))]
691extern "C" fn default_thread_destructor_fn(_thread: *mut ThreadInner) {}
692
693#[cfg(feature = "std")]
694extern "C" fn library_send_thread_msg_fn(
695 sender: *const core::ffi::c_void,
696 msg: ThreadSendMsg,
697) -> bool {
698 unsafe { &*(sender as *const Sender<ThreadSendMsg>) }
699 .send(msg)
700 .is_ok()
701}
702
703#[cfg(not(feature = "std"))]
704extern "C" fn library_send_thread_msg_fn(
705 _sender: *const core::ffi::c_void,
706 _msg: ThreadSendMsg,
707) -> bool {
708 false
709}
710
711#[cfg(feature = "std")]
712extern "C" fn library_receive_thread_msg_fn(
713 receiver: *const core::ffi::c_void,
714) -> OptionThreadReceiveMsg {
715 unsafe { &*(receiver as *const Receiver<ThreadReceiveMsg>) }
716 .try_recv()
717 .ok()
718 .into()
719}
720
721#[cfg(not(feature = "std"))]
722extern "C" fn library_receive_thread_msg_fn(
723 _receiver: *const core::ffi::c_void,
724) -> OptionThreadReceiveMsg {
725 None.into()
726}
727
728#[cfg(feature = "std")]
729extern "C" fn default_send_thread_msg_fn(
730 sender: *const core::ffi::c_void,
731 msg: ThreadReceiveMsg,
732) -> bool {
733 unsafe { &*(sender as *const Sender<ThreadReceiveMsg>) }
734 .send(msg)
735 .is_ok()
736}
737
738#[cfg(not(feature = "std"))]
739extern "C" fn default_send_thread_msg_fn(
740 _sender: *const core::ffi::c_void,
741 _msg: ThreadReceiveMsg,
742) -> bool {
743 false
744}
745
746#[cfg(feature = "std")]
747extern "C" fn default_receive_thread_msg_fn(
748 receiver: *const core::ffi::c_void,
749) -> OptionThreadSendMsg {
750 unsafe { &*(receiver as *const Receiver<ThreadSendMsg>) }
751 .try_recv()
752 .ok()
753 .into()
754}
755
756#[cfg(not(feature = "std"))]
757extern "C" fn default_receive_thread_msg_fn(
758 _receiver: *const core::ffi::c_void,
759) -> OptionThreadSendMsg {
760 None.into()
761}
762
763#[cfg(feature = "std")]
764extern "C" fn default_check_thread_finished(dropcheck: *const core::ffi::c_void) -> bool {
765 let weak = unsafe { &*(dropcheck as *const alloc::sync::Weak<()>) };
766 weak.upgrade().is_none()
767}
768
769#[cfg(not(feature = "std"))]
770extern "C" fn default_check_thread_finished(_dropcheck: *const core::ffi::c_void) -> bool {
771 true
772}
773
774#[cfg(feature = "std")]
775extern "C" fn thread_sender_drop(_: *mut ThreadSenderInner) {}
776
777#[cfg(not(feature = "std"))]
778extern "C" fn thread_sender_drop(_: *mut ThreadSenderInner) {}
779
780#[cfg(feature = "std")]
781extern "C" fn thread_receiver_drop(_: *mut ThreadReceiverInner) {}
782
783#[cfg(not(feature = "std"))]
784extern "C" fn thread_receiver_drop(_: *mut ThreadReceiverInner) {}
785
786pub type CreateThreadCallbackType = extern "C" fn(RefAny, RefAny, ThreadCallback) -> Thread;
788
789#[repr(C)]
790pub struct CreateThreadCallback {
791 pub cb: CreateThreadCallbackType,
792}
793
794impl core::fmt::Debug for CreateThreadCallback {
795 fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
796 write!(
797 f,
798 "CreateThreadCallback {{ cb: {:p} }}",
799 self.cb as *const ()
800 )
801 }
802}
803
804impl Clone for CreateThreadCallback {
805 fn clone(&self) -> Self {
806 Self { cb: self.cb }
807 }
808}
809
810impl Copy for CreateThreadCallback {}
811
812impl PartialEq for CreateThreadCallback {
813 fn eq(&self, other: &Self) -> bool {
814 self.cb as usize == other.cb as usize
815 }
816}
817
818impl Eq for CreateThreadCallback {}
819
820impl PartialOrd for CreateThreadCallback {
821 fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
822 (self.cb as usize).partial_cmp(&(other.cb as usize))
823 }
824}
825
826impl Ord for CreateThreadCallback {
827 fn cmp(&self, other: &Self) -> core::cmp::Ordering {
828 (self.cb as usize).cmp(&(other.cb as usize))
829 }
830}
831
832impl core::hash::Hash for CreateThreadCallback {
833 fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
834 (self.cb as usize).hash(state);
835 }
836}
837
838#[cfg(feature = "std")]
840pub extern "C" fn create_thread_libstd(
841 thread_initialize_data: RefAny,
842 writeback_data: RefAny,
843 callback: ThreadCallback,
844) -> Thread {
845 let (sender_receiver, receiver_receiver) = channel::<ThreadReceiveMsg>();
846 let mut sender_receiver = ThreadSender::new(ThreadSenderInner {
847 ptr: alloc::boxed::Box::new(sender_receiver),
848 send_fn: ThreadSendCallback {
849 cb: default_send_thread_msg_fn,
850 },
851 destructor: ThreadSenderDestructorCallback {
852 cb: thread_sender_drop,
853 },
854 });
855 sender_receiver.ctx = callback.ctx.clone();
857
858 let (sender_sender, receiver_sender) = channel::<ThreadSendMsg>();
859 let mut receiver_sender = ThreadReceiver::new(ThreadReceiverInner {
860 ptr: alloc::boxed::Box::new(receiver_sender),
861 recv_fn: ThreadRecvCallback {
862 cb: default_receive_thread_msg_fn,
863 },
864 destructor: ThreadReceiverDestructorCallback {
865 cb: thread_receiver_drop,
866 },
867 });
868 receiver_sender.ctx = callback.ctx.clone();
870
871 let thread_check = Arc::new(());
872 let dropcheck = Arc::downgrade(&thread_check);
873
874 let thread_handle = Some(thread::spawn(move || {
875 let _thread_check_guard = thread_check;
878 (callback.cb)(thread_initialize_data, sender_receiver, receiver_sender);
879 }));
881
882 let thread_handle: alloc::boxed::Box<Option<JoinHandle<()>>> =
883 alloc::boxed::Box::new(thread_handle);
884 let sender: alloc::boxed::Box<Sender<ThreadSendMsg>> = alloc::boxed::Box::new(sender_sender);
885 let receiver: alloc::boxed::Box<Receiver<ThreadReceiveMsg>> =
886 alloc::boxed::Box::new(receiver_receiver);
887 let dropcheck: alloc::boxed::Box<alloc::sync::Weak<()>> = alloc::boxed::Box::new(dropcheck);
888
889 Thread::new(ThreadInner {
890 thread_handle,
891 sender,
892 receiver,
893 writeback_data,
894 dropcheck,
895 thread_destructor_fn: ThreadDestructorCallback {
896 cb: default_thread_destructor_fn,
897 },
898 check_thread_finished_fn: CheckThreadFinishedCallback {
899 cb: default_check_thread_finished,
900 },
901 send_thread_msg_fn: LibrarySendThreadMsgCallback {
902 cb: library_send_thread_msg_fn,
903 },
904 receive_thread_msg_fn: LibraryReceiveThreadMsgCallback {
905 cb: library_receive_thread_msg_fn,
906 },
907 })
908}
909
910#[cfg(not(feature = "std"))]
911pub extern "C" fn create_thread_libstd(
912 _thread_initialize_data: RefAny,
913 _writeback_data: RefAny,
914 _callback: ThreadCallback,
915) -> Thread {
916 Thread {
917 ptr: core::ptr::null(),
918 run_destructor: false,
919 }
920}
921
922#[cfg(test)]
923mod tests {
924 use super::*;
925
926 extern "C" fn test_writeback_callback(
927 _thread_data: RefAny,
928 _writeback_data: RefAny,
929 _callback_info: CallbackInfo,
930 ) -> Update {
931 Update::DoNothing
932 }
933
934 #[test]
935 fn test_writeback_callback_creation() {
936 let callback = WriteBackCallback::new(test_writeback_callback);
937 assert_eq!(callback.cb as usize, test_writeback_callback as usize);
938 }
939
940 #[test]
941 fn test_writeback_callback_clone() {
942 let callback = WriteBackCallback::new(test_writeback_callback);
943 let cloned = callback.clone();
944 assert_eq!(callback, cloned);
945 }
946}
947
948#[derive(Debug, Clone)]
950#[repr(C, u8)]
951pub enum OptionThread {
952 None,
953 Some(Thread),
954}
955
956impl From<Option<Thread>> for OptionThread {
957 fn from(o: Option<Thread>) -> Self {
958 match o {
959 None => OptionThread::None,
960 Some(t) => OptionThread::Some(t),
961 }
962 }
963}
964
965impl OptionThread {
966 pub fn into_option(self) -> Option<Thread> {
967 match self {
968 OptionThread::None => None,
969 OptionThread::Some(t) => Some(t),
970 }
971 }
972}
973
974#[cfg(feature = "std")]
985pub fn thread_sleep_ms(milliseconds: u64) -> azul_css::corety::EmptyStruct {
986 std::thread::sleep(std::time::Duration::from_millis(milliseconds));
987 azul_css::corety::EmptyStruct::new()
988}
989
990#[cfg(not(feature = "std"))]
992pub fn thread_sleep_ms(_milliseconds: u64) -> azul_css::corety::EmptyStruct {
993 azul_css::corety::EmptyStruct::new()
995}
996
997#[cfg(feature = "std")]
1002pub fn thread_sleep_us(microseconds: u64) -> azul_css::corety::EmptyStruct {
1003 std::thread::sleep(std::time::Duration::from_micros(microseconds));
1004 azul_css::corety::EmptyStruct::new()
1005}
1006
1007#[cfg(not(feature = "std"))]
1009pub fn thread_sleep_us(_microseconds: u64) -> azul_css::corety::EmptyStruct {
1010 azul_css::corety::EmptyStruct::new()
1012}
1013
1014#[cfg(feature = "std")]
1019pub fn thread_sleep_ns(nanoseconds: u64) -> azul_css::corety::EmptyStruct {
1020 std::thread::sleep(std::time::Duration::from_nanos(nanoseconds));
1021 azul_css::corety::EmptyStruct::new()
1022}
1023
1024#[cfg(not(feature = "std"))]
1026pub fn thread_sleep_ns(_nanoseconds: u64) -> azul_css::corety::EmptyStruct {
1027 azul_css::corety::EmptyStruct::new()
1029}