I have a vector of boxes of some trait core::Object objects:
pub struct Packfile<'a> {
pub version: u32,
pub objects: Vec<Box<core::Object + 'a>>,
...
Now, I want one method of Packfile to return one of those objects optionally: -> Option<Box<core::Object + 'a>>. So, having i as a reference to the index I want, I return this:
Some(self.objects[*i])
OK, this doesn't work because I'm moving the box outside of the vec. Makes sense. Let's clone it (core::Object inherits from Clone).
Some(self.objects[*i].clone())
Now, here is what I don't understand. self.objects[*i] is a box, and clone() on boxes do this: impl<T> Clone for Box<T> where T: Clone { fn clone(&self) -> Box<T>; } so clone() should be giving me a box, right? But I get this error:
src/packfile/mod.rs:190:20: 190:44 error: mismatched types:
expected `Box<core::Object + 'a>`,
found `core::Object + 'a`
(expected box,
found trait core::Object)
src/packfile/mod.rs:190 Some(self.objects[*i].clone()),
^~~~~~~~~~~~~~~~~~~~~~~~
So I don't get why I'm getting a T and not a Box<T> out of clone().
Can you help me?
If you're fine with just a reference to the object, you can do something like:
Some(&self.objects[*i])
You can even implement Index to be able to leverage the indexing operator, so you can do some_packfile[3].
So I don't get why I'm getting a T and not a Box out of clone().
Methods also do auto deref. I don't know what a core::Object is, but if it implements Clone, that's why, I'd bet.
Related
I'm trying to imbed Lua into Rust using Mlua. Using its guided tour, I successfully loaded and evaluated a chunk of Lua code. My next goal is to combine this with opening a file and reading its contents. This is where things get problematic:
use anyhow::Result;
use mlua::{Lua, UserData};
use std::fs;
pub struct LuaManager {
lua_state: Lua
}
impl LuaManager {
pub fn new() -> Self {
LuaManager {
lua_state: Lua::new(),
}
}
pub fn eval<T>(&self, chunk: &str) -> Result<T> where T: Clone + UserData {
let v = self.lua_state.load(chunk).eval::<T>()?;
Ok(v)
}
}
Since scripts can return literally anything, I thought a trait-locked generic annotation would solve the issue: The problem is this:
Error generated by rustc: the parameter type `T` may not live long enough... so that the type `T` will meet its required lifetime bounds...
For reference, here is the function signature as defined in lua.rs:
pub fn eval<R: FromLuaMulti<'lua>>(self) -> Result<R>
I don't understand why I'm having this issue. I've looked this up and this question pertained to user-created types, which to my knowledge I'm not doing... so what is the problem here? It's clear that things like <i32> won't die anytime soon. Cargo did suggest adding a static lifetime annotation, but doing some research into it points me to trying to solve the problem without using it first, since in 99% of cases you actually can get away without it.
Unfortunately in this case it seems like 'static is really required.
Lua::load() takes &'lua self and returns Chunk<'lua, '_>. Chunk::<'lua, '_>::eval::<R>() requires R: FromLuaMulti<'lua>. FromLuaMulti<'lua> is implemented for T: FromLua<'lua>. FromLua<'lua> is implemented for T: UserData, however it requires T: 'static (and also T: Clone, but this is irrelevant).
I'm working with webassembly so I need to fetch the pointer to a buffer. In the case where T is just AsRef<[f32]> (that is, it can be converted to a slice if I'm understanding correctly), I have solved it like this:
#[derive(TS, Serialize)]
pub struct PtrBufF32(usize);
impl<T> From<T> for PtrBufF32
where T: AsRef<[f32]>
{
fn from(f32arr: T) -> Self {
let slc: &[f32] = f32arr.as_ref();
let ptr: *const f32 = slc.as_ptr();
Self(ptr as usize)
}
}
I had help from another stack overflow user to understand what's going on -- as far as I'm understanding, this means "for any T that can be converted to a refence of &[f32] (that is, a slice), then we can implement this trait. The result is simply the pointer to the start of the slice of course.
But then in addition to implementing for anything that can be represented as &[f32], we need to implement for any collection of things that can be represented by &[f32]. Like, if my type T implements Into<&[f32]>, then I can implement the type for any AsRef<[T]>, right? And so on. Any collection of those also implements it. So I thought:
impl<T> From<T> for PtrBufF32
where T: AsRef<[dyn Into<PtrBufF32>]>
{
fn from(f32arr: T) -> Self {
todo!()
}
}
But no… apparently those are "conflicting implementations" somehow?
error[E0119]: conflicting implementations of trait `std::convert::From<memory::ptrbuf::PtrBufF32>` for type `memory::ptrbuf::PtrBufF32`
Yet, if I try to PtrBufF32::from(vec![T]) and T implements Into<AsRef<[f32]>>, it doesn't let me. So clearly it's not conflicting, is it?
Thanks
As long as you implemented conversion for undefined list of types you should think a little bit more widely.
Imagine some type ForeignType, that implements both Into<PtrBufF32> and AsRef<[f32]>. Then if you call PtrBufF32::from(my_foreign_type), compiler cannot decide which of two implementation he must use.
For some OpenGL code, I created a trait Vertex. currently it looks like this
trait Vertex: Sized + Clone {
//...
}
Because of the way Vertex's are used in my program, its very important that anything is a vertex uses the packed representation. If there is any padding it could potentially create problems. Is there any way I can constrain the Vertex trait to only types that use the packed representation? If need be, I could just define my own marker trait that I manually implement for everything that implements Vertex. It seems like something the compiler could easily surface and enforce properly, but I haven't been able to find any kind of representation trait. Thanks
This question gave me the impetus to finish a project I had lying around to do exactly this.
I just pushed it to crates.io. I've been using it for some similar work (dealing with some strange FFI's), but never published it.
It lets you write this code:
use repr_trait::Packed;
// Safety: Only safe to call when T has #[repr(packed)]
unsafe fn safe_when_packed<T>(_param: T) {
unimplemented!()
}
fn safe_wrapper<T: Packed>(param: T) {
// Safety: Safe because T is guaranteed to be #[repr(packed)]
unsafe {
safe_when_packed(param)
}
}
#[derive(Packed, Default)]
#[repr(packed)]
struct PackedData(u32, u8);
safe_wrapper(PackedData(123, 45));
But this is a compile error:
#[derive(Packed)]
struct NotPacked(u32, u8);
You would write your vertex trait as:
trait Vertex: Sized + Clone + Packed {
//...
}
I'd like to create a generic tuple struct Producer which can hold any type P which implements the trait Produce<T>, defined below. This produces the (expected) commented error:
trait Produce<T> {
fn get(&mut self) -> T;
}
// ERROR: parameter `T` is never used [E0392]
struct Producer<P,T>(P) where P: Produce<T>;
If this were a non-tuple struct, I could remedy this issue by adding a PhantomData<T> field and writing a constructor Producer::new(p: P) to hide this as an implementation detail. However, I'm using this type as one of a family of tuple structs in a Builder API, so using a conventional struct + constructor feels pretty out of place.
Is there any way to achieve this?
In many cases, you don't want to parameterize your trait, but instead want an associated type:
trait Produce {
type T;
fn get(&mut self) -> Self::T;
}
struct Producer<P>(P) where P: Produce;
fn main() {}
Unfortunately, it's tough to tell if this will work for you without knowing a lot more about the anticipated use case and code examples, which might be too verbose for Stack Overflow.
I am caught between two different issues/bugs, and can't come up with a decent solution. Any help would be greatly appreciated
Context, FFI, and calling a lot of C functions, and wrapping C types in rust structs.
The first problem is ICE: this path should not cause illegal move.
This is forcing me to do all my struct-wrapping using & references as in:
pub struct CassResult<'a> {
result:&'a cql_ffi::CassResult
}
Instead of the simpler, and preferable:
pub struct CassResult {
result:cql_ffi::CassResult
}
Otherwise code like:
pub fn first_row(&self) -> Result<CassRow,CassError> {unsafe{
Ok(CassRow{row:*cql_ffi::cass_result_first_row(self.result)})
}}
Will result in:
error: internal compiler error: this path should not cause illegal move
Ok(CassRow{row:*cql_ffi::cass_result_first_row(self.result)})
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
So, I go ahead and wrap everything using lifetime managed references, and all is not-horrible until I try to implement an iterator. At which point I see no way around this problem.
method next has an incompatible type for trait: expected concrete lifetime, found bound lifetime parameter
So given those two conflicting issues, I am totally stuck and can't find any way to implement a proper rust iterator around a FFI iterator-like construct.
Edit: With Shep's suggestion, I get:
pub struct CassResult {
pub result:cql_ffi::CassResult
}
and
pub fn get_result(&mut future:future) -> Option<CassResult> {unsafe{
let result:&cql_ffi::CassResult = &*cql_ffi::cass_future_get_result(&mut future.future);
Some(CassResult{result:*result})
}}
but then get:
error: cannot move out of borrowed content
Some(CassResult{result:*result}
Is there any way to make that pattern work? It's repeated all over this FFI wrapping code.
Only a partial answer: use the "streaming iterator" trait and macro.
I have had a similar problem making Rust bindings around the C mysql API. The result is code like this, instead of native for syntax:
let query = format!("SELECT id_y, value FROM table_x WHERE id = {}", id_x);
let res = try!(db::run_query(&query));
streaming_for!( row, res.into_iter(), {
let id_y: usize = try!(row.convert::<usize>(0));
let value: f64 = try!(row.convert::<f64>(1));
});
Here res holds the result and frees memory on drop. The lifetime of row is tied to res:
/// Res has an attached lifetime to guard an internal pointer.
struct Res<'a>{ p: *mut c_void }
/// Wrapper created by into_iter()
struct ResMoveIter<'a>{ res: Res<'a> }
impl<'a> /*StreamingIterator<'a, Row<'a>> for*/ ResMoveIter<'a>{
/// Get the next row, or None if no more rows
pub fn next(&'a mut self) -> Option<Row<'a>>{
...
}
}
#[unsafe_destructor]
impl<'a> Drop for Res<'a>{
fn drop(&mut self){
...
}
}
To answer my own question. The only decent answer was a way around the original ICE, but as thepowersgang comments, the correct way to do this now is to use :std::ptr::read, so using that approach, no ICE, and hopefully progress.