1use crate::{
25 check_remaining, derive_ffi_traits, ffi_converter_rust_buffer_lift_and_lower, metadata,
26 ConvertError, FfiConverter, Lift, LiftRef, LiftReturn, Lower, LowerError, LowerReturn,
27 MetadataBuffer, Result, RustBuffer, RustCallError, TypeId, UnexpectedUniFFICallbackError,
28};
29use anyhow::bail;
30use bytes::buf::{Buf, BufMut};
31use std::{
32 collections::HashMap,
33 convert::TryFrom,
34 fmt::{Debug, Display},
35 sync::Arc,
36 time::{Duration, SystemTime},
37};
38
39macro_rules! impl_ffi_converter_for_num_primitive {
44 ($T:ty, $type_code:expr, $get:ident, $put:ident) => {
45 unsafe impl<UT> FfiConverter<UT> for $T {
46 type FfiType = $T;
47
48 fn lower(obj: $T) -> Self::FfiType {
49 obj
50 }
51
52 fn try_lift(v: Self::FfiType) -> Result<$T> {
53 Ok(v)
54 }
55
56 fn write(obj: $T, buf: &mut Vec<u8>) {
57 buf.$put(obj);
58 }
59
60 fn try_read(buf: &mut &[u8]) -> Result<$T> {
61 check_remaining(buf, std::mem::size_of::<$T>())?;
62 Ok(buf.$get())
63 }
64
65 const TYPE_ID_META: MetadataBuffer = MetadataBuffer::from_code($type_code);
66 }
67 };
68}
69
70impl_ffi_converter_for_num_primitive!(u8, metadata::codes::TYPE_U8, get_u8, put_u8);
71impl_ffi_converter_for_num_primitive!(i8, metadata::codes::TYPE_I8, get_i8, put_i8);
72impl_ffi_converter_for_num_primitive!(u16, metadata::codes::TYPE_U16, get_u16, put_u16);
73impl_ffi_converter_for_num_primitive!(i16, metadata::codes::TYPE_I16, get_i16, put_i16);
74impl_ffi_converter_for_num_primitive!(u32, metadata::codes::TYPE_U32, get_u32, put_u32);
75impl_ffi_converter_for_num_primitive!(i32, metadata::codes::TYPE_I32, get_i32, put_i32);
76impl_ffi_converter_for_num_primitive!(u64, metadata::codes::TYPE_U64, get_u64, put_u64);
77impl_ffi_converter_for_num_primitive!(i64, metadata::codes::TYPE_I64, get_i64, put_i64);
78impl_ffi_converter_for_num_primitive!(f32, metadata::codes::TYPE_F32, get_f32, put_f32);
79impl_ffi_converter_for_num_primitive!(f64, metadata::codes::TYPE_F64, get_f64, put_f64);
80
81unsafe impl<UT> FfiConverter<UT> for bool {
86 type FfiType = i8;
87
88 fn lower(obj: bool) -> Self::FfiType {
89 i8::from(obj)
90 }
91
92 fn try_lift(v: Self::FfiType) -> Result<bool> {
93 Ok(match v {
94 0 => false,
95 1 => true,
96 _ => bail!("unexpected byte for Boolean"),
97 })
98 }
99
100 fn write(obj: bool, buf: &mut Vec<u8>) {
101 buf.put_i8(<Self as FfiConverter<UT>>::lower(obj));
102 }
103
104 fn try_read(buf: &mut &[u8]) -> Result<bool> {
105 check_remaining(buf, 1)?;
106 <Self as FfiConverter<UT>>::try_lift(buf.get_i8())
107 }
108
109 const TYPE_ID_META: MetadataBuffer = MetadataBuffer::from_code(metadata::codes::TYPE_BOOL);
110}
111
112unsafe impl<UT> FfiConverter<UT> for String {
124 type FfiType = RustBuffer;
125
126 fn lower(obj: String) -> Self::FfiType {
130 RustBuffer::from_vec(obj.into_bytes())
131 }
132
133 fn try_lift(v: Self::FfiType) -> Result<String> {
136 let v = v.destroy_into_vec();
137 Ok(unsafe { String::from_utf8_unchecked(v) })
143 }
144
145 fn write(obj: String, buf: &mut Vec<u8>) {
146 let len = i32::try_from(obj.len()).unwrap();
149 buf.put_i32(len); buf.put(obj.as_bytes());
151 }
152
153 fn try_read(buf: &mut &[u8]) -> Result<String> {
154 check_remaining(buf, 4)?;
155 let len = usize::try_from(buf.get_i32())?;
156 check_remaining(buf, len)?;
157 let bytes = &buf.chunk()[..len];
161 let res = String::from_utf8(bytes.to_vec())?;
162 buf.advance(len);
163 Ok(res)
164 }
165
166 const TYPE_ID_META: MetadataBuffer = MetadataBuffer::from_code(metadata::codes::TYPE_STRING);
167}
168
169unsafe impl<UT> FfiConverter<UT> for SystemTime {
184 ffi_converter_rust_buffer_lift_and_lower!(UT);
185
186 fn write(obj: SystemTime, buf: &mut Vec<u8>) {
187 let mut sign = 1;
188 let epoch_offset = obj
189 .duration_since(SystemTime::UNIX_EPOCH)
190 .unwrap_or_else(|error| {
191 sign = -1;
192 error.duration()
193 });
194 let seconds = sign
196 * i64::try_from(epoch_offset.as_secs())
197 .expect("SystemTime overflow, seconds greater than i64::MAX");
198
199 buf.put_i64(seconds);
200 buf.put_u32(epoch_offset.subsec_nanos());
201 }
202
203 fn try_read(buf: &mut &[u8]) -> Result<SystemTime> {
204 check_remaining(buf, 12)?;
205 let seconds = buf.get_i64();
206 let nanos = buf.get_u32();
207 let epoch_offset = Duration::new(seconds.wrapping_abs() as u64, nanos);
208
209 if seconds >= 0 {
210 Ok(SystemTime::UNIX_EPOCH + epoch_offset)
211 } else {
212 Ok(SystemTime::UNIX_EPOCH - epoch_offset)
213 }
214 }
215
216 const TYPE_ID_META: MetadataBuffer =
217 MetadataBuffer::from_code(metadata::codes::TYPE_SYSTEM_TIME);
218}
219
220unsafe impl<UT> FfiConverter<UT> for Duration {
229 ffi_converter_rust_buffer_lift_and_lower!(UT);
230
231 fn write(obj: Duration, buf: &mut Vec<u8>) {
232 buf.put_u64(obj.as_secs());
233 buf.put_u32(obj.subsec_nanos());
234 }
235
236 fn try_read(buf: &mut &[u8]) -> Result<Duration> {
237 check_remaining(buf, 12)?;
238 Ok(Duration::new(buf.get_u64(), buf.get_u32()))
239 }
240
241 const TYPE_ID_META: MetadataBuffer = MetadataBuffer::from_code(metadata::codes::TYPE_DURATION);
242}
243
244unsafe impl<UT, T: Lower<UT>> Lower<UT> for Option<T> {
255 type FfiType = RustBuffer;
256
257 fn write(obj: Option<T>, buf: &mut Vec<u8>) {
258 match obj {
259 None => buf.put_i8(0),
260 Some(v) => {
261 buf.put_i8(1);
262 T::write(v, buf);
263 }
264 }
265 }
266
267 fn lower(obj: Option<T>) -> RustBuffer {
268 Self::lower_into_rust_buffer(obj)
269 }
270}
271
272unsafe impl<UT, T: Lift<UT>> Lift<UT> for Option<T> {
273 type FfiType = RustBuffer;
274
275 fn try_read(buf: &mut &[u8]) -> Result<Option<T>> {
276 check_remaining(buf, 1)?;
277 Ok(match buf.get_i8() {
278 0 => None,
279 1 => Some(T::try_read(buf)?),
280 _ => bail!("unexpected tag byte for Option"),
281 })
282 }
283
284 fn try_lift(buf: RustBuffer) -> Result<Option<T>> {
285 Self::try_lift_from_rust_buffer(buf)
286 }
287}
288
289impl<UT, T: TypeId<UT>> TypeId<UT> for Option<T> {
290 const TYPE_ID_META: MetadataBuffer =
291 MetadataBuffer::from_code(metadata::codes::TYPE_OPTION).concat(T::TYPE_ID_META);
292}
293
294unsafe impl<UT, T: Lower<UT>> Lower<UT> for Vec<T> {
305 type FfiType = RustBuffer;
306
307 fn write(obj: Vec<T>, buf: &mut Vec<u8>) {
308 let len = i32::try_from(obj.len()).unwrap();
310 buf.put_i32(len); for item in obj {
312 <T as Lower<UT>>::write(item, buf);
313 }
314 }
315
316 fn lower(obj: Vec<T>) -> RustBuffer {
317 Self::lower_into_rust_buffer(obj)
318 }
319}
320
321unsafe impl<UT, T: Lift<UT>> Lift<UT> for Vec<T> {
327 type FfiType = RustBuffer;
328
329 fn try_read(buf: &mut &[u8]) -> Result<Vec<T>> {
330 check_remaining(buf, 4)?;
331 let len = usize::try_from(buf.get_i32())?;
332 let mut vec = Vec::with_capacity(len);
333 for _ in 0..len {
334 vec.push(<T as Lift<UT>>::try_read(buf)?)
335 }
336 Ok(vec)
337 }
338
339 fn try_lift(buf: RustBuffer) -> Result<Vec<T>> {
340 Self::try_lift_from_rust_buffer(buf)
341 }
342}
343
344impl<UT, T: TypeId<UT>> TypeId<UT> for Vec<T> {
345 const TYPE_ID_META: MetadataBuffer =
346 MetadataBuffer::from_code(metadata::codes::TYPE_VEC).concat(T::TYPE_ID_META);
347}
348
349unsafe impl<K, V, UT> Lower<UT> for HashMap<K, V>
350where
351 K: Lower<UT> + std::hash::Hash + Eq,
352 V: Lower<UT>,
353{
354 type FfiType = RustBuffer;
355
356 fn write(obj: HashMap<K, V>, buf: &mut Vec<u8>) {
357 let len = i32::try_from(obj.len()).unwrap();
359 buf.put_i32(len); for (key, value) in obj {
361 <K as Lower<UT>>::write(key, buf);
362 <V as Lower<UT>>::write(value, buf);
363 }
364 }
365
366 fn lower(obj: HashMap<K, V>) -> RustBuffer {
367 Self::lower_into_rust_buffer(obj)
368 }
369}
370
371unsafe impl<K, V, UT> Lift<UT> for HashMap<K, V>
372where
373 K: Lift<UT> + std::hash::Hash + Eq,
374 V: Lift<UT>,
375{
376 type FfiType = RustBuffer;
377
378 fn try_read(buf: &mut &[u8]) -> Result<HashMap<K, V>> {
379 check_remaining(buf, 4)?;
380 let len = usize::try_from(buf.get_i32())?;
381 let mut map = HashMap::with_capacity(len);
382 for _ in 0..len {
383 let key = <K as Lift<UT>>::try_read(buf)?;
384 let value = <V as Lift<UT>>::try_read(buf)?;
385 map.insert(key, value);
386 }
387 Ok(map)
388 }
389
390 fn try_lift(buf: RustBuffer) -> Result<HashMap<K, V>> {
391 Self::try_lift_from_rust_buffer(buf)
392 }
393}
394
395impl<K, V, UT> TypeId<UT> for HashMap<K, V>
396where
397 K: TypeId<UT> + std::hash::Hash + Eq,
398 V: TypeId<UT>,
399{
400 const TYPE_ID_META: MetadataBuffer = MetadataBuffer::from_code(metadata::codes::TYPE_HASH_MAP)
401 .concat(K::TYPE_ID_META)
402 .concat(V::TYPE_ID_META);
403}
404
405derive_ffi_traits!(blanket u8);
406derive_ffi_traits!(blanket i8);
407derive_ffi_traits!(blanket u16);
408derive_ffi_traits!(blanket i16);
409derive_ffi_traits!(blanket u32);
410derive_ffi_traits!(blanket i32);
411derive_ffi_traits!(blanket u64);
412derive_ffi_traits!(blanket i64);
413derive_ffi_traits!(blanket f32);
414derive_ffi_traits!(blanket f64);
415derive_ffi_traits!(blanket bool);
416derive_ffi_traits!(blanket String);
417derive_ffi_traits!(blanket Duration);
418derive_ffi_traits!(blanket SystemTime);
419
420derive_ffi_traits!(impl<T, UT> LowerReturn<UT> for Option<T> where Option<T>: Lower<UT>);
425derive_ffi_traits!(impl<T, UT> LowerError<UT> for Option<T> where Option<T>: Lower<UT>);
426derive_ffi_traits!(impl<T, UT> LiftReturn<UT> for Option<T> where Option<T>: Lift<UT>);
427derive_ffi_traits!(impl<T, UT> LiftRef<UT> for Option<T> where Option<T>: Lift<UT>);
428
429derive_ffi_traits!(impl<T, UT> LowerReturn<UT> for Vec<T> where Vec<T>: Lower<UT>);
430derive_ffi_traits!(impl<T, UT> LowerError<UT> for Vec<T> where Vec<T>: Lower<UT>);
431derive_ffi_traits!(impl<T, UT> LiftReturn<UT> for Vec<T> where Vec<T>: Lift<UT>);
432derive_ffi_traits!(impl<T, UT> LiftRef<UT> for Vec<T> where Vec<T>: Lift<UT>);
433
434derive_ffi_traits!(impl<K, V, UT> LowerReturn<UT> for HashMap<K, V> where HashMap<K, V>: Lower<UT>);
435derive_ffi_traits!(impl<K, V, UT> LowerError<UT> for HashMap<K, V> where HashMap<K, V>: Lower<UT>);
436derive_ffi_traits!(impl<K, V, UT> LiftReturn<UT> for HashMap<K, V> where HashMap<K, V>: Lift<UT>);
437derive_ffi_traits!(impl<K, V, UT> LiftRef<UT> for HashMap<K, V> where HashMap<K, V>: Lift<UT>);
438
439derive_ffi_traits!(impl<T, UT> Lower<UT> for Arc<T> where Arc<T>: FfiConverter<UT>, T: ?Sized);
441derive_ffi_traits!(impl<T, UT> Lift<UT> for Arc<T> where Arc<T>: FfiConverter<UT>, T: ?Sized);
442derive_ffi_traits!(impl<T, UT> LowerReturn<UT> for Arc<T> where Arc<T>: Lower<UT>, T: ?Sized);
443derive_ffi_traits!(impl<T, UT> LowerError<UT> for Arc<T> where Arc<T>: Lower<UT>, T: ?Sized);
444derive_ffi_traits!(impl<T, UT> LiftReturn<UT> for Arc<T> where Arc<T>: Lift<UT>, T: ?Sized);
445derive_ffi_traits!(impl<T, UT> LiftRef<UT> for Arc<T> where Arc<T>: Lift<UT>, T: ?Sized);
446derive_ffi_traits!(impl<T, UT> TypeId<UT> for Arc<T> where Arc<T>: FfiConverter<UT>, T: ?Sized);
447
448unsafe impl<UT> LowerReturn<UT> for () {
451 type ReturnType = ();
452
453 fn lower_return(_: ()) -> Result<Self::ReturnType, RustCallError> {
454 Ok(())
455 }
456}
457
458unsafe impl<UT> LiftReturn<UT> for () {
459 type ReturnType = ();
460
461 fn try_lift_successful_return(_: ()) -> Result<Self> {
462 Ok(())
463 }
464}
465
466impl<UT> TypeId<UT> for () {
467 const TYPE_ID_META: MetadataBuffer = MetadataBuffer::from_code(metadata::codes::TYPE_UNIT);
468}
469
470#[cfg(not(all(target_arch = "wasm32", feature = "wasm-unstable-single-threaded")))]
474unsafe impl<UT, R, E> LowerReturn<UT> for Result<R, E>
475where
476 R: LowerReturn<UT>,
477 E: LowerError<UT> + Display + Debug + Send + Sync + 'static,
478{
479 type ReturnType = R::ReturnType;
480
481 fn lower_return(v: Self) -> Result<Self::ReturnType, RustCallError> {
482 match v {
483 Ok(r) => R::lower_return(r),
484 Err(e) => Err(RustCallError::Error(E::lower_error(e))),
485 }
486 }
487
488 fn handle_failed_lift(error: crate::LiftArgsError) -> Result<Self::ReturnType, RustCallError> {
489 let crate::LiftArgsError { arg_name, error } = error;
490
491 let error = match error.downcast::<E>() {
492 Ok(user) => RustCallError::Error(<E as LowerError<UT>>::lower_error(user)),
493 Err(error) => crate::LiftArgsError { arg_name, error }.to_internal_error(),
494 };
495
496 Err(error)
497 }
498}
499
500#[cfg(all(target_arch = "wasm32", feature = "wasm-unstable-single-threaded"))]
501unsafe impl<UT, R, E> LowerReturn<UT> for Result<R, E>
502where
503 R: LowerReturn<UT>,
504 E: LowerError<UT> + Display + Debug + 'static,
505{
506 type ReturnType = R::ReturnType;
507
508 fn lower_return(v: Self) -> Result<Self::ReturnType, RustCallError> {
509 match v {
510 Ok(r) => R::lower_return(r),
511 Err(e) => Err(RustCallError::Error(E::lower_error(e))),
512 }
513 }
514}
515
516unsafe impl<UT, R, E> LiftReturn<UT> for Result<R, E>
517where
518 R: LiftReturn<UT>,
519 E: Lift<UT, FfiType = RustBuffer> + ConvertError<UT>,
520{
521 type ReturnType = R::ReturnType;
522
523 fn try_lift_successful_return(v: R::ReturnType) -> Result<Self> {
524 R::try_lift_successful_return(v).map(Ok)
525 }
526
527 fn lift_error(buf: RustBuffer) -> Self {
528 match E::try_lift_from_rust_buffer(buf) {
529 Ok(lifted_error) => Err(lifted_error),
530 Err(anyhow_error) => {
531 Self::handle_callback_unexpected_error(UnexpectedUniFFICallbackError {
532 reason: format!("Error lifting from rust buffer: {anyhow_error}"),
533 })
534 }
535 }
536 }
537
538 fn handle_callback_unexpected_error(e: UnexpectedUniFFICallbackError) -> Self {
539 Err(E::try_convert_unexpected_callback_error(e).unwrap_or_else(|e| panic!("{e}")))
540 }
541}
542
543impl<UT, R, E> TypeId<UT> for Result<R, E>
544where
545 R: TypeId<UT>,
546 E: TypeId<UT>,
547{
548 const TYPE_ID_META: MetadataBuffer = MetadataBuffer::from_code(metadata::codes::TYPE_RESULT)
549 .concat(R::TYPE_ID_META)
550 .concat(E::TYPE_ID_META);
551}
552
553unsafe impl<T, UT> LiftRef<UT> for [T]
554where
555 T: Lift<UT>,
556{
557 type LiftType = Vec<T>;
558}
559
560unsafe impl<UT> LiftRef<UT> for str {
561 type LiftType = String;
562}