thlorenz / rid

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

feat: export hash map reference #21

Closed thlorenz closed 2 years ago

thlorenz commented 2 years ago

Summary

This PR adds the ability to export a reference to a hash map field. So far only HashMap<u8, u8> has been tested in order to have the generals worked out. More types will be added later as this PR is now large enough :)

First Use of Recursive rid Macro Expansion

In order to allow iterating the keys of the hash_map we use the first case of applying [rid::export] recursively. Thus this access is simply implemented by emitting the following:

let keys_impl = quote_spanned! { fn_keys_ident.span() =>
    #[rid::export]
    fn #fn_keys_ident(map: &HashMap<#key_ty, #val_ty>) -> Vec<&#key_ty> {
        map.keys().collect()
    }
};

I first tried a different route (visible from some of the commits) to fully render the method returning a RidVec and rendering the access to RidVecs via nested accesses.

However the final solution turned out to be so much simpler and basically is the first example of using rid features we can already render like a Lego piece in order to render higher level types and implementations. I plan to use this approach in more cases going forward.

Standalone Export as part of this PR

However to make this happen I had to implement standalone [rid::export]s. Up til now only exports that were part of an impl were allowed since I couldn't think of a clean way to prevent a rid::export to be rendered twice (once as part of the impl and once treated separately).

I now track exports that we rendered as an impl method and skip rendering it again, see 631701d.

Potential Future Issues

This works, but would hide a user error in which a method/function with the same name is once exported as an impl and then again as a separate method, i.e. it doesn't raise an error, but just ignores the second one, as in this example:


#[rid::export]
impl Store {
    #[rid::export]
    pub fn get_u8(&self) -> u8 {
        self.s_id
    }
}

// The below method is not exported, i.e. no rid ffi wrapper generated, nor any error/warning
// for the user is emitted.
#[rid::export]
pub fn get_u8() -> u8 {
  1 
}

If this causes lots of issues (which I don't really doubt) we'll have to take the tokens of the function into account in order to alert the user when two functions have a name colission.

Follow Up PR

As mentioned above this PR will be followed up with one that adds support for more HashMap key/val types.

Related Future Features

After that the following related features are on my radar.

However before I'll implement another sample app, this time to show off and battle test exporting HashMaps.

Commits

thlorenz commented 2 years ago

@chertov could you please verify that this addresses your needs (you mentioned here https://github.com/thlorenz/rid/issues/5)? Which key/val types are most important for you? I'm planning to focus on the following two for now HashMap<String, String>, HashMap<String, struct> and hash maps with primitive keys/values.