*Hello community! I thank you in advance for helping me solve this puzzle.
I'll try to be as precise as possible in my demand.
I'm trying to define a trait that can consume the value (the value should be cloneable) and produce another value of another type. It's typically used to upcast everything to dyn Any.
I am able to define the trait in the user crate for the *mut versions of the structure, and I probably can define it for the &mut and borrowed version of it, but I can't get it to work on the Rc version of it. Given my understanding that Rc<dyn X> is actually a fast pointer that just happens to point to X preceeded by a strong and weak counter, I think it should be possible to define it at least in the user crate but that's unfortunately not the case due to the orphan rule (which I believe should not apply in this case?)
Requirements
trait UpcastTo has to be in my_crate
trait UpcastTo and UserType are in two different crates
UserTypeWrapper cannot be in my_crate
main() cannot be in my_crate and cannot be changed.
Condition to solve my problem
(preferred) If you find a where clause for the impl with the comment //This won't work: that makes the code compile, this is the best solution I wish I had and I'll immediately mark it as the accepted answer
(acceptable) If you manage to let me have the impl despite the Error: only traits defined in the current crate...
(potentially acceptable) Any way to rewrite my code still spanning on two crates that leaves main() mostly unchanged.
mod my_crate {
//use std::rc::Rc;
//use std::any::Any;
pub trait UpcastTo<U>: Clone {
fn upcast_to(self) -> U;
}
// This won't work:
impl<From, To> UpcastTo<::std::rc::Rc<To>> for ::std::rc::Rc<From>
where
From: ?Sized,
To: ?Sized,
// What other condition is needed here?
{
fn upcast_to(self) -> ::std::rc::Rc<To> {
self as ::std::rc::Rc<To>
}
}
}
mod my_crate_user {
use std::rc::Rc;
use std::any::Any;
use crate::my_crate::*;
pub struct UserType{i: i32}
// This works, because *mut is not a type wrapper.
impl UpcastTo<*mut dyn Any> for *mut UserType
{
fn upcast_to(self) -> *mut dyn Any {
self as *mut dyn Any
}
}
// Error: only traits defined in the current crate can be implemented for types defined outside of the crate
// `Rc` is not defined in the current crate
/*impl UpcastTo<Rc<dyn Any>> for Rc<UserType>
{
fn upcast_to(self) -> Rc<dyn Any> {
self as ::std::rc::Rc<dyn Any>
}
}*/
#[derive(Clone)]
pub struct UserTypeWrapper<T: Clone>{k: i32, t: T}
impl<T: Clone, U: Clone> UpcastTo<UserTypeWrapper<U>> for UserTypeWrapper<T>
where T: UpcastTo<U>
{
fn upcast_to(self) -> UserTypeWrapper<U> {
UserTypeWrapper::<U>{k: self.k, t: self.t.upcast_to()}
}
}
pub fn main() {
let t = Rc::new(UserType{i: 3});
let k = UserTypeWrapper{k:1, t: t};
let _kAny: UserTypeWrapper<Rc<dyn Any>> = k.upcast_to();
}
}
fn main() {
my_crate_user::main();
}
The orphan rule is supposed to prevent the problem of two crates defining two conflicting implementations for the same trait and the same type.
In the case above, the compiler understands that UpcastTo is in another crate and Rc too, so it complains, because any other crate might do the same.
However, I'm not implementing for any Rc, I'm implementing for Rc<UpcastTo>, where UpcastTo is in the same crate.
On the other side, I'm able to do it for *mut UserType, despite *mut not being defined in any crate. I know *mut is not a trait, but what's the difference really?
However, you may have noticed that it was possible for &mut UserType. The difference is that &mut _, &_, Box<_> , and Pin<_> are fundamental types,[1] so if T is local &mut T is considered local, and so on. As mentioned in the RFC, making a type constructor fundamental means that adding blanket implementations a breaking change.
Rc<_> is not fundamental. This is probably core to your intuition that certain things should be possible, but aren't.
There are also fundamental traits, but I don't think they are any help to you; coherence allows some non-local negative reason for foreign fundamental traits, but they're still not considered local traits in terms of the orphan rules.
I'll mark it as the accepted answer because I an use crates.io: Rust Package Registry to avoid the need to depend on the nightly compiler. Thanks a lot!
use nightly_crimes::nightly_crimes;
nightly_crimes! {
#![feature(unsize)]
impl<From, To> UpcastTo<::std::rc::Rc<To>> for ::std::rc::Rc<From>
where
From: ?Sized + core::marker::Unsize<To>,
To: ?Sized,
{
fn upcast_to(self) -> ::std::rc::Rc<To> {
self as ::std::rc::Rc<To>
}
}
}