Trying to implement trait to `std::io::Read` and `std::fs::DirEntry` - rust

I am trying to implement my custom trait for both impl std::io::Read and std::fs::DirEntry - the idea is to implement trait both for directores as well as files, buffers and so on.
use std::fs::DirEntry;
use std::io::Read;
trait MyTrait {}
impl<T> MyTrait for T
where
T: Read,
{}
impl MyTrait for DirEntry {}
As a result I got error
error[E0119]: conflicting implementations of trait `MyTrait` for type `DirEntry`
--> src/mytrait.rs:11:1
|
6 | impl<T> MyTrait for T
| --------------------- first implementation here
...
11 | impl MyTrait for DirEntry {
| ^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `DirEntry`
|
= note: upstream crates may add a new impl of trait `std::io::Read` for type `std::fs::DirEntry` in future versions
For more information about this error, try `rustc --explain E0119`.
As far as I understand I cannot implement MyTrait for both impl std::io::Read and std::fs::DirEntry because, somehow, std::fs::DirEntry already implements std::io::Read.
However I cannot find any information about this fact in the docs. I tried to find something in source code but my knowledge about Rust source code is none so mission failed.
I found the solution in which I should manually implement MyTrait for std::fs::File, buffers and so on with some helper macro (like impl_mytrait) but I want to know where I can find informations about possible upstream implementations - and if it's possible I want to find better solution than impl_mytrait macro.

If you read the note, the error is not because such an implementation already exists but because
= note: upstream crates may add a new impl of trait std::io::Read for type std::fs::DirEntry in future versions
'in future versions' here means currently there is no such implementation, but it's disallowed in Rust because adding such an implementation would be a breaking change (i.e. a major version bump required) for your crate, while it only requires a minor version bump from the upstream crate.

Related

Re-implement Debug trait for a third-party struct in Rust

I have an autogenerated struct named Address by protobuf in Rust. It has a predefined Debug trait like this:
impl ::std::fmt::Debug for Address {
fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
::protobuf::text_format::fmt(self, f)
}
}
But I want to customize how it's printed when {:#?} is used. So I decided to implement Debug trait for it like this in my project:
impl fmt::Debug for EvmProto::Address {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
....
}
}
But it complains that conflicting implementations of trait `std::fmt::Debug` for type `protos::Evm::Address
UPDATE: while the answer can still be useful in some similar cases, in this case it seems incorrect. See the comments for details.
You can't implement an external trait on an external type.
I'm citing The Rust Book
we can’t implement external traits on external types. For example, we can’t implement the Display trait on Vec<T> within our aggregator crate, because Display and Vec<T> are both defined in the standard library and aren’t local to our aggregator crate. This restriction is part of a property called coherence, and more specifically the orphan rule, so named because the parent type is not present. This rule ensures that other people’s code can’t break your code and vice versa. Without the rule, two crates could implement the same trait for the same type, and Rust wouldn’t know which implementation to use.

How to fix the error "the trait `OutputType` is not implemented for `time::OffsetDateTime`"?

I'm using async-graphql and I'm trying to use this struct as SimpleObject:
use async_graphql::{CSimpleObject};
#[derive(SimpleObject)]
struct Player {
id: String,
created_at: time::OffsetDateTime,
email: String,
}
but I'm getting this error:
error[E0277]: the trait bound `time::OffsetDateTime: OutputType` is not satisfied
|
50 | #[derive(SimpleObject)]
| ^^^^^^^^^^^^ the trait `OutputType` is not implemented for `time::OffsetDateTime`
|
= help: the following other types implement trait `OutputType`:
&'a [T]
&'impl0 T
Arc<T>
Arc<[T]>
BTreeMap<K, V>
BTreeSet<T>
Cow<'a, T>
Edge<Cursor, Node, EdgeFields, Name>
and 56 others
= note: required because of the requirements on the impl of `OutputType` for `&time::OffsetDateTime`
= note: this error originates in the derive macro `SimpleObject` (in Nightly builds, run with -Z macro-backtrace for more info)
What can I do to fix this?
I tried to search but I cannot understand what to do.
First, the problem: derivation is generally recursive, so all the members of a structure have to implement the trait being derived before the structure itself can.
Generally (de)serialization libraries will implement the trait on standard library types, but they can't feasibly do so for every crate out there (not to mention they would have to depend on all of them in the first place).
So the possible solutions are:
Check the features of the library, sometimes the (de)serialization library will have an optional derivation for "major" crates of the ecosystem, which time probably qualifies as. This lets you just enable the corresponding feature and get the integration.
Barring that, you'll have to implement whatever trait or feature is necessary by hand, unless the field doesn't matter and you can just tell the library to skip it.

How to have a vec of Boxes which implement 2 traits? [duplicate]

This question already has an answer here:
Can I get a trait object of a multi-trait instance without using a generic type?
(1 answer)
Closed 10 months ago.
In rust I would like to have a vec containing items which implement 2 traits. However when I try to implement it like so, I get the error only auto traits can be used as additional traits in a trait object:
let mut v : Vec<Box<dyn MyTrait + std::fmt::Display>> = Vec::new();
FairPlay, I read the error message in full and defined a Trait which combines the two:
pub trait FormattableDoer: std::fmt::Display + MyTrait{}
The have a Vec of Boxes to that:
let mut v: Vec<Box<dyn FormattableDoer>> = Vec::new();
However the compiler can't seem to detect that my struct has implemented those things separately and I get the error the trait bound MyStruct: FormattableDoer is not satisfied.
I read about using a trait alias, but that's not in stable so I'd rather not use it.
Is this possible in rust? It seems like a common thing to want to do and I'm surprised that the answer isn't simple (or maybe it is and I have missed it!). I'm also thinking that maybe I have approached the problem all wrong and I'm attempting to do something in an 'non rusty' way. If that's the case, what is the preferred way of having a vector of things which are displayable and have some other trait?
Playground with a MWE and a use case.
You're almost there. You need a marker trait that implements both parents, as you've already done
pub trait FormattableDoer: std::fmt::Display + MyTrait {}
Then you need a blanket implementation which takes those two traits to your new trait.
impl<T: std::fmt::Display + MyTrait> FormattableDoer for T {}
Now everything that implements std::fmt::Display and MyTrait will implement FormattableDoer automatically, and since FormattableDoer is a single trait, it can be used as a trait object.
Then just use Box<dyn FormattableDoer> like you've already tried.
You still need to implement FormattableDoer for your struct. In the playground you posted, you're not doing that. Simply add
impl FormattableDoer for MyStruct {}
and you should be all done.
No user-defined traits are auto-implemented, even if they contain no methods or associated types.

How to get an implementation of fmt::Debug for a Vec of dyn Trait objects?

I have a trait MyTrait of which all implementations could implement fmt::Debug.
I have a struct MyStruct that contains a Vec<Rc<dyn MyTrait>>.
How do I implement fmt::Debug for MyStruct?
My first idea was to just implement Debug for MyStruct manually but that seems very wrong, considering that only the implementation of Debug of the MyTrait objects could vary.
Logically I should be able to require MyTrait to "include" (in Java terms that would be interface inheritance) Debug and then simply derive Debug for MyStruct automatically.
But how would I achieve this? I haven't found anything to that effect in the docs.
Add Debug as a supertrait of MyTrait:
trait MyTrait: std::fmt::Debug {...}
Some people call this feature "trait inheritance", but a supertrait is not much like a base class in languages that support class inheritance. It's really just a constraint on implementors of MyTrait: "If you implement MyTrait, you have to implement Debug too." Since dyn MyTrait is a type that implements MyTrait, it too has its own (automatically generated) Debug implementation, which just defers to the Debug for the concrete type.
However, you cannot upcast a trait object to a supertrait, at least not without some extra work.

Why is std::borrow::Borrow not implementet for every Type?

On the documentation it is stated that
impl<T> Borrow<T> for T where
T: ?Sized,
I would read this:
This Trait is implemented for every Type, even unsized ones.
Is this correct?
I got the error message:
the trait std::borrow::Borrow<T> is not implemented for &num_complex::Complex<f64>
which I can't make sense of.
(I do not want to post the whole code, I just want some clarification about which types implement std::borror::Borrow)
The important thing to recognize is that in the blanket impl there is only one T and it has to represent the same type in both places:
impl<T> Borrow<T> for T
where T: ?Sized
implements for each type T, only the specific trait Borrow<T>. i64 implements Borrow<i64>, String implements Borrow<String>, etc. When we instantiate this with T = &num_complex::Complex<f64>, what trait is implemented?
impl Borrow<&num_complex::Complex<f64>> for &num_complex::Complex<f64> // (not compilable code, just illustrative)
In words, you can borrow a &Complex<f64> as a &Complex<f64>, but you can't borrow it as any arbitrary T (which wouldn't make much sense, anyway).
You're using this in some generic code where T can be anything, so the blanket impl of Borrow<T> for T doesn't apply. You can probably fix this by adding a trait bound:
where num_complex::Complex<f64>: Borrow<T>
which means that Complex<f64> itself implements Borrow<T>, or
where for<'a> &'a num_complex::Complex<f64>: Borrow<T>
which means that any reference to Complex<f64> implements Borrow<T>. Depending on your actual code either or both of these may work due to autoref/autoderef.

Resources