rustffiglib

How to convert a slice of GObjects as a GList to a FFI function from Rust?


I am trying to pass a GObject to a FFI function from libsecret-1 which requires it be in a GList. I have some code that almost compiles, but it complains about the lifetime of the borrowed vaue being too short and not outliving the function. The object itself was created from the FFI using the wrapper! macro from the glib crate for Rust. Here is a minimum-viable reproduction that produces the error I am getting:

extern crate glib;                                                                                                                                                                            
                                                                                                                                                                                              
use glib::ffi::GList;
use glib::translate::{ToGlibPtr, GlibPtrDefault, ToGlibContainerFromSlice};

pub fn lock_object_test<'a, W: GlibPtrDefault +
  ToGlibPtr<'a, <W as GlibPtrDefault>::GlibType>>(obj: &'a W) {
    let arr = [obj];
    let slice: (*mut GList, <&W as ToGlibContainerFromSlice<'a, *mut GList>>::Storage) = 
        ToGlibContainerFromSlice::to_glib_none_from_slice(&arr[..]);
    // Would pass slice.0 here as a *mut GList argument to FFI
}

The GList should just be a shared reference that is only needed for the duration of the call to the FFI function so I am not sure why it thinks the lifetime need to live beyond the function. The error triggers on the &arr[..] due to it being borrowed for longer than the life of arr.

Also, any tips on how to make this less wordy would be nice.


Solution

  • The problem is you specify the caller can choose a lifetime 'a for which all of these bounds have to hold, but the caller can only specify lifetimes that live from before the call to after the function returned. But arr doesn't live that long.

    You can use higher ranked trait bounds (HRTB) to specify that W has to implement ToGlibPtr for any lifetime, not just lifetimes specified by the caller.

    use glib::ffi::GList;
    use glib::translate::{GlibPtrDefault, ToGlibPtr, ToGlibContainerFromSlice};
    pub fn lock_object_test<W> (obj: &W)
    where
        for<'a> W: GlibPtrDefault + ToGlibPtr<'a, <W as GlibPtrDefault>::GlibType>
    {
        let arr = [obj];
        let (ptr, _zstorage): (*mut GList, <&W as ToGlibContainerFromSlice<*mut GList>>::Storage) = 
            ToGlibContainerFromSlice::to_glib_none_from_slice(&arr[..]);
        // pass ptr here as a *mut GList argument to FFI
    }