Lifetime specifiers and generics in SFML - rust

I'm trying to wrap my head around trait bounds and lifetime specifiers but I do not really get what is wrong here.
fn render_screen<'a, T>(window: &mut RenderWindow, chip: &mut Chip, rect: &'a mut T)
where
T: Shape<'a> + Drawable,
{
window.clear(&Color::BLACK);
for x in 0..SCREEN_COLUMNS {
for y in 0..SCREEN_ROWS {
if chip.vid_mem[y][x] == 1 {
let x_pos = (x * SCALE) as f32;
let y_pos = (y * SCALE) as f32;
&mut rect.set_position((x_pos, y_pos));
window.draw(&rect);
}
}
}
}
error[E0277]: the trait bound `&'a mut T: sfml::graphics::Drawable` is not satisfied
--> src/main.rs:114:29
|
114 | window.draw(&rect);
| ^^^^^ the trait `sfml::graphics::Drawable` is not implemented for `&'a mut T`
|
= note: required for the cast to the object type `sfml::graphics::Drawable`
I don't really know how to specify my question any more than that since I have only been writing Rust for about 3 weeks and am still pretty new to the language.

the trait bound `&'a mut T: sfml::graphics::Drawable` is not satisfied
That's because it isn't — all you have required is that T implements Drawable:
T: Shape<'a> + Drawable,
T, &T and &mut T are all different types; just because T implements a trait doesn't mean that &mut T does. If you need to place a restriction on the mutable reference to a T, you can:
fn render_screen<'a, T>(window: &mut RenderWindow, chip: &mut Chip, rect: &'a mut T)
where
T: Shape<'a>,
for <'a> &'a mut T: Drawable,
You might also be able to accept a T with the appropriate bounds:
fn render_screen<'a, T>(window: &mut RenderWindow, chip: &mut Chip, mut rect: T)
where
T: Shape<'a> + Drawable,
and then just pass in a &mut Foo wherever it is called.

Related

Simplify Rust extension trait lifetimes when using Add trait

