Implementing `Deref` for slices/`?Sized` - rust

I'm working on a library implementing allocators (https://github.com/JonathanWoollett-Light/array-allocators) which can be used in shared memory.
I have a type which currently implements Deref and DerefMut on T: Sized and need it to implement on T: ?Sized to support slices.
This type is TypedLinkedListArrayWrapper:
pub struct TypedLinkedListArrayWrapper<'a, const N: usize, T: ?Sized> {
pub wrapper: LinkedListArrayWrapper<'a, N>,
__marker: PhantomData<T>,
}
which implements Deref and DerefMut:
impl<'a, const N: usize, T> Deref for TypedLinkedListArrayWrapper<'a, N, T> {
type Target = T;
fn deref(&self) -> &Self::Target {
unsafe { &*(self.wrapper.deref() as *const [LinkedListArrayBlock]).cast() }
}
}
impl<'a, const N: usize, T> DerefMut for TypedLinkedListArrayWrapper<'a, N, T> {
fn deref_mut(&mut self) -> &mut Self::Target {
unsafe { &mut *(self.wrapper.deref_mut() as *mut [LinkedListArrayBlock]).cast() }
}
}
If I change T to be T:?Sized here I get the errors
error[E0277]: the size for values of type `T` cannot be known at compilation time
--> src/linked_list.rs:166:54
|
162 | impl<'a, const N: usize, T: ?Sized> Deref for TypedLinkedListArrayWrapper<'a, N, T> {
| - this type parameter needs to be `std::marker::Sized`
...
166 | unsafe { &*std::ptr::addr_of!(*self.wrapper).cast() }
| ^^^^ doesn't have a size known at compile-time
|
note: required by a bound in `ptr::const_ptr::<impl *const T>::cast`
--> /home/jonathan/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/core/src/ptr/const_ptr.rs:60:23
|
60 | pub const fn cast<U>(self) -> *const U {
| ^ required by this bound in `ptr::const_ptr::<impl *const T>::cast`
help: consider removing the `?Sized` bound to make the type parameter `Sized`
|
162 - impl<'a, const N: usize, T: ?Sized> Deref for TypedLinkedListArrayWrapper<'a, N, T> {
162 + impl<'a, const N: usize, T> Deref for TypedLinkedListArrayWrapper<'a, N, T> {
|
For more information about this error, try `rustc --explain E0277`.
error: could not compile `array-allocators` due to previous error
This is on top of LinkedListArrayWrapper:
pub struct LinkedListArrayWrapper<'a, const N: usize> {
allocator: &'a LinkedListArrayAllocator<N>,
index: usize,
size: usize,
}
which implements Deref and DerefMut:
impl<'a, const N: usize> Deref for LinkedListArrayWrapper<'a, N> {
type Target = [LinkedListArrayBlock];
fn deref(&self) -> &Self::Target {
let allocator = unsafe { &*self.allocator.0.get() };
&allocator.data[self.index..self.index + self.size]
}
}
impl<'a, const N: usize> DerefMut for LinkedListArrayWrapper<'a, N> {
fn deref_mut(&mut self) -> &mut Self::Target {
let allocator = unsafe { &mut *self.allocator.0.get() };
&mut allocator.data[self.index..self.index + self.size]
}
}
where LinkedListArrayBlock is:
pub struct LinkedListArrayBlock {
size: usize,
next: Option<usize>,
}
How can I do this?

So I found a solution.
An important topic here relates to https://doc.rust-lang.org/std/ptr/trait.Pointee.html. Unfortunately this is nightly and requires #![feature(ptr_metadata)].
A solution is to use a custom type for slices to embed the meta data needed for a slice:
pub struct SliceLinkedListArrayWrapper<'a, const N: usize, T> {
pub wrapper: LinkedListArrayWrapper<'a, N>,
pub len: usize,
__marker: PhantomData<T>,
}
impl<'a, const N: usize, T> Deref for SliceLinkedListArrayWrapper<'a, N, T> {
type Target = [T];
fn deref(&self) -> &Self::Target {
unsafe { &*std::ptr::from_raw_parts(std::ptr::addr_of!(*self.wrapper).cast(), self.len) }
}
}
impl<'a, const N: usize, T> DerefMut for SliceLinkedListArrayWrapper<'a, N, T> {
fn deref_mut(&mut self) -> &mut Self::Target {
unsafe {
&mut *std::ptr::from_raw_parts_mut(
std::ptr::addr_of_mut!(*self.wrapper).cast(),
self.len,
)
}
}
}
A more generalized solution is likely possible although may be awkward.

The specific problem here is that .cast() requires the target type to be Sized. The reason can be found in the issue introducing the method:
Like with NonNull::cast, the input pointed type does not need to be Sized but the output pointed type does, because we wouldn’t know what appropriate pointer metadata (slice length, trait object vtable, …) to insert.
With that out of the way, I don't understand what you're trying to accomplish. At all. It seems like you're trying to use a slice of LinkedListArrayBlock as backing storage for T? That seems very dubious and wildly unsound. And even if it weren't you can't cast between fat pointers arbitrarily and have it make sense.

Related

Automatic trait implementation does not work

On the code below, you can see that I forced the implementation of A for everything that implements AsRef<[T]> and Index[T], so B should implement it, because it implements both of these. However this is not the case. Why?
use std::convert::{AsMut, AsRef};
use std::ops::{Index, IndexMut};
use std::slice::SliceIndex;
pub trait A<T, I: SliceIndex<[T], Output = T>>:
AsRef<[T]> + Index<I, Output = T>
{
fn len(&self) -> usize;
}
impl<
T: AsRef<[T]> + Index<I, Output = T>,
I: SliceIndex<[T], Output = T>,
> A<T, I> for T
{
fn len(&self) -> usize {
self.as_ref().len()
}
}
struct B<'a, T>{
data: &'a mut [T]
}
impl<'a, T> AsRef<[T]> for B<'a, T> {
fn as_ref(&self) -> &[T] {
self.data
}
}
impl<'a, T, I: SliceIndex<[T], Output = T>> Index<I> for B<'a, T> {
type Output = T;
fn index(
&self,
v: I,
) -> &Self::Output {
&self.as_ref()[v]
}
}
fn something<'a, T>(r: &'a mut[T]) -> Box<dyn A<T, usize>> {
let a = B{data: r};
Box::new(a)
}
https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=aa2353139f3d097e2497ed700d678ed3
Error:
error[E0277]: the trait bound `B<'_, T>: A<T, usize>` is not satisfied
--> src/lib.rs:46:5
|
46 | Box::new(a)
| ^^^^^^^^^^^ the trait `A<T, usize>` is not implemented for `B<'_, T>`
|
= note: required for the cast to the object type `dyn A<T, usize, Output = T>`
You need to introduce an additional type parameter on the blanket impl for A:
impl<T, I, V> A<T, I> for V
where
V: AsRef<[T]> + Index<I, Output = T>,
I: SliceIndex<[T], Output = T>,
{
fn len(&self) -> usize {
self.as_ref().len()
}
}
After fixing that, you'll get a lifetime error since the trait object returned in the box infers a 'static lifetime, so you'll need to bind it to the input slice's 'a lifetime.
fn something<'a, T>(r: &'a mut [T]) -> Box<dyn A<T, usize> + 'a> {
let a = B { data: r };
Box::new(a)
}

