1#![expect(
8 clippy::as_conversions,
9 clippy::missing_safety_doc,
10 clippy::missing_panics_doc,
11 clippy::undocumented_unsafe_blocks,
12 missing_docs,
13 reason = "needs refactoring"
14)]
15
16pub mod api;
17pub mod err;
18
19use std::{
20 cell::Cell,
21 ffi::{CString, c_void},
22 marker::PhantomData,
23 panic, ptr,
24};
25
26use dart_sys::{_Dart_Handle, Dart_Handle};
27use derive_more::with_trait::Display;
28use flutter_rust_bridge::{
29 JoinHandle,
30 for_generated::{
31 BaseAsyncRuntime, NoOpErrorListener, SimpleExecutor, SimpleHandler,
32 SimpleThreadPool,
33 },
34};
35use libc::c_char;
36
37pub use self::{
38 api::{
39 ConnectionHandle, Jason, LocalMediaTrack, MediaManagerHandle,
40 ReconnectHandle, RemoteMediaTrack, RoomCloseReason, RoomHandle,
41 },
42 err::DartError as Error,
43};
44pub use crate::media::MediaDirection;
45use crate::{
46 api::{api::ForeignClass, dart::err::new_panic_error},
47 media::{
48 FacingMode, MediaDeviceKind, MediaKind, MediaSourceKind,
49 NoiseSuppressionLevel,
50 },
51 platform::utils::{
52 c_str_into_string, dart_api, free_dart_native_string,
53 handle::DartHandle, string_into_c_str,
54 },
55};
56
57thread_local! {
58 pub static DART_HANDLER_PORT: Cell<Option<i64>> = Cell::default();
60}
61
62pub fn propagate_panic<T>(f: impl FnOnce() -> T) -> T {
65 panic::catch_unwind(panic::AssertUnwindSafe(f)).unwrap_or_else(|_| {
66 let exception = unsafe { new_panic_error() };
67 unsafe {
68 dart_api::propagate_error(exception);
69 }
70 unreachable!("`Dart_PropagateError` should do early return")
71 })
72}
73
74pub trait PrimitiveEnum: TryFrom<i64> {}
77
78#[derive(Clone, Copy, Debug)]
80#[repr(u8)]
81pub enum MemoryOwner {
82 Rust = 0,
84
85 Dart = 1,
87}
88
89#[derive(Debug)]
91#[repr(C, u8)]
92pub enum DartValue {
93 None,
96
97 Ptr(ptr::NonNull<c_void>),
99
100 Handle(ptr::NonNull<Dart_Handle>),
102
103 String(ptr::NonNull<c_char>, MemoryOwner),
105
106 Int(i64),
110
111 Float(f64),
113
114 Bool(bool),
116}
117
118impl Drop for DartValue {
119 fn drop(&mut self) {
120 match self {
121 Self::Float(_)
122 | Self::Bool(_)
123 | Self::Int(_)
124 | Self::Ptr(_)
125 | Self::Handle(_)
126 | Self::None => {}
127 Self::String(ptr, MemoryOwner::Dart) => unsafe {
128 free_dart_native_string(*ptr);
129 },
130 Self::String(ptr, MemoryOwner::Rust) => unsafe {
131 drop(CString::from_raw(ptr.as_ptr()));
132 },
133 }
134 }
135}
136
137impl From<()> for DartValue {
138 fn from((): ()) -> Self {
139 Self::None
140 }
141}
142
143impl<T: ForeignClass> From<T> for DartValue {
144 fn from(val: T) -> Self {
145 Self::Ptr(val.into_ptr().cast())
146 }
147}
148
149impl<T: ForeignClass> From<Option<T>> for DartValue {
150 fn from(val: Option<T>) -> Self {
151 val.map_or(Self::None, |t| Self::from(t))
152 }
153}
154
155impl From<String> for DartValue {
156 fn from(string: String) -> Self {
157 Self::String(string_into_c_str(string), MemoryOwner::Rust)
158 }
159}
160
161impl From<Option<String>> for DartValue {
162 fn from(val: Option<String>) -> Self {
163 val.map_or(Self::None, Self::from)
164 }
165}
166
167impl From<Option<i64>> for DartValue {
168 fn from(val: Option<i64>) -> Self {
169 val.map_or(Self::None, Self::from)
170 }
171}
172
173impl From<ptr::NonNull<Dart_Handle>> for DartValue {
174 fn from(handle: ptr::NonNull<*mut _Dart_Handle>) -> Self {
175 Self::Handle(handle)
176 }
177}
178
179impl From<Option<ptr::NonNull<Dart_Handle>>> for DartValue {
180 fn from(val: Option<ptr::NonNull<Dart_Handle>>) -> Self {
181 val.map_or(Self::None, Self::from)
182 }
183}
184
185impl From<Dart_Handle> for DartValue {
186 fn from(handle: Dart_Handle) -> Self {
187 Self::Handle(ptr::NonNull::from(Box::leak(Box::new(handle))))
188 }
189}
190
191impl From<Option<Dart_Handle>> for DartValue {
192 fn from(val: Option<Dart_Handle>) -> Self {
193 val.map_or(Self::None, Self::from)
194 }
195}
196
197impl From<Error> for DartValue {
198 fn from(err: Error) -> Self {
199 Self::Handle(err.into())
200 }
201}
202
203impl From<Option<Error>> for DartValue {
204 fn from(val: Option<Error>) -> Self {
205 val.map_or(Self::None, Self::from)
206 }
207}
208
209impl From<MediaDirection> for DartValue {
210 fn from(val: MediaDirection) -> Self {
211 Self::from(val as u8)
212 }
213}
214
215impl From<bool> for DartValue {
216 fn from(val: bool) -> Self {
217 Self::Bool(val)
218 }
219}
220
221impl From<f32> for DartValue {
222 fn from(val: f32) -> Self {
223 Self::Float(f64::from(val))
224 }
225}
226
227impl From<f64> for DartValue {
228 fn from(val: f64) -> Self {
229 Self::Float(val)
230 }
231}
232
233macro_rules! impl_from_num_for_dart_value {
236 ($arg:ty) => {
237 impl From<$arg> for DartValue {
238 fn from(val: $arg) -> Self {
239 DartValue::Int(i64::from(val))
240 }
241 }
242 };
243}
244
245impl_from_num_for_dart_value!(i8);
246impl_from_num_for_dart_value!(i16);
247impl_from_num_for_dart_value!(i32);
248impl_from_num_for_dart_value!(i64);
249impl_from_num_for_dart_value!(u8);
250impl_from_num_for_dart_value!(u16);
251impl_from_num_for_dart_value!(u32);
252
253#[derive(Debug)]
258#[repr(transparent)]
259pub struct DartValueArg<T>(DartValue, PhantomData<*const T>);
260
261impl<F, T> From<F> for DartValueArg<T>
262where
263 DartValue: From<F>,
264{
265 fn from(from: F) -> Self {
266 Self(DartValue::from(from), PhantomData)
267 }
268}
269
270impl<T> TryFrom<DartValueArg<T>> for ptr::NonNull<c_void> {
271 type Error = DartValueCastError;
272
273 fn try_from(value: DartValueArg<T>) -> Result<Self, Self::Error> {
274 match value.0 {
275 DartValue::Ptr(ptr) => Ok(ptr),
276 DartValue::None
277 | DartValue::Handle(_)
278 | DartValue::String(_, _)
279 | DartValue::Int(_)
280 | DartValue::Bool(_)
281 | DartValue::Float(_) => Err(DartValueCastError {
282 expectation: "NonNull<c_void>",
283 value: value.0,
284 }),
285 }
286 }
287}
288
289impl<T> TryFrom<DartValueArg<T>> for Option<ptr::NonNull<c_void>> {
290 type Error = DartValueCastError;
291
292 fn try_from(value: DartValueArg<T>) -> Result<Self, Self::Error> {
293 match value.0 {
294 DartValue::None => Ok(None),
295 DartValue::Ptr(ptr) => Ok(Some(ptr)),
296 DartValue::Handle(_)
297 | DartValue::String(_, _)
298 | DartValue::Float(_)
299 | DartValue::Bool(_)
300 | DartValue::Int(_) => Err(DartValueCastError {
301 expectation: "Option<NonNull<c_void>>",
302 value: value.0,
303 }),
304 }
305 }
306}
307
308impl TryFrom<DartValueArg<Self>> for String {
309 type Error = DartValueCastError;
310
311 fn try_from(value: DartValueArg<Self>) -> Result<Self, Self::Error> {
312 match value.0 {
313 DartValue::String(c_str, _) => unsafe {
314 Ok(c_str_into_string(c_str))
315 },
316 DartValue::None
317 | DartValue::Ptr(_)
318 | DartValue::Handle(_)
319 | DartValue::Float(_)
320 | DartValue::Bool(_)
321 | DartValue::Int(_) => Err(DartValueCastError {
322 expectation: "String",
323 value: value.0,
324 }),
325 }
326 }
327}
328
329impl TryFrom<DartValueArg<()>> for () {
330 type Error = DartValueCastError;
331
332 fn try_from(value: DartValueArg<()>) -> Result<Self, Self::Error> {
333 match value.0 {
334 DartValue::None => Ok(()),
335 DartValue::Ptr(_)
336 | DartValue::Handle(_)
337 | DartValue::String(_, _)
338 | DartValue::Float(_)
339 | DartValue::Bool(_)
340 | DartValue::Int(_) => {
341 Err(DartValueCastError { expectation: "()", value: value.0 })
342 }
343 }
344 }
345}
346
347impl TryFrom<DartValueArg<Self>> for Option<DartHandle> {
348 type Error = DartValueCastError;
349
350 fn try_from(value: DartValueArg<Self>) -> Result<Self, Self::Error> {
351 match value.0 {
352 DartValue::None => Ok(None),
353 DartValue::Handle(handle) => {
354 let handle = unsafe { *handle.as_ptr() };
355 Ok(Some(unsafe { DartHandle::new(handle) }))
356 }
357 DartValue::Ptr(_)
358 | DartValue::Bool(_)
359 | DartValue::Float(_)
360 | DartValue::String(_, _)
361 | DartValue::Int(_) => Err(DartValueCastError {
362 expectation: "Option<DartHandle>",
363 value: value.0,
364 }),
365 }
366 }
367}
368
369impl TryFrom<DartValueArg<Self>> for Option<String> {
370 type Error = DartValueCastError;
371
372 fn try_from(value: DartValueArg<Self>) -> Result<Self, Self::Error> {
373 match value.0 {
374 DartValue::None => Ok(None),
375 DartValue::String(c_str, _) => unsafe {
376 Ok(Some(c_str_into_string(c_str)))
377 },
378 DartValue::Ptr(_)
379 | DartValue::Bool(_)
380 | DartValue::Float(_)
381 | DartValue::Handle(_)
382 | DartValue::Int(_) => Err(DartValueCastError {
383 expectation: "Option<String>",
384 value: value.0,
385 }),
386 }
387 }
388}
389
390impl<T> TryFrom<DartValueArg<T>> for Dart_Handle {
391 type Error = DartValueCastError;
392
393 fn try_from(value: DartValueArg<T>) -> Result<Self, Self::Error> {
394 match value.0 {
395 DartValue::Handle(c_ptr) => Ok(unsafe { unbox_dart_handle(c_ptr) }),
396 DartValue::None
397 | DartValue::Ptr(_)
398 | DartValue::String(_, _)
399 | DartValue::Float(_)
400 | DartValue::Bool(_)
401 | DartValue::Int(_) => Err(DartValueCastError {
402 expectation: "Dart_Handle",
403 value: value.0,
404 }),
405 }
406 }
407}
408
409impl TryFrom<DartValueArg<Self>> for DartHandle {
410 type Error = DartValueCastError;
411
412 fn try_from(value: DartValueArg<Self>) -> Result<Self, Self::Error> {
413 match value.0 {
414 DartValue::Handle(handle) => {
415 let handle = unsafe { unbox_dart_handle(handle) };
416 Ok(unsafe { Self::new(handle) })
417 }
418 DartValue::None
419 | DartValue::Ptr(_)
420 | DartValue::String(_, _)
421 | DartValue::Float(_)
422 | DartValue::Bool(_)
423 | DartValue::Int(_) => Err(DartValueCastError {
424 expectation: "DartHandle",
425 value: value.0,
426 }),
427 }
428 }
429}
430
431impl<T> TryFrom<DartValueArg<T>> for ptr::NonNull<Dart_Handle> {
432 type Error = DartValueCastError;
433
434 fn try_from(value: DartValueArg<T>) -> Result<Self, Self::Error> {
435 match value.0 {
436 DartValue::Handle(c_str) => Ok(c_str),
437 DartValue::None
438 | DartValue::Ptr(_)
439 | DartValue::String(_, _)
440 | DartValue::Float(_)
441 | DartValue::Bool(_)
442 | DartValue::Int(_) => Err(DartValueCastError {
443 expectation: "NonNull<Dart_Handle>",
444 value: value.0,
445 }),
446 }
447 }
448}
449
450impl<T> TryFrom<DartValueArg<T>> for Option<ptr::NonNull<Dart_Handle>> {
451 type Error = DartValueCastError;
452
453 fn try_from(value: DartValueArg<T>) -> Result<Self, Self::Error> {
454 match value.0 {
455 DartValue::None => Ok(None),
456 DartValue::Handle(c_str) => Ok(Some(c_str)),
457 DartValue::Ptr(_)
458 | DartValue::Bool(_)
459 | DartValue::Float(_)
460 | DartValue::String(_, _)
461 | DartValue::Int(_) => Err(DartValueCastError {
462 expectation: "Option<NonNull<Dart_Handle>>",
463 value: value.0,
464 }),
465 }
466 }
467}
468
469macro_rules! impl_primitive_dart_value_try_from {
472 ($arg:ty) => {
473 impl TryFrom<DartValueArg<Self>> for $arg {
474 type Error = DartValueCastError;
475
476 fn try_from(
477 value: DartValueArg<Self>,
478 ) -> Result<Self, Self::Error> {
479 match value.0 {
480 DartValue::Int(num) => {
481 Ok(Self::try_from(num).map_err(
482 |_| DartValueCastError {
483 expectation: stringify!($arg),
484 value: value.0,
485 }
486 )?)
487 }
488 _ => Err(DartValueCastError {
489 expectation: stringify!($arg),
490 value: value.0,
491 }),
492 }
493 }
494 }
495
496 impl TryFrom<DartValueArg<Self>> for Option<$arg> {
497 type Error = DartValueCastError;
498
499 fn try_from(
500 value: DartValueArg<Self>
501 ) -> Result<Self, Self::Error> {
502 match value.0 {
503 DartValue::None => Ok(None),
504 DartValue::Int(num) => {
505 Ok(Some(<$arg>::try_from(num).map_err(
506 |_| DartValueCastError {
507 expectation: concat!(
508 "Option<",
509 stringify!($arg),
510 ">"
511 ),
512 value: value.0,
513 }
514 )?))
515 }
516 _ => Err(DartValueCastError {
517 expectation: concat!("Option<", stringify!($arg), ">"),
518 value: value.0,
519 }),
520 }
521 }
522 }
523 };
524 ($($arg:ty),+) => {
525 $(impl_primitive_dart_value_try_from!($arg);)+
526 }
527}
528
529impl_primitive_dart_value_try_from![i8, i16, i32, i64, u8, u16, u32];
530
531impl<T: PrimitiveEnum> TryFrom<DartValueArg<T>> for i64 {
532 type Error = DartValueCastError;
533
534 fn try_from(value: DartValueArg<T>) -> Result<Self, Self::Error> {
535 match value.0 {
536 DartValue::Int(num) => Ok(num),
537 DartValue::None
538 | DartValue::Ptr(_)
539 | DartValue::Handle(_)
540 | DartValue::Float(_)
541 | DartValue::Bool(_)
542 | DartValue::String(_, _) => {
543 Err(DartValueCastError { expectation: "i64", value: value.0 })
544 }
545 }
546 }
547}
548
549impl<T: PrimitiveEnum> TryFrom<DartValueArg<Self>> for Option<T> {
550 type Error = DartValueCastError;
551
552 fn try_from(value: DartValueArg<Self>) -> Result<Self, Self::Error> {
553 match value.0 {
554 DartValue::None => Ok(None),
555 DartValue::Int(num) => match T::try_from(num) {
556 Ok(variant) => Ok(Some(variant)),
557 Err(_) => Err(DartValueCastError {
558 expectation: "Option<i64>",
559 value: value.0,
560 }),
561 },
562 DartValue::Ptr(_)
563 | DartValue::Float(_)
564 | DartValue::Bool(_)
565 | DartValue::Handle(_)
566 | DartValue::String(_, _) => Err(DartValueCastError {
567 expectation: "Option<i64>",
568 value: value.0,
569 }),
570 }
571 }
572}
573
574impl TryFrom<DartValueArg<Self>> for Option<f64> {
575 type Error = DartValueCastError;
576
577 fn try_from(value: DartValueArg<Self>) -> Result<Self, Self::Error> {
578 match value.0 {
579 DartValue::None => Ok(None),
580 DartValue::Float(num) => Ok(Some(num)),
581 DartValue::Ptr(_)
582 | DartValue::Handle(_)
583 | DartValue::String(..)
584 | DartValue::Int(_)
585 | DartValue::Bool(_) => Err(DartValueCastError {
586 expectation: "Option<f64>",
587 value: value.0,
588 }),
589 }
590 }
591}
592
593impl TryFrom<DartValueArg<Self>> for Option<bool> {
594 type Error = DartValueCastError;
595
596 fn try_from(value: DartValueArg<Self>) -> Result<Self, Self::Error> {
597 match value.0 {
598 DartValue::None => Ok(None),
599 DartValue::Bool(num) => Ok(Some(num)),
600 DartValue::Ptr(_)
601 | DartValue::Handle(_)
602 | DartValue::String(..)
603 | DartValue::Int(_)
604 | DartValue::Float(_) => Err(DartValueCastError {
605 expectation: "Option<bool>",
606 value: value.0,
607 }),
608 }
609 }
610}
611
612impl TryFrom<DartValueArg<Self>> for bool {
613 type Error = DartValueCastError;
614
615 fn try_from(value: DartValueArg<Self>) -> Result<Self, Self::Error> {
616 match value.0 {
617 DartValue::Bool(num) => Ok(num),
618 DartValue::Ptr(..)
619 | DartValue::None
620 | DartValue::Handle(..)
621 | DartValue::String(..)
622 | DartValue::Int(..)
623 | DartValue::Float(..) => {
624 Err(DartValueCastError { expectation: "bool", value: value.0 })
625 }
626 }
627 }
628}
629
630#[derive(Debug, Display)]
632#[display("expected `{expectation}`, but got: `{value:?}`")]
633pub struct DartValueCastError {
634 expectation: &'static str,
636
637 value: DartValue,
639}
640
641impl PrimitiveEnum for MediaSourceKind {}
642impl PrimitiveEnum for FacingMode {}
643impl PrimitiveEnum for NoiseSuppressionLevel {}
644impl PrimitiveEnum for MediaDirection {}
645
646impl TryFrom<i64> for MediaSourceKind {
647 type Error = i64;
648
649 fn try_from(value: i64) -> Result<Self, Self::Error> {
650 match value {
651 0 => Ok(Self::Device),
652 1 => Ok(Self::Display),
653 _ => Err(value),
654 }
655 }
656}
657
658impl TryFrom<i64> for FacingMode {
659 type Error = i64;
660
661 fn try_from(value: i64) -> Result<Self, Self::Error> {
662 match value {
663 0 => Ok(Self::User),
664 1 => Ok(Self::Environment),
665 2 => Ok(Self::Left),
666 3 => Ok(Self::Right),
667 _ => Err(value),
668 }
669 }
670}
671
672impl TryFrom<i64> for NoiseSuppressionLevel {
673 type Error = i64;
674
675 fn try_from(value: i64) -> Result<Self, Self::Error> {
676 match value {
677 0 => Ok(Self::Low),
678 1 => Ok(Self::Moderate),
679 2 => Ok(Self::High),
680 3 => Ok(Self::VeryHigh),
681 _ => Err(value),
682 }
683 }
684}
685
686impl TryFrom<i64> for MediaKind {
687 type Error = i64;
688
689 fn try_from(value: i64) -> Result<Self, Self::Error> {
690 match value {
691 0 => Ok(Self::Audio),
692 1 => Ok(Self::Video),
693 _ => Err(value),
694 }
695 }
696}
697
698impl TryFrom<i64> for MediaDeviceKind {
699 type Error = i64;
700
701 fn try_from(value: i64) -> Result<Self, Self::Error> {
702 match value {
703 0 => Ok(Self::AudioInput),
704 1 => Ok(Self::VideoInput),
705 2 => Ok(Self::AudioOutput),
706 _ => Err(value),
707 }
708 }
709}
710
711impl TryFrom<i64> for MediaDirection {
712 type Error = i64;
713
714 fn try_from(value: i64) -> Result<Self, Self::Error> {
715 match value {
716 0 => Ok(Self::SendRecv),
717 1 => Ok(Self::SendOnly),
718 2 => Ok(Self::RecvOnly),
719 3 => Ok(Self::Inactive),
720 _ => Err(value),
721 }
722 }
723}
724
725#[unsafe(no_mangle)]
727pub unsafe extern "C" fn unbox_dart_handle(
728 val: ptr::NonNull<Dart_Handle>,
729) -> Dart_Handle {
730 unsafe { *val.as_ptr() }
731}
732
733#[unsafe(no_mangle)]
735pub unsafe extern "C" fn free_boxed_dart_handle(
736 val: ptr::NonNull<Dart_Handle>,
737) {
738 let handle = unsafe { Box::from_raw(val.as_ptr()) };
739 unsafe {
740 dart_api::delete_persistent_handle(*handle);
741 }
742}
743
744#[unsafe(no_mangle)]
747pub unsafe extern "C" fn box_dart_handle(
748 val: Dart_Handle,
749) -> ptr::NonNull<Dart_Handle> {
750 let persisted = unsafe { dart_api::new_persistent_handle(val) };
751 ptr::NonNull::from(Box::leak(Box::new(persisted)))
752}
753
754#[unsafe(no_mangle)]
756pub unsafe extern "C" fn box_foreign_value(
757 val: DartValue,
758) -> ptr::NonNull<DartValue> {
759 ptr::NonNull::from(Box::leak(Box::new(val)))
760}
761
762pub type FrbHandler = SimpleHandler<
765 SimpleExecutor<
766 NoOpErrorListener,
767 SimpleThreadPool,
768 UnreachableAsyncRuntime,
769 >,
770 NoOpErrorListener,
771>;
772
773#[must_use]
775pub fn new_frb_handler() -> FrbHandler {
776 SimpleHandler::new(
777 SimpleExecutor::new(
778 NoOpErrorListener,
779 SimpleThreadPool,
780 UnreachableAsyncRuntime,
781 ),
782 NoOpErrorListener,
783 )
784}
785
786#[derive(Debug, Copy, Clone)]
788pub struct UnreachableAsyncRuntime;
789
790impl BaseAsyncRuntime for UnreachableAsyncRuntime {
791 fn spawn<F>(&self, _: F) -> JoinHandle<F::Output>
792 where
793 F: Future<Output: Send + 'static> + Send + 'static,
794 {
795 unreachable!("no async runtime available")
800 }
801}
802
803#[cfg(feature = "mockable")]
804#[expect(clippy::missing_docs_in_private_items, reason = "for testing only")]
805mod dart_value_extern_tests_helpers {
806 use super::propagate_panic;
807 use crate::platform::set_panic_hook;
808
809 #[unsafe(no_mangle)]
810 pub unsafe extern "C" fn fire_panic() {
811 set_panic_hook();
812 propagate_panic(|| panic!("Panicking"));
813 }
814}