What is 'self: Box<Self>' on a method? [duplicate] - rust

I wanted to create a method that only works where the self parameter was an Rc. I saw that I could use Box, so I thought I might try to mimic how that works:
use std::rc::Rc;
use std::sync::Arc;
struct Bar;
impl Bar {
fn consuming(self) {}
fn reference(&self) {}
fn mutable_reference(&mut self) {}
fn boxed(self: Box<Bar>) {}
fn ref_count(self: Rc<Bar>) {}
fn atomic_ref_count(self: Arc<Bar>) {}
}
fn main() {}
Yields these errors:
error[E0308]: mismatched method receiver
--> a.rs:11:18
|
11 | fn ref_count(self: Rc<Bar>) {}
| ^^^^ expected struct `Bar`, found struct `std::rc::Rc`
|
= note: expected type `Bar`
= note: found type `std::rc::Rc<Bar>`
error[E0308]: mismatched method receiver
--> a.rs:12:25
|
12 | fn atomic_ref_count(self: Arc<Bar>) {}
| ^^^^ expected struct `Bar`, found struct `std::sync::Arc`
|
= note: expected type `Bar`
= note: found type `std::sync::Arc<Bar>`
This is with Rust 1.15.1.

Before Rust 1.33, there are only four valid method receivers:
struct Foo;
impl Foo {
fn by_val(self: Foo) {} // a.k.a. by_val(self)
fn by_ref(self: &Foo) {} // a.k.a. by_ref(&self)
fn by_mut_ref(self: &mut Foo) {} // a.k.a. by_mut_ref(&mut self)
fn by_box(self: Box<Foo>) {} // no short form
}
fn main() {}
Originally, Rust didn't have this explicit self form, only self, &self, &mut self and ~self (the old name for Box). This changed so that only by-value and by-references have the short-hand built-in syntax, since they are the common cases, and have very key language properties, while all smart pointers (including Box) require the explicit form.
As of Rust 1.33, some additional selected types are available for use as self:
Rc
Arc
Pin
This means that the original example now works:
use std::{rc::Rc, sync::Arc};
struct Bar;
impl Bar {
fn consuming(self) { println!("self") }
fn reference(&self) { println!("&self") }
fn mut_reference(&mut self) { println!("&mut self") }
fn boxed(self: Box<Bar>) { println!("Box") }
fn ref_count(self: Rc<Bar>) { println!("Rc") }
fn atomic_ref_count(self: Arc<Bar>) { println!("Arc") }
}
fn main() {
Bar.consuming();
Bar.reference();
Bar.mut_reference();
Box::new(Bar).boxed();
Rc::new(Bar).ref_count();
Arc::new(Bar).atomic_ref_count();
}
However, the impl handling hasn't yet been fully generalised to match the syntax, so user-created types still don't work. Progress on this is being made under the feature flag arbitrary_self_types and discussion is taking place in the tracking issue 44874.
(Something to look forward to!)

It's now possible to use arbitrary types for self, including Arc<Self>, but the feature is considered unstable and thus requires adding this crate attribute:
#![feature(arbitrary_self_types)]
Using feature crate attributes requires using nightly Rust.

Related

My T generic does implement the conditions on where, but I can't use it