Trouble with stricter lifetime requirements when implementing FromIterator for LazyList

I was playing with the code from this answer but the FromIterator impl does not compile any more:
error[E0276]: impl has stricter requirements than trait --> src/lib.rs:184:9
| 184 | fn from_iter<I: IntoIterator<Item = T> + 'a>(itrbl: I) -> LazyList<'a, T> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ impl has extra requirement `I: 'a`
For more information about this error, try `rustc --explain E0276`.
The slightly updated code is on the playground.
// only necessary because Box<FnOnce() -> R> doesn't work...
mod thunk {
pub trait Invoke<R = ()> {
fn invoke(self: Box<Self>) -> R;
}
impl<R, F: FnOnce() -> R> Invoke<R> for F {
#[inline(always)]
fn invoke(self: Box<F>) -> R { (*self)() }
}
}
// Lazy is lazily evaluated contained value using the above Invoke trait
// instead of the desire Box<FnOnce() -> T> or a stable FnBox (currently not)...
pub mod lazy {
use crate::thunk::Invoke;
use std::cell::UnsafeCell;
use std::mem::replace;
use std::ops::Deref;
// Lazy is lazily evaluated contained value using the above Invoke trait
// instead of the desire Box<FnOnce() -> T> or a stable FnBox (currently not)...
pub struct Lazy<'a, T: 'a>(UnsafeCell<LazyState<'a, T>>);
enum LazyState<'a, T: 'a> {
Unevaluated(Box<dyn Invoke<T> + 'a>),
EvaluationInProgress,
Evaluated(T),
}
use self::LazyState::*;
impl<'a, T: 'a> Lazy<'a, T> {
#[inline]
pub fn new<F: 'a + FnOnce() -> T>(func: F) -> Lazy<'a, T> {
Lazy(UnsafeCell::new(Unevaluated(Box::new(func))))
}
#[inline]
pub fn evaluated(val: T) -> Lazy<'a, T> {
Lazy(UnsafeCell::new(Evaluated(val)))
}
#[inline(always)]
fn force(&self) {
unsafe {
match *self.0.get() {
Evaluated(_) => {}, // nothing required; already Evaluated
EvaluationInProgress => panic!("Lazy::force called recursively!!!"),
_ => {
let ue = replace(&mut *self.0.get(), EvaluationInProgress);
if let Unevaluated(thnk) = ue {
*self.0.get() = Evaluated(thnk.invoke());
} // no other possiblity!
}
}
}
}
#[inline]
pub fn unwrap<'b>(self) -> T where T: 'b { // consumes the object to produce the value
self.force(); // evaluatate if not evealutated
match { self.0.into_inner() } {
Evaluated(v) => v,
_ => unreachable!() // previous code guarantees never not Evaluated
}
}
}
impl<'a, T: 'a> Deref for Lazy<'a, T> {
type Target = T;
#[inline]
fn deref(&self) -> &T {
self.force(); // evaluatate if not evalutated
match *unsafe { &*self.0.get() } {
Evaluated(ref v) => v,
_ => unreachable!(),
}
}
}
}
// LazyList is an immutable lazily-evaluated persistent (memoized) singly-linked list
// similar to lists in Haskell, although here only tails are lazy...
// depends on the contained type being Clone so that the LazyList can be
// extracted from the reference-counted Rc heap objects in which embedded.
pub mod lazylist {
use crate::lazy::Lazy;
use std::rc::Rc;
use std::iter::FromIterator;
use std::mem::{replace, swap};
#[derive(Clone)]
pub enum LazyList<'a, T: 'a + Clone> {
Empty,
Cons(T, RcLazyListNode<'a, T>),
}
pub use self::LazyList::Empty;
use self::LazyList::Cons;
type RcLazyListNode<'a, T> = Rc<Lazy<'a, LazyList<'a, T>>>;
// impl<'a, T:'a> !Sync for LazyList<'a, T> {}
impl<'a, T: 'a + Clone> LazyList<'a, T> {
#[inline]
pub fn singleton(v: T) -> LazyList<'a, T> {
Cons(v, Rc::new(Lazy::evaluated(Empty)))
}
#[inline]
pub fn cons<F>(v: T, cntf: F) -> LazyList<'a, T>
where F: 'a + FnOnce() -> LazyList<'a, T>
{
Cons(v, Rc::new(Lazy::new(cntf)))
}
#[inline]
pub fn head(&self) -> &T {
if let Cons(ref hd, _) = *self {
return hd;
}
panic!("LazyList::head called on an Empty LazyList!!!")
}
#[inline]
pub fn tail<'b>(&'b self) -> &'b Lazy<'a, LazyList<'a, T>> {
if let Cons(_, ref rlln) = *self {
return &*rlln;
}
panic!("LazyList::tail called on an Empty LazyList!!!")
}
#[inline]
pub fn unwrap(self) -> (T, RcLazyListNode<'a, T>) {
// consumes the object
if let Cons(hd, rlln) = self {
return (hd, rlln);
}
panic!("LazyList::unwrap called on an Empty LazyList!!!")
}
#[inline]
fn iter(&self) -> Iter<'a, T> {
Iter(self)
}
}
impl<'a, T: 'a + Clone> Iterator for LazyList<'a, T> {
type Item = T;
fn next(&mut self) -> Option<Self::Item> {
match replace(self, Empty) {
Cons(hd, rlln) => {
let mut newll = (*rlln).clone();
swap(self, &mut newll); // self now contains tail, newll contains the Empty
Some(hd)
}
_ => None,
}
}
}
pub struct Iter<'a, T: 'a + Clone>(*const LazyList<'a, T>);
impl<'a, T: 'a + Clone> Iterator for Iter<'a, T> {
type Item = &'a T;
fn next(&mut self) -> Option<Self::Item> {
unsafe {
if let LazyList::Cons(ref v, ref r) = *self.0 {
self.0 = &***r;
Some(v)
} else {
None
}
}
}
}
impl<'i, 'l, T: 'i + Clone> IntoIterator for &'l LazyList<'i, T> {
type Item = &'i T;
type IntoIter = Iter<'i, T>;
fn into_iter(self) -> Self::IntoIter {
self.iter()
}
}
impl<'a, T: 'a + Clone, > FromIterator<T> for LazyList<'a, T> {
fn from_iter<I: IntoIterator<Item = T> + 'a>(itrbl: I) -> LazyList<'a, T> {
let itr = itrbl.into_iter();
#[inline(always)]
fn next_iter<'b, R, Itr>(mut iter: Itr) -> LazyList<'b, R>
where R: 'b + Clone,
Itr: 'b + Iterator<Item = R>
{
match iter.next() {
Some(val) => LazyList::cons(val, move || next_iter(iter)),
None => Empty,
}
}
next_iter(itr)
}
}
}
Unfortunately I've exhausted ideas on how to try and fix this.
The code in the question (though not in the referenced answer, which has since been updated) relies on a soundness bug in older versions of the compiler (#18937) which has since been fixed.
It is not possible to implement FromIterator for LazyList, or indeed for any data structure, by storing the iterator inside the structure. This is because the FromIterator trait allows the implementor (Self) to outlive the iterator type (I::IntoIter). That the compiler ever accepted it was an oversight.
When copying code from the internet, be conscious of the age of the source. This code is also out of date in several other respects, notably:
it uses Rust 2015-style paths
it omits dyn on trait object types
the Invoke workaround is no longer needed, since dyn FnOnce() -> T works properly now.

How do I return the result of get_mut from a HashMap or a HashSet?

I'm trying to wrap a HashMap, as defined below, to return a mutable reference from a HashMap:
use std::{collections::HashMap, marker::PhantomData};
struct Id<T>(usize, PhantomData<T>);
pub struct IdCollection<T>(HashMap<Id<T>, T>);
impl<'a, T> std::ops::Index<Id<T>> for &'a mut IdCollection<T> {
type Output = &'a mut T;
fn index(&mut self, id: &'a Id<T>) -> Self::Output {
self.0.get_mut(id).unwrap()
}
}
And the resulting error:
note: first, the lifetime cannot outlive the anonymous lifetime #1 defined on the method body at 54:5...
--> src/id_container.rs:54:5
|
54 | / fn index(&mut self, id: &'a Id<T>) -> Self::Output {
55 | | self.0.get_mut(id).unwrap()
56 | | }
| |_____^
note: ...so that reference does not outlive borrowed content
--> src/id_container.rs:55:9
|
55 | self.0.get_mut(id).unwrap()
| ^^^^^^
note: but, the lifetime must be valid for the lifetime 'a as defined on the impl at 52:6...
--> src/id_container.rs:52:6
|
52 | impl<'a, T> std::ops::Index<Id<T>> for &'a mut IdCollection<T> {
| ^^
= note: ...so that the types are compatible:
expected std::ops::Index<id_container::Id<T>>
found std::ops::Index<id_container::Id<T>>
Why can't the compiler extend the lifetime of the get_mut? The IdCollection would then be borrowed mutably.
Note that I tried using a std::collections::HashSet<IdWrapper<T>> instead of a HashMap:
struct IdWrapper<T> {
id: Id<T>,
t: T,
}
Implementing the proper borrow etc. so I can use the Id<T> as a key.
However, HashSet doesn't offer a mutable getter (which makes sense since you don't want to mutate what's used for your hash). However in my case only part of the object should be immutable. Casting a const type to a non-const is UB so this is out of the question.
Can I achieve what I want? Do I have to use some wrapper such as a Box? Although I'd rather avoid any indirection...
EDIT
Ok I'm an idiot. First I missed the IndexMut instead of the Index, and I forgot the & when specifying the Self::Output in the signature.
Here's my full code below:
pub struct Id<T>(usize, PhantomData<T>);
impl<T> std::fmt::Display for Id<T> {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(f, "{}", self.0)
}
}
impl<T> Hash for Id<T> {
fn hash<H: Hasher>(&self, state: &mut H) {
self.0.hash(state);
}
}
impl<T> PartialEq for Id<T> {
fn eq(&self, o: &Self) -> bool {
self.0 == o.0
}
}
impl<T> Eq for Id<T> {}
pub struct IdCollection<T>(HashMap<Id<T>, T>);
impl<'a, T> IntoIterator for &'a IdCollection<T> {
type Item = (&'a Id<T>, &'a T);
type IntoIter = std::collections::hash_map::Iter<'a, Id<T>, T>;
fn into_iter(self) -> Self::IntoIter {
self.0.iter()
}
}
impl<'a, T> IntoIterator for &'a mut IdCollection<T> {
type Item = (&'a Id<T>, &'a mut T);
type IntoIter = std::collections::hash_map::IterMut<'a, Id<T>, T>;
fn into_iter(self) -> Self::IntoIter {
self.0.iter_mut()
}
}
impl<T> std::ops::Index<Id<T>> for IdCollection<T> {
type Output = T;
fn index(&self, id: Id<T>) -> &Self::Output {
self.0.get(&id).unwrap()
}
}
impl<T> std::ops::IndexMut<Id<T>> for IdCollection<T> {
fn index_mut(&mut self, id: Id<T>) -> &mut Self::Output {
self.0.get_mut(&id).unwrap()
}
}
impl<T> std::ops::Index<&Id<T>> for IdCollection<T> {
type Output = T;
fn index(&self, id: &Id<T>) -> &Self::Output {
self.0.get(id).unwrap()
}
}
impl<T> std::ops::IndexMut<&Id<T>> for IdCollection<T> {
fn index_mut(&mut self, id: &Id<T>) -> &mut Self::Output {
self.0.get_mut(id).unwrap()
}
}
If I understand correctly what you try to achieve, then I have to tell you, that it is a bit more complex than you originally thought it would be.
First of all, you have to realise, that if you like to use a HashMap then the type of the key required to be hashable and comparable. Therefore the generic type parameter T in Id<T> has to be bound to those traits in order to make Id hashable and comparable.
The second thing you need to understand is that there are two different traits to deal with the indexing operator: Index for immutable data access, and IndexMut for mutable one.
use std::{
marker::PhantomData,
collections::HashMap,
cmp::{
Eq,
PartialEq,
},
ops::{
Index,
IndexMut,
},
hash::Hash,
};
#[derive(PartialEq, Hash)]
struct Id<T>(usize, PhantomData<T>)
where T: PartialEq + Hash;
impl<T> Eq for Id<T>
where T: PartialEq + Hash
{}
struct IdCollection<T>(HashMap<Id<T>, T>)
where T: PartialEq + Hash;
impl<T> Index<Id<T>> for IdCollection<T>
where T: PartialEq + Hash
{
type Output = T;
fn index(&self, id: Id<T>) -> &Self::Output
{
self.0.get(&id).unwrap()
}
}
impl<T> IndexMut<Id<T>> for IdCollection<T>
where T: PartialEq + Hash
{
fn index_mut(&mut self, id: Id<T>) -> &mut Self::Output
{
self.0.get_mut(&id).unwrap()
}
}
fn main()
{
let mut i = IdCollection(HashMap::new());
i.0.insert(Id(12, PhantomData), 99i32);
println!("{:?}", i[Id(12, PhantomData)]);
i[Id(12, PhantomData)] = 54i32;
println!("{:?}", i[Id(12, PhantomData)]);
}
It may seem a bit surprising, but IndexMut is not designed to insert an element into the collection but to actually modify an existing one. That's the main reason why HashMap does not implement IndexMut -- and that's also the reason why the above example uses the HashMap::insert method to initially place the data. As you can see, later on, when the value is already available we can modify it via the IdCollection::index_mut.

Wrong trait chosen based on type parameter

I have a binary trait Resolve.
pub trait Resolve<RHS = Self> {
type Output;
fn resolve(self, rhs: RHS) -> Self::Output;
}
I implemented the trait for something trivial where both arguments are taken by reference (self is &'a Foo and rhs is &'b Foo):
struct Foo;
impl <'a, 'b> Resolve<&'b Foo> for &'a Foo {
type Output = Foo;
fn resolve(self, rhs: &'b Foo) -> Self::Output {
unimplemented!()
}
}
If I now write
fn main() {
let a: &Foo = &Foo;
let b = Foo;
a.resolve(&b);
}
it will compile just fine, but if I try to implement it on my struct Signal, it will not work.
pub struct Signal<'a, T> {
ps: Vec<&'a T>,
}
impl<'a, T: Resolve<&'a T, Output = T> + 'a> Signal<'a, T> {
pub fn foo(&mut self) {
let a: &T = &self.ps[0];
let b = &self.ps[1];
a.resolve(b);
}
}
error[E0507]: cannot move out of borrowed content
--> src/main.rs:25:9
|
25 | a.resolve(b);
| ^ cannot move out of borrowed content
How do I get this example working? (playground)
The trait bound on foo only says that T implements Resolve, but you try to call .resolve() on a value of type &T.
To say, instead, that references to T must implement Resolve, you need a higher-ranked trait bound:
impl<'a, T> Signal<'a, T>
where
for<'b> &'b T: Resolve<&'a T, Output = T>,
{
pub fn foo(&mut self) { ... }
}
After thinking about this I came up with a simpler solution that does not rely on HRTB.
impl<'a, T> Signal<'a, T>
where
&'a T: Resolve<&'a T, Output = T> + 'a,
{
pub fn foo(&mut self) {
let a: &T = &self.ps[0];
let b = &self.ps[1];
a.resolve(b);
}
}
This does the same, namely describe, that &T implements Resolve, but without the need of HRTB.
You have to use the where clause for this, but apart from that this is a nice and easy solution.

