Michael-F-Bryan / ffi_helpers

A crate to make working with FFI code easier.
MIT License
67 stars 6 forks source link

split_closure with reverse order #1

Open andoriyu opened 4 years ago

andoriyu commented 4 years ago

Hello, sweet library that I've discovered just in time. However, C function I'm working is passes user data as last argument.

Is it possible to add another function to support that use case?

Michael-F-Bryan commented 4 years ago

One way this could be implemented is to add some sort of trailing_data_trampoline() method and a TrailingDataTrampoline associated type to the Split trait. This would return a "trampoline" function that accepts the user data pointer as the last argument.

I'd be happy to mentor a PR if you are interested in implementing this.

andoriyu commented 4 years ago

Yeah, I'm interested. I made trampoline already for my use case, but that one is specific to my function.

On Wed, Apr 8, 2020, 1:04 AM Michael Bryan notifications@github.com wrote:

One way this could be implemented is to add some sort of trailing_data_trampoline() method and a TrailingDataTrampoline associated type to the Split trait https://github.com/Michael-F-Bryan/ffi_helpers/blob/master/src/split.rs. This would return a "trampoline" function that accepts the user data pointer as the last argument.

I'd be happy to mentor a PR if you are interested in implementing this.

— You are receiving this because you authored the thread. Reply to this email directly, view it on GitHub https://github.com/Michael-F-Bryan/ffi_helpers/issues/1#issuecomment-610814288, or unsubscribe https://github.com/notifications/unsubscribe-auth/AABEFGZIN3X44HBWLMNPKOLRLQVY7ANCNFSM4MDSXGZQ .

timfish commented 3 years ago

I've been trying to modify your macro for use with trailing c_void but the compiler is still giving me errors. This is probably because I have no idea what I'm doing and have just been hacking around!

What is that I don't understand about dealing with code after the trailing repeated identifiers? I haven't been able to find any docs or examples to help...

This:

macro_rules! impl_split {
    ($( $outer:ident ),* ; $( $inner:ident ),*) => {
        impl<Func, Ret, $($outer),*> Split<($( $outer, )*), Ret> for Func
        where
            Func: FnMut($($outer),*) -> Ret,
        {
            type Trampoline = unsafe extern "C" fn($($outer),*, *mut c_void) -> Ret;

            fn trampoline() -> Self::Trampoline {
                // declare a trampoline function which will turn our pointer
                // back into an `F` and invoke it

                // Note: we're deliberately using `$inner` to generate an ident
                // for the argument
                #[allow(non_snake_case)]
                unsafe extern "C" fn trampoline<T, Ret_, $( $inner ),*>($($inner: $inner),* ptr: *mut c_void) -> Ret_
                where
                    T: FnMut($($inner),*) -> Ret_,
                {
                    debug_assert!(!ptr.is_null());

                    let callback: &mut T = &mut *(ptr as *mut T);

                    callback($($inner),*)
                }

                trampoline::<Func, Ret, $($outer,)*>
            }
        }
    };
}

Gives me two errors. I've tried all sorts of combinations of coma etc and it doesn't seem to want comma anywhere 🤷‍♂️


error: expected argument name, found `,`
   |
22 |             type Trampoline = unsafe extern "C" fn($($outer),*, *mut c_void) -> Ret;
   |                                                               ^ expected argument name

error: expected one of `!`, `(`, `)`, `+`, `,`, `::`, or `<`, found `ptr`
   |
31 |                 unsafe extern "C" fn trampoline<T, Ret_, $( $inner ),*>($($inner: $inner),* ptr: *mut c_void) -> Ret_
   |                                                                                         -   ^^^ expected one of 7 possible tokens
   |                                                                                         |
   |                                                                                         help: missing `,`
...
timfish commented 3 years ago

As is generally always the case, I managed to get it working shortly after posting the above:

macro_rules! impl_split {
    ($( $outer:ident ),* ; $( $inner:ident ),*) => {
        impl<Func, Ret, $($outer),*> Split<($( $outer, )*), Ret> for Func
        where
            Func: FnMut($($outer),*) -> Ret,
        {
            type Trampoline = unsafe extern "C" fn($($outer,)* *mut c_void) -> Ret;

            fn trampoline() -> Self::Trampoline {
                // declare a trampoline function which will turn our pointer
                // back into an `F` and invoke it

                // Note: we're deliberately using `$inner` to generate an ident
                // for the argument
                #[allow(non_snake_case)]
                unsafe extern "C" fn trampoline<T, Ret_, $( $inner ),*>($($inner: $inner,)* ptr: *mut c_void) -> Ret_
                where
                    T: FnMut($($inner),*) -> Ret_,
                {
                    debug_assert!(!ptr.is_null());

                    let callback: &mut T = &mut *(ptr as *mut T);

                    callback($($inner),*)
                }

                trampoline::<Func, Ret, $($outer,)*>
            }
        }
    };
}
anzbert commented 2 years ago

Hi ! This feature would be great to have. Is it still on the agenda?

edit: Thx @timfish ! For the moment i just forked this rep and replaced the macro with your version. Works great. 😄 I wish I was more prolific in Rust yet so I could help with a trait and a PR, but macros are still a bit too much for me.

anzbert commented 2 years ago

One way this could be implemented is to add some sort of trailing_data_trampoline() method and a TrailingDataTrampoline associated type to the Split trait. This would return a "trampoline" function that accepts the user data pointer as the last argument.

I'd be happy to mentor a PR if you are interested in implementing this.

Hey @Michael-F-Bryan

I went ahead and implemented the trait and another split function. Submitting a pull request and I am looking forward to your input. You seem to be very experienced in Rust and I am always happy to learn some more.

I've seen on your blog that you are also from Perth. What a coincidence 😁. Alrighty, that's it for now...