I need an extension trait for everything that implements AsRef<[T]>. A method of this trait takes a reference to T and based on some math with it returns a sub-slice of the original array.
Sample code can look like:
trait Sample<T> {
fn sample(&self, element: &T, k: usize) -> &[T];
}
impl<'a, A, T> Sample<T> for A
where
A: AsRef<[T]>,
&'a T: Add<Output = T>,
T: 'a,
{
fn sample(&self, element: &T, k: usize) -> &[T] {
let array = self.as_ref();
let doubled = element + element;
&array[0..0]
}
}
It does not compile, though.
error: lifetime may not live long enough
--> src/arrays/sample.rs:15:23
|
7 | impl<'a, A, T> Sample<T> for A
| -- lifetime `'a` defined here
...
13 | fn sample(&self, element: &T, k: usize) -> &[T] {
| - let's call the lifetime of this reference `'1`
14 | let array = self.as_ref();
15 | let doubled = element + element;
| ^^^^^^^^^^^^^^^^^ requires that `'1` must outlive `'a`
I don't really understand why element lifetime must be bigger than 'a.
Anyways, after a while I made it work, but it does not feel right.
use core::ops::Add;
trait KClosestExt<'t, T> {
fn find_k_closest(&'t self, element: &'t T, k: usize) -> &[T];
}
impl<'a, 't, A, T> KClosestExt<'t, T> for A
where
A: AsRef<[T]>,
&'a T: Add<Output = T>,
T: 'a + 't + PartialOrd,
't: 'a,
{
fn find_k_closest(&'t self, element: &'t T, k: usize) -> &[T] {
let array = self.as_ref();
if k > array.len() {
return array;
}
let doubled = element + element;
let left = binary_search(0, array.len() - k, |mid| doubled > &array[mid + k] + &array[mid]);
&array[left..left + k]
}
}
According to what I need, is it possible to simplify lifetime management for this example?
Your lifetime issues stem from the bound &'a T: Add<Output = T>. This says that &T implements Add but only when the lifetime is exactly &'a T.
What you most likely want is for<'a> &'a T: Add<Output = T> which specifies that &T implements Add for any lifetime that you choose. (1)
With this change, you sample code compiles without needing to specify any more lifetimes. playground.
trait Sample<T> {
fn sample(&self, element: &T, k: usize) -> &[T];
}
impl<A, T> Sample<T> for A
where
A: AsRef<[T]>,
for<'a> &'a T: std::ops::Add<Output = T>,
{
fn sample(&self, element: &T, k: usize) -> &[T] {
let array = self.as_ref();
let doubled = element + element;
&array[0..0]
}
}
(1) Strictly speaking, this is a more restrictive bound but I struggle to see a situation where the first one is fulfilled but not the second one.

Can a trait's impl specify a lifetime that comes from a method's input argument?

For a type
pub struct Child<'a> {
buf: &'a mut [u8],
}
I can define a trait and implement the trait for the type but with a lifetime that is bound to a calling function's context (not to a local loop context):
pub trait MakeMut<'a> {
fn make_mut(buf: &'a mut [u8]) -> Self;
}
impl<'a> MakeMut<'a> for Child<'a> {
fn make_mut(buf: &'a mut [u8]) -> Self {
Self { buf }
}
}
And first to show a somewhat working example because x is only borrowed within the context of the loop because Child::make_mut is hardcoded in the map1 function:
pub fn map1<F>(mut func: F)
where
F: FnMut(&mut Child),
{
let mut vec = vec![0; 16];
let x = &mut vec;
for i in 0..2 {
let offset = i * 8;
let s = &mut x[offset..];
let mut w = Child::make_mut(s);
func(&mut w);
}
}
But in trying to make map2, a generic version of map1 where the T is bound to the MakeMut trait but with lifetime of the entire function body, this won't compile, for good reasons (the T lifetimes that would be created by T: MakeMut<'a> have the lifetime of map2, not the inner loop):
pub fn map2<'a, F, T>(mut func: F) // lifetime `'a` defined here
where
T: MakeMut<'a>,
F: FnMut(&mut T),
{
let mut vec = vec![0; 16];
let x = &mut vec;
for i in 0..2 {
let offset = i * 8;
let s = &mut x[offset..];
let mut w = T::make_mut(s); // error: argument requires that `*x` is borrowed for `'a`
func(&mut w);
}
}
I want to do something almost like this but of course it doesn't compile either:
pub trait MakeMut {
fn make_mut<'a>(buf: &'a mut [u8]) -> Self;
}
impl<'a> MakeMut for Child<'a> {
fn make_mut(buf: &'a mut [u8]) -> Self { // lifetime mismatch
Self{ buf }
}
}
with the compiler errors:
error[E0308]: method not compatible with trait
--> src/main.rs:45:5
|
45 | fn make_mut(buf: &'a mut [u8]) -> Self {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ lifetime mismatch
|
= note: expected fn pointer `fn(&'a mut [u8]) -> Child<'_>`
found fn pointer `fn(&'a mut [u8]) -> Child<'_>`
note: the lifetime `'a` as defined here...
--> src/main.rs:45:5
|
45 | fn make_mut(buf: &'a mut [u8]) -> Self {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
note: ...does not necessarily outlive the lifetime `'a` as defined here
--> src/main.rs:44:6
|
44 | impl<'a> MakeMut for Child<'a> {
| ^^
Is there a syntax that allows a trait for a Child<'a> where the 'a is defined by the input argument to the method make_mut? So a generic function could be defined for a trait that returns an instance but where the instance lifetime is not the entire function, but just a shorter lifetime defined by an inner block?
I understand the lifetime is part of the type being returned, but it almost seems like a higher-ranked trait bound (HRTB) would suite this problem except I haven't found a way to specify the lifetime that suites the trait and the method signatures.
Here is a playground link https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=fb28d6da9d89fde645edeb1ca0ae5b21
Your first attempt is close to what you want. For reference:
pub trait MakeMut<'a> {
fn make_mut(buf: &'a mut [u8]) -> Self;
}
impl<'a> MakeMut<'a> for Child<'a> {
fn make_mut(buf: &'a mut [u8]) -> Self {
Self { buf }
}
}
The first problem is the bound on T in map2:
pub fn map2<'a, F, T>(mut func: F)
where
T: MakeMut<'a>,
F: FnMut(&mut T),
This requires the compiler to deduce a single 'a that applies for the whole function. Since lifetime parameters come from outside of the function, the lifetime 'a is necessarily longer than the function invocation, which means anything with lifetime 'a has to outlive the function. Working backwards from the T::make_mut() call, the compiler eventually deduces that x is &'a mut Vec<_> which means vec has to outlive the function invocation, but there's no possible way it can since it's a local.
This can be fixed by using a higher-rank trait bound indicating that T has to implement MakeMut<'a> for any possible lifetime 'a, which is expressed like this:
pub fn map2<F, T>(mut func: F)
where
T: for<'a> MakeMut<'a>,
F: FnMut(&mut T),
With this change, the code compiles.
What you'll then find is that you can't ever actually call map2 with T=Child<'_> because you'll run into the same problem in a different place. The caller must specify a specific lifetime for 'a in Child<'a>, but this disagrees with the HRTB -- you have impl<'a> MakeMut<'a> for Child<'a> but the HRTB wants impl<'a, 'b> MakeMut<'b> for Child<'a>, and that brings back the lifetime problem in that implementation's make_mut.
One way around this is to decouple the implementation of MakeMut from Child, providing a "factory type" that uses associated types. This way, the caller doesn't have to supply any pesky lifetime argument that could cause trouble later.
pub trait MakeMut<'a> {
type Item;
fn make_mut(buf: &'a mut [u8]) -> Self::Item;
}
struct ChildFactory;
impl<'a> MakeMut<'a> for ChildFactory {
type Item = Child<'a>;
fn make_mut(buf: &'a mut [u8]) -> Child<'a> {
Child { buf }
}
}
Then we modify map2 to be aware of the associated type:
pub fn map2<F, T>(mut func: F)
where
T: for<'a> MakeMut<'a>,
F: for<'a, 'b> FnMut(&'b mut <T as MakeMut<'a>>::Item),
whew
Now, finally, we can use map2:
map2::<_, ChildFactory>(|v| {});
(Playground)

Why explicitly non-dispatchable methods in Iterator are dispatchable?

Rust reference object-safety confused me for a while, and says:
Explicitly non-dispatchable functions require:
Have a where Self: Sized bound (receiver type of Self (i.e. self) implies this).
But I found code::iter::Iterator has dozen of methods are declared as explicitly non-dispatchable functions, one of them below:
pub trait Iterator {
...
fn count(self) -> usize
where
Self: Sized,
{
self.fold(
0,
#[rustc_inherit_overflow_checks]
|count, _| count + 1,
)
}
...
}
However, all of them are dispatchable by trait-object at rust-playground:
fn main() {
let it: &mut dyn Iterator<Item = u32> = &mut [1, 2, 3].into_iter();
assert_eq!(3, it.count()); // ok
}
That is good, I start try to implements a worked example, but it can not be dispatched at rust-playground, and report compiler error: "the dispatch method cannot be invoked on a trait object" that is expected:
fn main() {
pub trait Sup {
fn dispatch(self) -> String
where
Self: Sized,
{
"sup".to_string()
}
}
struct Sub;
impl Sup for Sub {
fn dispatch(self) -> String {
"sub".to_string()
}
}
let it: &mut dyn Sup = &mut Sub;
assert_eq!("trait", it.dispatch());
}
Why explicitly non-dispatchable methods in code::iter::Iterator are dispatchable? Is there any magic which I didn't found?
The reason is simple, if we think of this: what type we're invoking the method count on?
Is it dyn Iterator<Item = u32>? Let's check:
assert_eq!(3, <dyn Iterator<Item = u32>>::count(it));
Nope, there are two errors:
error[E0308]: mismatched types
--> src/main.rs:3:53
|
3 | assert_eq!(3, <dyn Iterator<Item = u32>>::count(it));
| ^^ expected trait object `dyn Iterator`, found mutable reference
|
= note: expected trait object `dyn Iterator<Item = u32>`
found mutable reference `&mut dyn Iterator<Item = u32>`
error[E0277]: the size for values of type `dyn Iterator<Item = u32>` cannot be known at compilation time
--> src/main.rs:3:53
|
3 | assert_eq!(3, <dyn Iterator<Item = u32>>::count(it));
| --------------------------------- ^^ doesn't have a size known at compile-time
| |
| required by a bound introduced by this call
|
= help: the trait `Sized` is not implemented for `dyn Iterator<Item = u32>`
note: required by a bound in `count`
OK, well... is it &mut dyn Iterator, then?
assert_eq!(3, <&mut dyn Iterator<Item = u32>>::count(it));
Now it compiles. It's understandable that the second error goes away - &mut T is always Sized. But why do the &mut dyn Iterator has access to the method of Iterator?
The answer is in the documentation. First, dyn Iterator obviously implements Iterator - that's true for any trait. Second, there's implementation of Iterator for any &mut I, where I: Iterator + ?Sized - which our dyn Iterator satisfies.
Now, one may ask - what code is executed when we use this implementation? After all, count requires consuming self, so calling it on reference can't delegate to the dyn Iterator - otherwise we'd be back to square one, dispatching non-dispatchable.
Here, the answer lies in the structure of the Iterator trait. As one can see, it has only a single required method, namely next, which takes &mut self; all other methods are provided, that is, they have some default implementations using next - for example, here's it for count:
fn count(self) -> usize
where
Self: Sized,
{
self.fold(
0,
#[rustc_inherit_overflow_checks]
|count, _| count + 1,
)
}
where fold, in turn, is the following:
fn fold<B, F>(mut self, init: B, mut f: F) -> B
where
Self: Sized,
F: FnMut(B, Self::Item) -> B,
{
let mut accum = init;
while let Some(x) = self.next() {
accum = f(accum, x);
}
accum
}
As you can see, knowing just the next, compiler can derive fold and then count.
Now, back to our &mut dyn Iterators. Let's check how, exactly, this implementation looks like; it appears to be quite simple:
#[stable(feature = "rust1", since = "1.0.0")]
impl<I: Iterator + ?Sized> Iterator for &mut I {
type Item = I::Item;
#[inline]
fn next(&mut self) -> Option<I::Item> {
(**self).next()
}
fn size_hint(&self) -> (usize, Option<usize>) {
(**self).size_hint()
}
fn advance_by(&mut self, n: usize) -> Result<(), usize> {
(**self).advance_by(n)
}
fn nth(&mut self, n: usize) -> Option<Self::Item> {
(**self).nth(n)
}
}
You can see that the &self and &mut self methods, i.e. the ones which can be called on the trait object, are forwarded by the reference to the inner value and dispatched dynamically.
The self methods, i.e. the ones which cannot use the trait object, are dispached statically using their default implementation, which consume the reference and pass it, eventually, into one of these - non-consuming, dynamically-dispatched - methods.

Why is it necessary to add redundant trait bounds even though my trait uses those same traits as bounds?

I have been trying to code a trait which requires a type to implement Add (and further down the line other operations for vector spaces) with itself as well as among its references. The following is a small example, illustrating the problem I ran into:
use std::ops::Add;
#[derive(Debug)]
struct MyVec<T>(Vec<T>);
impl<'a, 'b, T: Copy + Add> Add<&'a MyVec<T>> for &'b MyVec<T> {
type Output = MyVec<T::Output>;
fn add(self, other: &'a MyVec<T>) -> Self::Output {
/* ... */
}
}
impl<'a, T: Copy + Add> Add<MyVec<T>> for &'a MyVec<T> {
/* ... */
}
impl<'a, T: Copy + Add> Add<&'a MyVec<T>> for MyVec<T> {
/* ... */
}
impl<T: Copy + Add> Add<MyVec<T>> for MyVec<T> {
/* ... */
}
trait Addable: Add<Self, Output = Self>
where
Self: Sized,
for<'a> &'a Self: Add<Self, Output = Self>,
for<'b> Self: Add<&'b Self, Output = Self>,
for<'a, 'b> &'a Self: Add<&'b Self, Output = Self>,
{
}
impl<T: Copy + Add<Output = T>> Addable for MyVec<T> {}
fn add_stuff<'a, 'b, T: Addable>(x: &'a T, y: &'b T) -> T {
x + y
}
fn main() {
let v = MyVec(vec![1, 2, 3]);
let w = MyVec(vec![2, 4, 6]);
println!("{:?}", add_stuff(&v, &w));
}
I use the newtype pattern to create an alias of Vec so I can implement a foreign trait (Add) on a foreign struct (Vec).
I implement Add for MyVec and its references. The associated type Output is always the (unreferenced) MyVec. The latter three impls are implemented in terms of the first.
Addable is the central trait that I want to demo. Things that are addable should allow themselves and their references to be added with the result being Self. Particularly, in add_stuff I want the expression x + y + x to be valid where x + y gives a non-ref which can be added with x (which has not been moved out of, because it's a ref) to produce another non-ref.
I don't get any complaints from the compiler regarding the implementation of the Addable trait on MyVec. Specifically, the compiler seems to recognize that the above impls satisfy the bounds in the where clause.
However, I get the following compiler errors:
error[E0277]: the trait bound `for<'a> &'a T: std::ops::Add<T>` is not satisfied
--> src/main.rs:33:1
|
33 | / fn add_stuff<'a, 'b, T: Addable>(x: &'a T, y: &'b T) -> T {
34 | | x + y
35 | | }
| |_^ no implementation for `&'a T + T`
|
= help: the trait `for<'a> std::ops::Add<T>` is not implemented for `&'a T`
= help: consider adding a `where for<'a> &'a T: std::ops::Add<T>` bound
= note: required by `Addable`
error[E0277]: the trait bound `for<'a, 'b> &'a T: std::ops::Add<&'b T>` is not satisfied
--> src/main.rs:33:1
|
33 | / fn add_stuff<'a, 'b, T: Addable>(x: &'a T, y: &'b T) -> T {
34 | | x + y
35 | | }
| |_^ no implementation for `&'a T + &'b T`
|
= help: the trait `for<'a, 'b> std::ops::Add<&'b T>` is not implemented for `&'a T`
= help: consider adding a `where for<'a, 'b> &'a T: std::ops::Add<&'b T>` bound
= note: required by `Addable`
This can be fixed by amending the add_stuff function with a where clause as suggested by the compiler:
where
for<'c, 'd> &'c T: Add<&'d T, Output = T>,
for<'c> &'c T: Add<T, Output = T>,
I do not understand why this is necessary. I thought by specifying a bound in the definition of the trait I could rely on that bound being met for any type that implements that trait? Having to add these where clauses every time sort of defies the whole point of my Addable trait.
Googling brought up this GitHub issue which I don't understand fully but which might be related? That would suggest this is indeed a bug in Rust (which hasn't been fixed for a very long time).
You've hit a shortcoming of the Rust compiler as it currently is. RFC 2089 proposed to make it work as you expect, and was accepted in December 2017.
However, as of today, the feature isn't implemented. The tracking issue for the implementation hasn't seen much activity yet, so it appears implementation hasn't even started. It appears that some fundamental improvements to the compiler's trait bound handling are necessary before this particular feature can be efficiently implemented (search keyword: chalk).

Rust generic AddAssign with references

A while ago I looked into writing a generic iterator for the Fibonacci sequence
that could accept both primitive numbers as well as custom types (such as
bignums). After failing to get a version working for both the primitive types
and bignums, I stumbled upon this question:
How to write a trait bound for adding two references of a generic type?
Which used so called Higher Ranked Trait Bounds to solve the problem with this
particular issue.
Now however, I'm trying to use a similar strategy to use the *_assign
operators instead. In particular, I'm trying to get something similar to this
working:
use std::ops::{Add, AddAssign};
fn add_test<'a, T>(x: &'a T, y: &'a T) -> T
where
for<'b> &'b T: Add<Output = T>,
{
x + y
}
fn add_assign_test<'a, T>(x: &'a mut T, y: &'a T) -> T
where
for<'b> &'b mut T: AddAssign<&'b T>,
T: Clone,
{
x += y;
x.clone()
}
fn main() {
println!("add_test()={}", add_test(&1, &2));
println!("add_assign_test()={}", add_assign_test(&mut 2, &2));
}
add_test() works as expected but I'm unable to get add_assign_test() to work in a similar way. The errors I'm getting suggest that there might not actually exist an implementation for this kind of behaviour on the primitive types:
error[E0277]: the trait bound `for<'b> &'b mut _: std::ops::AddAssign<&'b _>` is not satisfied
--> src/main.rs:21:38
|
21 | println!("add_assign_test()={}", add_assign_test(&mut 2, &2));
| ^^^^^^^^^^^^^^^ no implementation for `&'b mut _ += &'b _`
|
= help: the trait `for<'b> std::ops::AddAssign<&'b _>` is not implemented for `&'b mut _`
= note: required by `add_assign_test`
I could create a macro that creates implementations for these operators that actually takes references to the primitive types, but that seems a little wasteful. Is there any other way to achieve the same effect?
Just a tiny oversight in your code. Let's look at the trait:
pub trait AddAssign<Rhs = Self> {
fn add_assign(&mut self, rhs: Rhs);
}
The receiver of the method is already &mut self and not self. The reason that you had to do the extra work with Add is because it accepts self as receiver. For AddAssign this means: if a type T implements AddAssign, you can call the method add_assign() on a &mut T!
Thus, instead of writing:
where for <'b> &'b mut T: AddAssign<&'b T>,
... you would write:
where for <'b> T: AddAssign<&'b T>,
(No other line changed so far)
However, you notice that the code still won't compile:
error[E0277]: the trait bound `for<'b> {integer}: std::ops::AddAssign<&'b {integer}>` is not satisfied
--> src/main.rs:13:38
|
13 | println!("add_assign_test()={}", add_assign_test(&mut 2, &2));
| ^^^^^^^^^^^^^^^ no implementation for `{integer} += &'b {integer}`
|
= help: the trait `for<'b> std::ops::AddAssign<&'b {integer}>` is not implemented for `{integer}`
= note: required by `add_assign_test`
The reason is simple: there is simply no implementation of AddAssign for primitive types which takes an immutable reference as rhs (Docs). I don't know if this is an oversight -- it could be worth opening an issue on the Rust repo.
To verify the above code works, I write my own type and implemented AddAssign appropriately: Playground.
Corrected the code snippet based on Lukas' reply:
use std::ops::{Add, AddAssign};
fn add_test<'a, T>(x: &'a T, y: &'a T) -> T
where
for<'b> &'b T: Add<Output = T>,
{
x + y
}
fn add_assign_test<'a, T>(x: &'a mut T, y: &'a T) -> T
where
for<'b> T: AddAssign<&'b T>,
T: Clone,
{
*x += y;
x.clone()
}
fn main() {
println!("add_test()={}", add_test(&1, &2));
println!("add_assign_test()={}", add_assign_test(&mut 2, &2));
}
It appears that this is an issue in Rust itself. There is currently a tracker for this issue.
Until this is fixed, there's two possible workarounds:
Create named-tuples for each primitives and implement OpAssign for those types instead. This does however force you to 'cast' all primitives to your custom type.
Duplicate the 'generic' code with specializations for the primitives.

Resources