Trait to store structs with different generic parameters

I need to store in the same Vec instances of the same struct, but with different generic parameters. This is the struct definition:
struct Struct<'a, T: 'a> {
items: Vec<&'a T>
}
The struct has a method returning an iterator to a type that does not depend on the generic type parameter T:
impl<'a, T: 'a> Struct<'a, T> {
fn iter(&self) -> slice::Iter<&i32> {
unimplemented!()
}
}
I need to access this method for those different structs in the vector, so I've implemented this trait:
type Iter<'a> = Iterator<Item=&'a i32>;
trait Trait {
fn iter(&self) -> Box<Iter>;
}
And I've implemented the trait for Struct:
impl<'a, T: 'a> Trait for Struct<'a, T> {
fn iter(&self) -> Box<Iter> {
Box::new(self.iter())
}
}
But the compiler complains:
<anon>:21:9: 21:30 error: type mismatch resolving `<core::slice::Iter<'_, &i32> as core::iter::Iterator>::Item == &i32`:
expected &-ptr,
found i32 [E0271]
<anon>:21 Box::new(self.iter())
^~~~~~~~~~~~~~~~~~~~~
<anon>:21:9: 21:30 help: see the detailed explanation for E0271
<anon>:21:9: 21:30 note: required for the cast to the object type `core::iter::Iterator<Item=&i32> + 'static`
<anon>:21 Box::new(self.iter())
^~~~~~~~~~~~~~~~~~~~~
I've tried different possibilities for lifetime parameters in the trait, but none of them work. How can I make this work?
Rust Playground snippet
Edit
As pointed out by #MatthieuM. one problem is that the type alias is not working properly. Here's another example demonstrating this:
use std::slice;
type Iter<'a> = Iterator<Item=&'a i32>;
struct Struct<'a> { _phantom: std::marker::PhantomData<&'a i32> }
impl<'a> Struct<'a> {
fn direct<'b>(i: &'b slice::Iter<'a, i32>) -> &'b Iterator<Item=&'a i32>
{ i }
fn aliased<'b>(i: &'b slice::Iter<'a, i32>) -> &'b Iter<'a>
{ i }
}
In this example, direct compiles, but aliased not, with the error:
<anon>:12:7: 12:8 error: the type `core::slice::Iter<'a, i32>` does not fulfill the required lifetime
<anon>:12 { i }
^
note: type must outlive the static lifetime
But they seem to be the same thing. What's happening?
Problem 1 — slice::Iter<T> has an Iterator::Item of &T, thus your reference levels are mismatched. Change your method to be
fn iter(&self) -> slice::Iter<i32>
Problem 2 — Box<SomeTrait> is equivalent to Box<SomeTrait + 'static>, but your iterator does not live for the 'static lifetime. You need to explicitly bring in a lifetime:
Box<SomeTrait + 'a>
Problem 3 — I don't understand how you can create a type alias for a trait, that seems very odd. You probably don't want it anyway. Instead, create a type alias for the whole boxed version:
type IterBox<'a> = Box<Iterator<Item=&'a i32> + 'a>;
Problem 4 — Rearrange your main so that references will live long enough and add mutability:
fn main() {
let i = 3;
let v = vec![&i];
let mut traits : Vec<Box<Trait>> = Vec::new();
traits.push(Box::new(Struct{ items: v }));
}
All together:
use std::slice;
type IterBox<'a> = Box<Iterator<Item=&'a i32> + 'a>;
trait Trait {
fn iter<'a>(&'a self) -> IterBox;
}
struct Struct<'a, T: 'a> {
items: Vec<&'a T>
}
impl<'a, T: 'a> Struct<'a, T> {
fn iter(&self) -> slice::Iter<i32> {
unimplemented!()
}
}
impl<'a, T: 'a> Trait for Struct<'a, T> {
fn iter(&self) -> IterBox {
Box::new(self.iter())
}
}
fn main() {
let i = 3;
let v = vec![&i];
let mut traits: Vec<Box<Trait>> = Vec::new();
traits.push(Box::new(Struct { items: v }));
}

Resources