struct Response {}
struct PlayResponse(Response);
struct DescribeResponse(Response);
impl From<Response> for PlayResponse {
fn from(response: Response) -> Self {
PlayResponse(response)
}
}
enum RtspState {
Init,
Playing,
}
struct RtspMachine {
state: RtspState
}
pub trait OnEvent<T> {
fn on_event(&mut self, event: &T) -> std::result::Result<(), ()>;
}
impl OnEvent<PlayResponse> for RtspMachine {
fn on_event(&mut self, event: &PlayResponse) -> std::result::Result<(), ()> {
self.state = RtspState::Playing;
Ok(())
}
}
fn do_something<T: OnEvent<T>>() where RtspMachine: OnEvent<T>, T: From<Response>{
let mut rtsp_machine = RtspMachine{state: RtspState::Init};
rtsp_machine.on_event(&T::from(Response{}));
rtsp_machine.on_event(&PlayResponse::from(Response{}));
}
On the do_something above, we require where RtspMachine: OnEvent<T>, T: From<Response>.
Note that RtspMachine: OnEvent<PlayResponse> and PlayResponse: From<Response>. I should be able to do rtsp_machine.on_event(&PlayResponse::from(Response{}));, but it only works for the version with T.:
Compiling playground v0.0.1 (/playground)
error[E0308]: mismatched types
--> src/lib.rs:36:27
|
33 | fn do_something<T: OnEvent<T>>() where RtspMachine: OnEvent<T>, T: From<Response>{
| - this type parameter
...
36 | rtsp_machine.on_event(&PlayResponse::from(Response{}));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected type parameter `T`, found struct `PlayResponse`
|
= note: expected reference `&T`
found reference `&PlayResponse`
Rust playground
I know that
fn do_something<T>() where
RtspMachine: OnEvent<T> + OnEvent<PlayResponse>,
T: From<Response>
would work but I have lots of T that I wanted to use the specific type instead of generic T, so I can't just put them all on the where like that.
This is a known problem with the compiler's method resolution in the presence of trait bounds (#24066, #38071). Changing your method call
rtsp_machine.on_event(&PlayResponse::from(Response{}));
to the explicit function call form
OnEvent::<PlayResponse>::on_event(
&mut rtsp_machine, &PlayResponse::from(Response{}));
will allow the code to compile. Apparently, in the version that doesn't work, method resolution is looking only at the OnEvent<T> trait that's mentioned in where, even though OnEvent<PlayResponse> also exists.
I don't know if there's a more elegant solution, but perhaps the above will be adequate for your problem — at least it means the extra syntax is local to the call site.

trying to use dyn AsyncReadExt, "the trait cannot be made into an object" error

I'm working on a network service that's intended to work with either a TcpStream or stdin/stdout. I get a compile error: the trait tokio::io::util::async_read_ext::AsyncReadExt cannot be made into an object. Currently my workaround is to use a wrapper enum:
enum ClientReader {
Stream(OwnedReadHalf),
Stdin(Stdin),
}
enum ClientWriter {
Stream(OwnedWriteHalf),
Stdout(Stdout),
}
This requires match blocks all over the place, which seems inelegant.
I made a simplified project to repro the issue:
Cargo.toml
[package]
name = "demo"
version = "0.1.0"
authors = ["test"]
edition = "2018"
[dependencies]
tokio = { version = "0.2", features = ["full"] }
src/main.rs
use tokio::io::AsyncReadExt;
struct Test {
test: Box<dyn AsyncReadExt>,
}
fn main () {}
This produces a similar error:
error[E0038]: the trait `tokio::io::AsyncReadExt` cannot be made into an object
--> src/main.rs:4:3
|
4 | test: Box<dyn AsyncReadExt>,
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `tokio::io::AsyncReadExt` cannot be made into an object
|
::: /home/???/.cargo/registry/src/github.com-1ecc6299db9ec823/tokio-0.2.22/src/io/util/async_read_ext.rs:162:12
|
162 | fn read<'a>(&'a mut self, buf: &'a mut [u8]) -> Read<'a, Self>
| ---- the trait cannot be made into an object because method `read` references the `Self` type in its return type
...
280 | fn read_exact<'a>(&'a mut self, buf: &'a mut [u8]) -> ReadExact<'a, Self>
| ---------- the trait cannot be made into an object because method `read_exact` references the `Self` type in its return type
I'm not sure how to proceed. I was considering a giant impl block for the enum wrapper, but that seems like more work than the match blocks. In an OO language there'd be a parent class or interface so I investigated the trait_enum crate to automate making a wrapper impl but had a lot of trouble getting that to work.
At the moment the only cleanup I'm sure will work is to move the workaround into a macro or function.
I'd appreciate any feedback on a better way to do this. :)
EDIT: per suggestion by user4815162342 I made the struct generic over type AsyncReadExt and this appears to work for my example. Will try on my larger project later.
use tokio::io::AsyncReadExt;
struct Test<T: AsyncReadExt> {
test: T,
}
async fn myfn<T: AsyncReadExt>(mut t: Test<T>) where T: std::marker::Unpin {
let mut v = Vec::<u8>::new();
t.test.read_buf(&mut v).await;
}
fn main () {}
To turn an AsyncRead into a trait object, you should use the type Pin<Box<dyn AsyncRead>>.
use std::pin::Pin;
use tokio::io::AsyncRead;
struct Test {
test: Pin<Box<dyn AsyncRead>>,
}
impl Test {
fn new<T: AsyncRead>(io: T) -> Self {
Self {
test: Box::pin(io),
}
}
}
The AsyncReadExt trait is an extension trait, and you should always use the AsyncRead trait when mentioning the type of an AsyncRead.

Why does SmallVec have different behaviour when storing types with lifetimes compared to Vec?

I've got three examples, one using Vec one using SmallVec, and one with my own implementation of SmallVec. The ones using Vec and my own SmallVec compile but the one using the real SmallVec does not.
Working example using Vec
use std::borrow::Cow;
use std::collections::HashMap;
pub trait MyTrait {
fn get_by_id(&self, id: usize) -> &ItemTraitReturns;
}
/// IMPORTANT PART IS HERE: `Vec<Cow<'a, str>>`
pub struct ItemTraitReturns<'a>(Vec<Cow<'a, str>>);
/// this implementation only takes items with static lifetime (but other implementations also might have different lifetimes)
pub struct MyTraitStruct {
map: HashMap<usize, ItemTraitReturns<'static>>,
}
impl MyTrait for MyTraitStruct {
fn get_by_id(&self, id: usize) -> &ItemTraitReturns {
let temp: &ItemTraitReturns<'static> = self.map.get(&id).unwrap();
// Works as expected: I expect that I can return `&ItemTraitReturns<'_>`
// when I have `&ItemTraitReturns<'static>` (since 'static outlives everything).
temp
// Will return `&ItemTraitReturns<'_>`
}
}
Failing example with SmallVec
Uses SmallVec instead of Vec with no other changes.
use smallvec::SmallVec;
use std::borrow::Cow;
use std::collections::HashMap;
pub trait MyTrait {
fn get_by_id(&self, id: usize) -> &ItemTraitReturns;
}
/// IMPORTANT PART IS HERE: Uses SmallVec instead of Vec
pub struct ItemTraitReturns<'a>(SmallVec<[Cow<'a, str>; 2]>);
/// this implementation only takes items with static lifetime (but other implementations also might have different lifetimes)
pub struct MyTraitStruct {
map: HashMap<usize, ItemTraitReturns<'static>>,
}
impl MyTrait for MyTraitStruct {
fn get_by_id(&self, id: usize) -> &ItemTraitReturns {
let temp: &ItemTraitReturns<'static> = self.map.get(&id).unwrap();
temp
}
}
error[E0308]: mismatched types
--> src/lib.rs:23:9
|
23 | temp
| ^^^^ lifetime mismatch
|
= note: expected type `&ItemTraitReturns<'_>`
found type `&ItemTraitReturns<'static>`
note: the anonymous lifetime #1 defined on the method body at 18:5...
--> src/lib.rs:18:5
|
18 | / fn get_by_id(&self, id: usize) -> &ItemTraitReturns {
19 | | let temp: &ItemTraitReturns<'static> = self.map.get(&id).unwrap();
20 | | // Error:
21 | | // = note: expected type `&demo2::ItemTraitReturns<'_>`
22 | | // found type `&demo2::ItemTraitReturns<'static>`
23 | | temp
24 | | }
| |_____^
= note: ...does not necessarily outlive the static lifetime
Working example with my own SmallVec
When I implement my own (very naive) SmallVec<[T; 2]> (called NaiveSmallVec2<T>) the code also compiles... Very strange!
use std::borrow::Cow;
use std::collections::HashMap;
/// This is a very naive implementation of a SmallVec<[T; 2]>
pub struct NaiveSmallVec2<T> {
item1: Option<T>,
item2: Option<T>,
more: Vec<T>,
}
impl<T> NaiveSmallVec2<T> {
pub fn push(&mut self, item: T) {
if self.item1.is_none() {
self.item1 = Some(item);
} else if self.item2.is_none() {
self.item2 = Some(item);
} else {
self.more.push(item);
}
}
pub fn element_by_index(&self, index: usize) -> Option<&T> {
match index {
0 => self.item1.as_ref(),
1 => self.item2.as_ref(),
_ => self.more.get(index - 2),
}
}
}
pub trait MyTrait {
fn get_by_id(&self, id: usize) -> &ItemTraitReturns;
}
/// IMPORTANT PART IS HERE: Uses NaiveSmallVec2
pub struct ItemTraitReturns<'a>(NaiveSmallVec2<Cow<'a, str>>);
/// only takes items with static lifetime
pub struct MyTraitStruct {
map: HashMap<usize, ItemTraitReturns<'static>>,
}
impl MyTrait for MyTraitStruct {
fn get_by_id(&self, id: usize) -> &ItemTraitReturns {
let temp: &ItemTraitReturns<'static> = self.map.get(&id).unwrap();
// astonishingly this works!
temp
}
}
I expect the SmallVec version to compile like the Vec version does. I don't understand why in some cases (in the case of Vec) &ItemTraitReturns<'static> can be converted to &ItemTraitReturns<'_> and in some cases (SmallVec) it's not possible (I don't see the influence of Vec / SmallVec).
I don't want to change lifetimes of this trait:
pub trait MyTrait {
fn get_by_id(&self, id: usize) -> &ItemTraitReturns;
}
... since when using the trait I don't care about lifetimes (this should be an implementation detail) ... but still would like to use SmallVec.
This difference appears to be caused by a difference in variance between Vec and SmallVec. While Vec<T> is covariant in T, SmallVec appears to be invariant. As a result, SmallVec<[&'a T; 1]> can't be converted to SmallVec<[&'b T; 1]> even when lifetime 'a outlives 'b and the conversion should be safe. Here is a minimal example triggering the compiler error:
fn foo<'a, T>(x: SmallVec<[&'static T; 1]>) -> SmallVec<[&'a T; 1]> {
x // Compiler error here: lifetime mismatch
}
fn bar<'a, T>(x: Vec<&'static T>) -> Vec<&'a T> {
x // Compiles fine
}
This appears to be a shortcoming of SmallVec. Variance is automatically determined by the compiler, and it is sometimes cumbersome to convince the compiler that it is safe to assume that a type is covariant.
There is an open Github issue for this problem.
Unfortunately, I don't know a way of figuring out the variance of a type based on its public interface. Variance is not included in the documentation, and depends on the private implementation details of a type. You can read more on variance in the language reference or in the Nomicon.

