flutter_rust_bridge/misc/
into_into_dart.rs

1use crate::codec::BaseCodec;
2use crate::for_generated::{BaseArc, StreamSinkBase};
3use crate::generalized_isolate::{IntoDart, ZeroCopyBuffer};
4#[cfg(feature = "rust-async")]
5use crate::rust_auto_opaque::{inner::RustAutoOpaqueInner, RustAutoOpaqueBase};
6use crate::rust_opaque::RustOpaqueBase;
7use std::collections::{HashMap, HashSet};
8
9/// Basically the Into trait.
10///
11/// We need this separate trait because we need to implement it for Vec<T> etc.
12/// These blanket implementations allow us to accept external types in various places.
13/// The initial reason for this was to allow mirrored types in StreamSink<>.
14/// See also [PR 1285](https://github.com/fzyzcjy/flutter_rust_bridge/pull/1285)
15pub trait IntoIntoDart<D: IntoDart> {
16    fn into_into_dart(self) -> D;
17}
18
19impl<T, D> IntoIntoDart<Vec<D>> for Vec<T>
20where
21    T: IntoIntoDart<D>,
22    Vec<D>: IntoDart,
23    D: IntoDart,
24{
25    #[inline(always)]
26    fn into_into_dart(self) -> Vec<D> {
27        self.into_iter().map(|e| e.into_into_dart()).collect()
28    }
29}
30
31impl<T, D> IntoIntoDart<Option<D>> for Option<T>
32where
33    T: IntoIntoDart<D>,
34    D: IntoDart,
35{
36    #[inline(always)]
37    fn into_into_dart(self) -> Option<D> {
38        self.map(|e| e.into_into_dart())
39    }
40}
41
42impl<T, A: BaseArc<T>> IntoIntoDart<RustOpaqueBase<T, A>> for RustOpaqueBase<T, A> {
43    #[inline(always)]
44    fn into_into_dart(self) -> RustOpaqueBase<T, A> {
45        self
46    }
47}
48
49#[cfg(feature = "rust-async")]
50impl<T, A: BaseArc<RustAutoOpaqueInner<T>>> IntoIntoDart<RustAutoOpaqueBase<T, A>>
51    for RustAutoOpaqueBase<T, A>
52{
53    #[inline(always)]
54    fn into_into_dart(self) -> RustAutoOpaqueBase<T, A> {
55        self
56    }
57}
58
59impl<T, D> IntoIntoDart<ZeroCopyBuffer<D>> for ZeroCopyBuffer<T>
60where
61    T: IntoIntoDart<D>,
62    D: IntoDart,
63    ZeroCopyBuffer<D>: IntoDart,
64{
65    #[inline(always)]
66    fn into_into_dart(self) -> ZeroCopyBuffer<D> {
67        ZeroCopyBuffer(self.0.into_into_dart())
68    }
69}
70
71impl<T, D, const C: usize> IntoIntoDart<[D; C]> for [T; C]
72where
73    T: IntoIntoDart<D>,
74    [D; C]: IntoDart,
75    D: IntoDart,
76{
77    #[inline(always)]
78    fn into_into_dart(self) -> [D; C] {
79        self.map(|e| e.into_into_dart())
80    }
81}
82
83impl<T, D> IntoIntoDart<D> for Box<T>
84where
85    T: IntoIntoDart<D>,
86    D: IntoDart,
87{
88    #[inline(always)]
89    fn into_into_dart(self) -> D {
90        (*self).into_into_dart()
91    }
92}
93
94impl<KT, KD, VT, VD, S> IntoIntoDart<HashMap<KD, VD>> for HashMap<KT, VT, S>
95where
96    KT: IntoIntoDart<KD>,
97    VT: IntoIntoDart<VD>,
98    HashMap<KD, VD>: IntoDart,
99    KD: IntoDart + std::cmp::Eq + std::hash::Hash,
100    VD: IntoDart,
101{
102    #[inline(always)]
103    fn into_into_dart(self) -> HashMap<KD, VD> {
104        self.into_iter()
105            .map(|(k, v)| (k.into_into_dart(), v.into_into_dart()))
106            .collect()
107    }
108}
109
110impl<T, D, S> IntoIntoDart<HashSet<D>> for HashSet<T, S>
111where
112    T: IntoIntoDart<D>,
113    HashSet<D>: IntoDart,
114    D: IntoDart + Eq + std::hash::Hash,
115{
116    #[inline(always)]
117    fn into_into_dart(self) -> HashSet<D> {
118        self.into_iter().map(|e| e.into_into_dart()).collect()
119    }
120}
121
122// frb-coverage:ignore-start
123impl<T, Rust2DartCodec: BaseCodec> IntoIntoDart<StreamSinkBase<T, Rust2DartCodec>>
124    for StreamSinkBase<T, Rust2DartCodec>
125{
126    fn into_into_dart(self) -> StreamSinkBase<T, Rust2DartCodec> {
127        unreachable!()
128    }
129}
130// frb-coverage:ignore-end
131
132// ref: into_dart.rs
133macro_rules! impl_into_into_dart_for_tuple {
134    ($( ($($A:ident)+ ; $($AD:ident)+ ; $($N:tt)+) )*) => {$(
135        impl<$($A: IntoIntoDart<$AD>, $AD: IntoDart),+> IntoIntoDart<($($AD),+,)> for ($($A),+,)
136        where
137            $($A: IntoIntoDart<$AD>, $AD: IntoDart),+,
138        {
139            #[inline(always)]
140            fn into_into_dart(self) -> ($($AD),+,) {
141                (
142                    $(
143                        self.$N.into_into_dart(),
144                    )+
145                )
146            }
147        }
148    )*};
149}
150
151impl_into_into_dart_for_tuple! {
152    (A ; AD ; 0)
153    (A B ; AD BD ; 0 1)
154    (A B C ; AD BD CD ; 0 1 2)
155    (A B C D ; AD BD CD DD ; 0 1 2 3)
156    (A B C D E ; AD BD CD DD ED ; 0 1 2 3 4)
157    (A B C D E F ; AD BD CD DD ED FD ; 0 1 2 3 4 5)
158    (A B C D E F G ; AD BD CD DD ED FD GD ; 0 1 2 3 4 5 6)
159    (A B C D E F G H ; AD BD CD DD ED FD GD HD ; 0 1 2 3 4 5 6 7)
160    (A B C D E F G H I ; AD BD CD DD ED FD GD HD ID ; 0 1 2 3 4 5 6 7 8)
161    (A B C D E F G H I J ; AD BD CD DD ED FD GD HD ID JD ; 0 1 2 3 4 5 6 7 8 9)
162}
163
164// more generic impls do not work because they crate possibly conflicting trait impls
165// this is why here are some more specific impls
166
167// Implementations for simple types
168macro_rules! impl_into_into_dart_by_self {
169    ($t:ty) => {
170        impl IntoIntoDart<$t> for $t {
171            #[inline(always)]
172            fn into_into_dart(self) -> $t {
173                self
174            }
175        }
176    };
177}
178
179// Impls for primitive types are taken from the IntoDart trait
180
181impl_into_into_dart_by_self!(u8);
182impl_into_into_dart_by_self!(i8);
183impl_into_into_dart_by_self!(u16);
184impl_into_into_dart_by_self!(i16);
185impl_into_into_dart_by_self!(u32);
186impl_into_into_dart_by_self!(i32);
187impl_into_into_dart_by_self!(u64);
188impl_into_into_dart_by_self!(i64);
189impl_into_into_dart_by_self!(u128);
190impl_into_into_dart_by_self!(i128);
191impl_into_into_dart_by_self!(f32);
192impl_into_into_dart_by_self!(f64);
193impl_into_into_dart_by_self!(bool);
194impl_into_into_dart_by_self!(());
195impl_into_into_dart_by_self!(usize);
196impl_into_into_dart_by_self!(isize);
197impl_into_into_dart_by_self!(String);
198impl_into_into_dart_by_self!(char);
199#[cfg(feature = "dart-opaque")]
200impl_into_into_dart_by_self!(crate::dart_opaque::DartOpaque);
201#[cfg(not(target_family = "wasm"))]
202impl_into_into_dart_by_self!(allo_isolate::ffi::DartCObject);
203#[cfg(target_family = "wasm")]
204impl_into_into_dart_by_self!(wasm_bindgen::JsValue);
205#[cfg(feature = "uuid")]
206impl_into_into_dart_by_self!(uuid::Uuid);
207#[cfg(feature = "backtrace")]
208impl_into_into_dart_by_self!(backtrace::Backtrace);
209#[cfg(feature = "anyhow")]
210impl_into_into_dart_by_self!(anyhow::Error);
211// TODO await upstream
212// impl_into_into_dart_by_self!(std::backtrace::Backtrace);
213
214#[cfg(feature = "chrono")]
215mod chrono_impls {
216    use super::IntoIntoDart;
217    use chrono::{Local, Utc};
218    impl_into_into_dart_by_self!(chrono::Duration);
219    impl_into_into_dart_by_self!(chrono::NaiveDateTime);
220    impl_into_into_dart_by_self!(chrono::DateTime<Local>);
221    impl_into_into_dart_by_self!(chrono::DateTime<Utc>);
222}
223
224#[cfg(test)]
225mod tests {
226    #[cfg(not(target_family = "wasm"))]
227    #[test]
228    fn test_zero_copy_buffer() {
229        use crate::misc::into_into_dart::IntoIntoDart;
230        let raw: allo_isolate::ZeroCopyBuffer<Vec<u8>> = allo_isolate::ZeroCopyBuffer(vec![10]);
231        assert_eq!(raw.into_into_dart().0, vec![10]);
232    }
233}