thlorenz / rid

Rust integrated Dart framework providing an easy way to build Flutter apps with Rust.
64 stars 4 forks source link

Some insights on implementing rid::model manually / for third-party crate defined types ? #56

Closed Roms1383 closed 2 years ago

Roms1383 commented 2 years ago

When using third-party crate (e.g. uuid::Uuid) for field(s) in struct(s) annotated with #[rid::model] it doesn't compile since Rid knows nothing about these external types.

I'm currently looking for manually implementing rid::model or maybe there's another better solution ?

Roms1383 commented 2 years ago

To avoid having to check, I just made a quick test with well-known types, so for example given:

/// highlight the issue when using third-party crate defined type in field
/// 
/// ```compile_fail
/// use uuid::Uuid;
/// #[rid::model]
/// pub struct Model {
///   pub id: i32,
///   pub name: String,
///   pub uuid: Uuid,
/// }
/// ```
#[rid::model]
pub struct Model {
  pub id: i32,
  pub name: String,
}

Roughly when I cargo expand the previous simple #[rid::model] annotated struct, this is what I get (stripped the comments out for brevity):

#![feature(prelude_import)]
#[prelude_import]
use std::prelude::rust_2021::*;
#[macro_use]
extern crate std;
pub struct Model {
    pub id: i32,
    pub name: String,
}
#[allow(non_snake_case, non_camel_case_types, unused_imports)]
mod __rid_Model_dart_mod {
    #[no_mangle]
    pub extern "C" fn _to_dart_for_Model() {}
}
mod __model_field_access {
    use super::*;
    #[no_mangle]
    #[allow(non_snake_case, non_camel_case_types, unused_imports)]
    pub extern "C" fn rid_model_id(ptr: *mut Model) -> i32 {
        let receiver = unsafe {
            if !!ptr.is_null() {
                ::core::panicking::panic("assertion failed: !ptr.is_null()")
            };
            let ptr: *mut Model = &mut *ptr;
            ptr.as_mut().expect("resolve_ptr.as_mut failed")
        };
        receiver.id
    }
    #[no_mangle]
    #[allow(non_snake_case, non_camel_case_types, unused_imports)]
    pub extern "C" fn rid_model_name(ptr: *mut Model) -> *const ::std::os::raw::c_char {
        let receiver = unsafe {
            if !!ptr.is_null() {
                ::core::panicking::panic("assertion failed: !ptr.is_null()")
            };
            let ptr: *mut Model = &mut *ptr;
            ptr.as_mut().expect("resolve_ptr.as_mut failed")
        };
        let cstring = ::std::ffi::CString::new(receiver.name.as_str()).expect(&{
            let res = ::alloc::fmt::format(::core::fmt::Arguments::new_v1(
                &["Invalid string encountered"],
                &match () {
                    () => [],
                },
            ));
            res
        });
        cstring.into_raw()
    }
    #[no_mangle]
    #[allow(non_snake_case, non_camel_case_types, unused_imports)]
    pub extern "C" fn rid_model_name_len(ptr: *mut Model) -> usize {
        let receiver = unsafe {
            if !!ptr.is_null() {
                ::core::panicking::panic("assertion failed: !ptr.is_null()")
            };
            let ptr: *mut Model = &mut *ptr;
            ptr.as_mut().expect("resolve_ptr.as_mut failed")
        };
        receiver.name.len()
    }
}
mod __rid_utils_module {
    #[no_mangle]
    pub struct str {}
    #[no_mangle]
    pub struct CString {}
    #[no_mangle]
    pub extern "C" fn rid_cstring_free(ptr: *mut ::std::os::raw::c_char) {
        if !ptr.is_null() {
            ::core::mem::drop(unsafe { ::std::ffi::CString::from_raw(ptr) });
        }
    }
    #[no_mangle]
    pub extern "C" fn rid_init_msg_isolate(port: i64) {
        rid::_init_msg_isolate(port)
    }
    #[no_mangle]
    pub extern "C" fn rid_init_reply_isolate(port: i64) {
        rid::_init_reply_isolate(port)
    }
}

I guess there's no associated trait, so wondering if writing all manually is a good idea. How would you address this kind of external newtype pattern (since Uuid is simply wrapping [u8;16]) @thlorenz ?

Roms1383 commented 2 years ago

By the way I know I can cast my struct into another "#[rid::model] types-compliant only" struct (and that's probably what I'm gonna do at the moment), but actually I'm also quite curious to know if there's an alternative.

thlorenz commented 2 years ago

Non model structs aren't directly supported yet, just primitives, vecs, hasmaps and structs that you declare and annotate with rid::model.

Rid will have to be taught how to handle each new data type we try to support

thlorenz commented 2 years ago

Casting into a model struct is the way to go for now.

Roms1383 commented 2 years ago

Ok 👌