How can I implement Borrow for a generic container in the case of the use of associated types?

I would like to implement Borrow for UserFriendlyDataStructure to provide access to the internal_data field within a function that should be agnostic with respect to the data provider. The type of the internal_data field is determined by the type associated to trait TraitA. Note that the Sealed trait ensures that none of these traits here can be implemented by other crates; this is functionality that strictly I provide. Furthermore, the type TraitA::Data is restricted by the empty trait DataTrait to prevent UserFriendlyDataStructure from being used as that type.
The following example explains best:
use std::borrow::Borrow;
use std::marker::PhantomData;
mod private {
pub trait Sealed {}
}
pub trait DataTrait: private::Sealed {}
pub trait TraitA: private::Sealed {
type Data: DataTrait;
}
pub struct UserFriendlyDataStructure<A: TraitA> {
internal_data: A::Data,
_a: PhantomData<A>,
}
impl<A: TraitA> Borrow<A::Data> for UserFriendlyDataStructure<A> {
fn borrow(&self) -> &A::Data {
&self.internal_data
}
}
pub fn important_function<A: TraitA, T: Borrow<A::Data>>(data: &T) {
let _internal_data = data.borrow();
// Do lots of work.
}
#[cfg(test)]
mod tests {
use super::*;
pub struct TestData(u32);
impl super::private::Sealed for TestData {}
impl DataTrait for TestData {}
pub struct TestProvider;
impl super::private::Sealed for TestProvider {}
impl TraitA for TestProvider {
type Data = TestData;
}
#[test]
fn basic_test() {
let ufds: UserFriendlyDataStructure<TestProvider> = UserFriendlyDataStructure {
internal_data: TestData(100),
_a: PhantomData::default(),
};
important_function::<TestProvider, _>(&ufds);
}
}
Unfortunately, the compiler complains:
error[E0119]: conflicting implementations of trait `std::borrow::Borrow<UserFriendlyDataStructure<_>>` for type `UserFriendlyDataStructure<_>`:
--> src/lib.rs:19:1
|
19 | impl<A: TraitA> Borrow<A::Data> for UserFriendlyDataStructure<A> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: conflicting implementation in crate `core`:
- impl<T> std::borrow::Borrow<T> for T
where T: ?Sized;
Is there a way to achieve what I am trying to do?
The compiler can be cajoled into accepting the code by introducing a redundant second type parameter that is constrained to be identical to A::Data:
impl<A, D> Borrow<D> for UserFriendlyDataStructure<A>
where
A: TraitA<Data = D>,
D: DataTrait,
{
fn borrow(&self) -> &A::Data {
&self.internal_data
}
}
I don't know why this works, and simply constraining A::Data: DataTrait doesn't. I think the compiler should accept both versions.
(Full code on the playground)
Edit: The fact that we need the redundant type D in the above code appears to be a shortcoming of the current compiler implementation, and is hopefully resolved once the experimental type inference engine chalk gets integrated in the compiler.

