gpt4 book ai didi

How to convert a slice of GObjects as a GList to a FFI function from Rust?(如何将GOBJECT的切片作为GLIST转换为来自Rust的FFI函数?)

转载 作者:bug小助手 更新时间:2023-10-25 21:21:08 27 4
gpt4 key购买 nike



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:

我正在尝试将一个GObject从libret-1传递给FFI函数,这要求它出现在glist中。我有一些几乎可以编译的代码,但它抱怨借用的vaue的生命周期太短,并且没有超过函数的寿命。对象本身是使用包装器从FFI创建的!从油滑的板条箱里取来的宏,用于生锈。这是一个最小可行的复制,它产生了我得到的错误:


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.

GLIST应该只是一个仅在调用FFI函数期间需要的共享引用,所以我不确定为什么它认为生存期需要存在于函数之外。错误在&arr[..]上触发因为它被借的时间比阿尔的寿命还长。


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

此外,任何关于如何让这一点不那么冗长的提示都会很好。


更多回答

@cafce25 Apologies for that oversight. I've added the missing dependencies and it compiles for me in its own, dedicated file now. I originally was going to add the use-case for slice, but that pulls in some FFI code to call a C function with several arguments and I felt added a lot of extra noise to the MVE above. Here is the function I am calling: developer-old.gnome.org/libsecret/unstable/…. I can call that function and pass ptr::null_mut() as the second argument to it as long as I comment out the line creating the GList slice.

@afce25为这一疏忽道歉。我已经添加了缺少的依赖项,现在它会在它自己的专用文件中为我编译。我最初打算添加Slice的用例,但这会引入一些FFI代码来调用带有几个参数的C函数,我觉得这会给上面的MVE增加很多额外的噪音。下面是我要调用的函数:Developer-old.gnome.org/libret/unstant/…。只要我注释掉创建GLIST切片的行,我就可以调用该函数并将ptr::ullmut()作为第二个参数传递给它。

优秀答案推荐

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.

问题是,您指定调用者可以选择所有这些界限都必须保持的生存期,但调用者只能指定从调用前到函数返回后的生存期。但arr没有那么长的生存期。


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.

您可以使用更高级别的特征界限(HRTB)来指定W必须在任何生存期内实现ToGlibPtr,而不仅仅是调用者指定的生存期。


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
}


The error you're encountering is due to Rust's borrow checker ensuring that the borrowed value (&arr[..]) doesn't outlive the reference itself (arr). In this case, Rust doesn't know how long the reference arr will be needed, so it assumes that you're trying to use the borrowed value outside its expected lifetime.

您遇到的错误是由于Rust的借用检查器确保借用的值(&[..])不会比引用本身更长久()。在这种情况下,Rust并不知道需要多长时间的引用,所以它假设你试图在其预期的生命周期之外使用借用的值。


To address this issue, you can use the std::mem::ManuallyDrop wrapper to temporarily extend the lifetime of the arr variable. Here's a modified version of your code that avoids the lifetime issue and is less wordy:

要解决此问题,您可以使用std::Mem::ManuallyDrop包装来临时延长arr变量的生命周期。以下是代码的修改版本,它避免了生命周期问题,并且不那么冗长:


use glib::translate::*;
use glib::GlibPtrDefault;
use libc::GList;
use std::mem::ManuallyDrop;

pub fn lock_object_test<'a, W>(obj: &'a W)
where
W: GlibPtrDefault + ToGlibPtr<'a, <W as GlibPtrDefault>::GlibType>,
{
// Create a ManuallyDrop to extend the lifetime of 'arr'.
let arr = ManuallyDrop::new([obj]);

// Convert the ManuallyDrop reference to a GList.
let slice = arr.as_ref();
let slice_ptr: (*mut GList, <&W as ToGlibContainerFromSlice<'a, *mut GList>>::Storage) =
ToGlibContainerFromSlice::to_glib_none_from_slice(slice);

// Pass slice_ptr.0 as a *mut GList argument to FFI.
// ...
}

fn main() {
// Example usage:
// let obj = ...; // Create your GObject here.
// lock_object_test(&obj);
}

更多回答

This exactly resolved the issue with a good explanation. It also fixes the code given in the other answer. When were HRTBs added to stable Rust?

这恰如其分地解决了问题,并做出了很好的解释。它还修复了另一个答案中给出的代码。HRTB何时被添加到稳定锈菌中?

They've always been there since 1.0. They were added in November 2014

从1.0开始,它们就一直在那里。它们是在2014年11月添加的

I'm just surprised I don't recall running into them yet. Your solution was perfect, though I did tweak it slightly. I broke up the where clause to only use the HRTB for the trait that needed it. The rest of the code which I omitted from the OP worked as is.

我只是很惊讶我还不记得我遇到过他们。你的解决方案是完美的,尽管我稍微调整了一下。我分解了WHERE子句,以便只将HRTB用于需要它的特征。我在操作中省略的其余代码按原样工作。

Well HRTB are rarely needed. That's why you don't see them often, their main usecase the Fn family of traits has special syntax sugar which hides them and other usecases are few and far apart.

嗯,很少需要HRTB。这就是为什么你不经常看到它们的原因,它们的主要用法FN家族的特征有特殊的语法糖分,隐藏了它们,而其他用例很少,而且相距甚远。

Hmm, copying your example verbatim still triggered the error for me. The borrowed value from arr.as_ref() which was bound at ManuallyDrop::new([obj]) does not live long enough. I am using Rust 1.71.0.

嗯,逐字复制您的示例仍然会触发我的错误。从arr.as_ref()借来的值绑定到ManuallyDrop::new([obj])时寿命不够长。我使用的是铁锈1.71.0。

@penguin359 yea that's what I would have expected, when the arr goes out of scope so do references to it, that doesn't get changed by ManuallyDrop I wouldn't expect this to work.

@penguin359年,这就是我所期望的,当arr超出范围时,所以要引用它,这不会被ManuallyDrop更改我不会期望这会起作用。

Hmm.. how about trying use the ToGlibPtr trait to convert each GObject in the slice to a *mut GObject, and then manually construct the GList?

嗯...尝试使用ToGlibPtr trait将切片中的每个GObject转换为 *mut GObject,然后手动构造GList,怎么样?

Something like that: // Function to create a GList from a slice of GObject references fn create_glist(objects: &[&dyn IsA<glib::Object>]) -> *mut GList { let mut glist_ptr: *mut GList = std::ptr::null_mut(); for obj in objects.iter() { // Convert each object to *mut GObject let obj_ptr = obj.to_glib_full(); // Append it to the GList glist_ptr = unsafe { g_list_append(glist_ptr, obj_ptr as *mut c_void) }; } glist_ptr }

类似这样的://从一片GObject引用FN CREATE_GLIST(对象:&[&dyn Isa])->*mut glist{let mut glist_ptr:*mut glist=std::ptr::ull_mut();for obj::ptr(){//将每个对象转换为*mut GObject let obj_ptr=obj.to_glib_Full();//追加到glist glist_ptr=unSafe{g_list_append(glist_ptr,obj_ptr as*mut c_void)};}glist_ptr}

@user3527282 I had considered that, but I looked at the source for the ToGlibContainerFromSlice trait and that is basically what it already does so I don't think doing manually. It uses the ToGlibPtr trait to convert each entry and then adds them to a GList with the native glib API.

@user3527282我曾考虑过这一点,但我查看了ToGlibContainerFromSlice特征的源代码,这基本上就是它已经做的,所以我不认为手动做这件事。它使用ToGlibPtr特征来转换每个条目,然后使用本地Glib API将它们添加到glist中。

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com