Create a generic struct with Option<T> without specifying T when instantiating with None

I have a
struct Foo<T>
where
T: // ... some complex trait bound ...
{
a: Bar,
b: Option<T>,
}
When attempting to instantiate the struct with a b: None the compiler complains that it cannot infer the type and requires a type hint e.g. via the turbofish syntax. That is onerous on the caller because they will have to find a type that fulfills the trait bounds and import it despite not caring about that optional functionality.
I think what I am looking for would be a bottom type that automatically fulfills any trait bounds but cannot be instantiated so that None::<Bottom> could be used, but I have not found such a type in the documentation.
There's a feature in the works that allows specifying the never type as !. This is not present in stable Rust, so you need to use a nightly and a feature flag:
#![feature(never_type)]
fn thing<T>() -> Option<T> {
None
}
fn main() {
thing::<!>();
}
However, this doesn't work for your case yet (this is part of the reason that it's unstable):
#![feature(never_type)]
trait NothingImplementsMe {}
fn thing<T>() -> Option<T>
where T: NothingImplementsMe,
{
None
}
fn main() {
thing::<!>();
}
error[E0277]: the trait bound `!: NothingImplementsMe` is not satisfied
--> src/main.rs:12:5
|
12 | thing::<!>();
| ^^^^^^^^^^ the trait `NothingImplementsMe` is not implemented for `!`
|
= note: required by `thing`
The very first unresolved question on the tracking issue is:
What traits should we implement for !?
Since this feature is both unstable and doesn't do what you want, you may want to consider creating your own bespoke "bottom" type:
trait AlmostNothingImplementsMe {
fn foo();
}
struct Nope;
impl AlmostNothingImplementsMe for Nope {
fn foo() { unimplemented!() }
}
fn thing<T>() -> Option<T>
where T: AlmostNothingImplementsMe,
{
None
}
fn main() {
thing::<Nope>();
}
To improve the UX of this, I'd suggest creating a builder of some type that starts you off with the faux-bottom type:
mod nested {
pub trait AlmostNothingImplementsMe {
fn foo();
}
pub struct Nope;
impl AlmostNothingImplementsMe for Nope {
fn foo() { unimplemented!() }
}
pub fn with_value<T>(t: T) -> Option<T>
where T: AlmostNothingImplementsMe,
{
Some(t)
}
pub fn without_value() -> Option<Nope> {
None
}
}
fn main() {
nested::without_value();
}
You can see this similar pattern in crates like Hyper, although it boxes the concrete type so you don't see it from the outside.
One option to avoid the need to the turbofish operator is to have a type alias:
trait MyTrait {}
impl MyTrait for () {}
struct Foo<T: MyTrait> {
i: isize,
o: Option<T>,
}
type Bar = Foo<()>;
fn main() {
let foo_default = Bar { i: 1, o: None };
}
I used () as the default for simplicity, but ! (when available) or your own bottom type as in #Shepmaster's answer may be better.
A constructor function could also work if you don't mind Foo::new_default(i) or similar.

Resources