How do I clone a Rc trait object and cast it to another trait object? - casting

This is a follow up question from Rust dynamic cast trait object between different taits. The solution provided there works really well when we use references for trait objects, but this time I am trying to do the same with Rc pointers. For example
I have a super trait named TraitAB and 2 traits named TraitA and TraitB
So when I first create a trait object of type TraitAB instead of using a Box, now I use an Rc pointer.
I need a variable of type TraitA to be a reference of ab
Here I made a very minimal example:
use std::rc::Rc;
trait TraitAB: TraitA + TraitB {
fn as_a(&self) -> Rc<dyn TraitA>;
fn as_b(&self) -> Rc<dyn TraitB>;
}
trait TraitA {}
trait TraitB {}
struct MyType {}
impl TraitAB for MyType {
fn as_a(&self) -> Rc<dyn TraitA> {
Rc::clone(self)
}
fn as_b(&self) -> Rc<dyn TraitB> {
Rc::clone(self)
}
}
impl TraitA for MyType {}
impl TraitB for MyType {}
fn main() {
let a: Rc<dyn TraitA>;
let b: Rc<dyn TraitB>;
{
let mut ab: Rc<dyn TraitAB> = Rc::new(MyType {});
a = ab.as_a();
b = ab.as_b();
}
}
This doesn't work though. According to the error messages:
error[E0308]: mismatched types
--> src/main.rs:15:19
|
15 | Rc::clone(self)
| ^^^^ expected struct `std::rc::Rc`, found struct `MyType`
|
= note: expected reference `&std::rc::Rc<dyn TraitA>`
found reference `&MyType`
error[E0308]: mismatched types
--> src/main.rs:18:19
|
18 | Rc::clone(self)
| ^^^^ expected struct `std::rc::Rc`, found struct `MyType`
|
= note: expected reference `&std::rc::Rc<dyn TraitB>`
found reference `&MyType`
as_a and as_b can't know self is actually an Rc pointer.
Is there a way to do the cast of a cloned shared pointer?

methods as_a and as_b can't know self is actually an Rc pointer.
Actually, that's not true! There's a rarely used feature that allows self to be taken as various standard kinds of references (Rc<Self>, Box<Self>, etc.).
That means that you can rewrite your TraitAB as
trait TraitAB : TraitA + TraitB {
fn as_a(self: Rc<Self>) -> Rc<dyn TraitA>;
fn as_b(self: Rc<Self>) -> Rc<dyn TraitB>;
}
Unfortunately, as written, as_a and as_b move self: Rc<Self>, since Rc<T> doesn't implement Copy (only Clone). One way to fix this is to simply clone ab before passing it into these methods. This also means that you don't need to clone the self inside the method. (playground link)
let ab: Rc<dyn TraitAB> = Rc::new(MyType{});
let _a: Rc<dyn TraitA> = ab.clone().as_a();
let _b: Rc<dyn TraitB> = ab.clone().as_b();
Using the nightly-only feature arbitrary_self_types, it's possible to make as_a and as_b take self as &Rc<Self> (which looks weird to me since it's a reference to a reference). This allows ab.as_a() to be called without moving ab. The only problem with this approach is that TraitAB is no longer object-safe1, so Rc<dyn TraitAB> no longer works. (playground link).
According to the tracking issue for arbitrary self types, the object safety question is still open. I'm not really sure what the rules are right now.

You need to implement TraitAB on RC<MyType>:
use std::rc::Rc;
trait TraitAB {
fn as_a(&self) -> Rc<dyn TraitA>;
fn as_b(&self) -> Rc<dyn TraitB>;
}
trait TraitA {}
trait TraitB {}
struct MyType {}
impl TraitAB for Rc<MyType> {
fn as_a(&self) -> Rc<dyn TraitA> {
Rc::clone(self) as Rc<dyn TraitA>
}
fn as_b(&self) -> Rc<dyn TraitB> {
Rc::clone(self) as Rc<dyn TraitB>
}
}
impl TraitA for MyType {}
impl TraitB for MyType {}
fn main() {
let a: Rc<dyn TraitA>;
let b: Rc<dyn TraitB>;
{
let mut ab: &TraitAB = &Rc::new(MyType {});
a = ab.as_a();
b = ab.as_b();
}
}
By the way, I don't see any reason for TraitAB to extend TraitA + TraitB, but you can extend and implement TraitA and TraitB for Rc<MyType> as well.
This is a working example with the implemented functions for TraitA and TraitB.

Related

Make functions instantiate its generic parameter

What would be an equivalent to the following C++ program in rust?
#include <iostream>
#include <vector>
template <typename T>
T stuff() {
return T();
}
int main() {
std::vector<int> vec = stuff<std::vector<int>>();
vec.push_back(1);
for (auto &&i : vec) {
std::cout << i << std::endl;
}
}
I tried the following:
trait Newable{
fn new() -> Self;
}
fn stuff<T: Newable>() -> T {
T::new()
}
I tried using a newtype for this -
struct NwVec<T>{
vec: Vec<T>
}
impl<T> Newable<T> for NwVec<T>{
fn new() -> Self {
NwVec { vec: Vec::new() }
}
}
and used it like so:
fn main() {
let x: NwVec<i32> = stuff::<NwVec<i32>>();
}
but I get a
error[E0277]: the trait bound `NwVec<i32>: Newable<NwVec<i32>>` is not satisfied
--> src\main.rs:2:25
|
2 | let x: NwVec<i32> = stuff();
| ^^^^^ the trait `Newable<NwVec<i32>>` is not implemented for `NwVec<i32>`
|
= help: the following implementations were found:
<NwVec<T> as Newable<T>>
note: required by a bound in `stuff`
Is there a way to achieve what the C++ program achieves?
P.S.: I am rather new to rust, I am really sorry if the solution to this is trivial.
Maybe there was a mixup when you entered the code that you say gave you the error you provided, because that same code did not yield that specific error when I tried it.
Either way, you were close. Consider this code:
trait Newable {
fn new() -> Self;
}
fn stuff<T: Newable>() -> T {
T::new()
}
#[derive(Debug)]
struct NwVec<T> {
vec: Vec<T>
}
impl<T> Newable for NwVec<T> {
fn new() -> Self {
NwVec { vec: Vec::new() }
}
}
fn main() {
let x: NwVec<i32> = stuff::<NwVec<i32>>();
println!("{x:?}");
}
Playground
All I changed was:
Added #[derive(Debug)] to NwVec<T> so we could print it out
I removed the type parameter <T> on Newable<T> from your original impl<T> Newable<T> for NwVec<T>. This is because the Newable trait itself, as provided in your post, is not generic, so it takes no type parameter.
I imagine this is something of a learning exercise, but in case you were curious, you may be interested in std::default::Default which is a trait somewhat similar to your Newable in that implementations provide a simple and consistent way to create a "default" version of something. Vec itself is an implementer, so you can call e.g. Default::default() or Vec::default() wherever a Vec<T> is expected. Check this playground.
Adding to the excellent answer by #JorgeIsraelPeña, in case you insist on Newable, you don't need a newtype. You can implement a trait for a type as long as either the trait or the type are yours (well, the actual rules are a bit more complicated). That means you can implement Newable directly for Vec:
impl<T> Newable for Vec<T> {
fn new() -> Self {
Vec::new()
}
}
fn main() {
let x = stuff::<Vec<i32>>();
println!("{x:?}");
}
Playground.

AST node for accessing struct data members

I just added C-style struct to my toy language, and I am not sure how to represent accesses to data members in my AST. I am considering something like
class StructProperty : public Expr {
std::unique_ptr<Expr> parent_;
std::string property_;
};
so that getParent().data.foo = 42; would be parsed as
AssignStmt:
-> rhs: IntegerLiteral
-> value: 42
-> lvalue: StructProperty
-> name: foo
-> parent: StructProperty
-> name: data
-> parent: FuncCall
-> name: getParent
-> args: none
Does that make any sense? Is that how struct data members are typically represented in ASTs? Is there a better way?

Clone an Rc<RefCell<MyType> trait object and cast it

This question is related to Rust: Clone and Cast Rc pointer
Let's say I have this piece of code which works fine:
use std::rc::Rc;
trait TraitAB : TraitA + TraitB {
fn as_a(self: Rc<Self>) -> Rc<dyn TraitA>;
fn as_b(self: Rc<Self>) -> Rc<dyn TraitB>;
}
trait TraitA {}
trait TraitB {}
struct MyType {}
impl TraitAB for MyType {
fn as_a(self: Rc<Self>) -> Rc<dyn TraitA> {self}
fn as_b(self: Rc<Self>) -> Rc<dyn TraitB> {self}
}
impl TraitA for MyType {}
impl TraitB for MyType {}
fn main() {
let a: Rc<dyn TraitA>;
let b: Rc<dyn TraitB>;
{
let mut ab: Rc<dyn TraitAB> = Rc::new(MyType{});
a = ab.clone().as_a();
b = ab.clone().as_b();
}
// Use a and b.
}
Explaining the code a bit:
I have type called MyType which implements TraitA and TraitB.
The goal is to have a trait object TraitA be able to get casted to TraitB and viceversa.
So I uses a supertrait that holds the methods to do the conversions.
This works great for std::Rc smart pointers.
So far so good. But now I need a mutable reference of both a and b, but since a and bare actually the same type instance, Rust won't let me have 2 mutable references of the same thing.
So, the common pattern for this kind of problems is std::cell::RefCell.
Note: I believe this pattern is correct in this particular case because it's a common interior mutability problem. I'm not willing to actually change the reference, but the internal state of the type only.
So following that idea I changed the following lines:
trait TraitAB : TraitA + TraitB {
fn as_a(self: Rc<RefCell<Self>>) -> Rc<RefCell<dyn TraitA>>;
fn as_b(self: Rc<RefCell<Self>>) -> Rc<RefCell<dyn TraitB>>;
}
//...
let mut ab: Rc<RefCell<dyn TraitAB>> = Rc::new(RefCell::new(MyType{}));
But this changes won't compile. After some reading, I found that self can only be:
self: Self // self
self: &Self // &self
self: &mut Self // &mut self
self: Box<Self> // No short form
self: Rc<Self> // No short form / Recently supported
So this means I can't use
self: Rc<RefCell<Self>>
for the self param.
So, the main question is: Is there a way to cast an Rc<RefCell<TraitA>> to an Rc<RefCell<TraitB> ?
Thanks
You can work around this issue by not using a receiver in TraitAB's casting methods (i.e. by declaring them as associated functions):
trait TraitAB : TraitA + TraitB {
fn as_a(it: Rc<RefCell<Self>>) -> Rc<RefCell<dyn TraitA>>;
fn as_b(it: Rc<RefCell<Self>>) -> Rc<RefCell<dyn TraitB>>;
}
The trait can then be implemented as
impl TraitAB for MyType {
fn as_a(it: Rc<RefCell<MyType>>) -> Rc<RefCell<dyn TraitA>> {it}
fn as_b(it: Rc<RefCell<MyType>>) -> Rc<RefCell<dyn TraitB>> {it}
}
These functions can then be called using the fully qualified syntax.
a = TraitAB::as_a(ab.clone());
b = TraitAB::as_b(ab.clone());
The TraitAB implementation for all types will be the same. To make this implementation available for all types implementing TraitA and TraitB, you can use a generic impl:
impl<T: TraitA + TraitB + 'static> TraitAB for T {
fn as_a(it: Rc<RefCell<T>>) -> Rc<RefCell<dyn TraitA>> {it}
fn as_b(it: Rc<RefCell<T>>) -> Rc<RefCell<dyn TraitB>> {it}
}
Note that T: 'static because the trait objects in the function return types have an implicit 'static lifetime bound.
Playground

Safety of casting arbitrary types to usize

I wrote some code. It works... but is it safe?
use std::mem;
use std::ptr;
use std::marker::PhantomData;
struct Atomic<T: Copy>(AtomicUsize, PhantomData<T>);
impl<T: Copy> Atomic<T> {
unsafe fn encode(src: T) -> usize {
assert!(mem::size_of::<T>() <= mem::size_of::<usize>());
let mut dst = 0;
ptr::write(&mut dst as *mut usize as *mut T, src);
dst
}
unsafe fn decode(src: usize) -> T {
assert!(mem::size_of::<T>() <= mem::size_of::<usize>());
ptr::read(&src as *const usize as *const T)
}
fn new(val: T) -> Atomic<T> {
unsafe {
Atomic(AtomicUsize::new(Self::encode(val)), PhantomData)
}
}
fn load(&self, order: Ordering) -> T {
unsafe { Self::decode(self.0.load(order)) }
}
fn store(&self, val: T, order: Ordering) {
unsafe { self.0.store(Self::encode(val), order) }
}
}
impl<T: Copy + Default> Default for Atomic<T> {
fn default() -> Atomic<T> {
Self::new(T::default())
}
}
As you can see, I write an arbitrary Copy value of small enough size into a usize, and ship it around in an Atomic. I then read it out as a new value.
In essence I use the usize as a memory block of size size_of::<usize>().
If this is safe, the next step is to consider fancier operations.
unsafe trait PackedInt {}
unsafe impl PackedInt for u8 {}
unsafe impl PackedInt for i8 {}
unsafe impl PackedInt for u32 {}
unsafe impl PackedInt for i32 {}
unsafe impl PackedInt for u64 {}
unsafe impl PackedInt for i64 {}
impl<T: Copy + PackedInt> Atomic<T> {
fn compare_and_swap(&self, current: T, new: T, order: Ordering) -> T {
unsafe {
Self::decode(self.0.compare_and_swap(
Self::encode(current),
Self::encode(new),
order
))
}
}
fn fetch_add(&self, val: T, order: Ordering) -> T {
unsafe {
Self::decode(self.0.fetch_add(Self::encode(val), order))
}
}
fn fetch_sub(&self, val: T, order: Ordering) -> T {
unsafe {
Self::decode(self.0.fetch_sub(Self::encode(val), order))
}
}
}
These are of course not always particularly sensible on overflow (since two "equal" values could compare unequal due to bits outside of the T), but they still seem well-defined... I think.
So, is this safe, and why?
It's almost safe... but not quite. You're probably only thinking about people using Atomic with integers and floats, but references are also Copy. A user could easily cause a crash using relaxed loads and stores on an Atomic<&&u32>.
On a side-note, your fetch_add and fetch_sub won't work correctly on big-endian systems.

How can I approximate method overloading?

I am modeling an API where method overloading would be a good fit. My naïve attempt failed:
// fn attempt_1(_x: i32) {}
// fn attempt_1(_x: f32) {}
// Error: duplicate definition of value `attempt_1`
I then added an enum and worked through to:
enum IntOrFloat {
Int(i32),
Float(f32),
}
fn attempt_2(_x: IntOrFloat) {}
fn main() {
let i: i32 = 1;
let f: f32 = 3.0;
// Can't pass the value directly
// attempt_2(i);
// attempt_2(f);
// Error: mismatched types: expected enum `IntOrFloat`
attempt_2(IntOrFloat::Int(i));
attempt_2(IntOrFloat::Float(f));
// Ugly that the caller has to explicitly wrap the parameter
}
Doing some quick searches, I've found some references that talk about overloading, and all of them seem to end in "we aren't going to allow this, but give traits a try". So I tried:
enum IntOrFloat {
Int(i32),
Float(f32),
}
trait IntOrFloatTrait {
fn to_int_or_float(&self) -> IntOrFloat;
}
impl IntOrFloatTrait for i32 {
fn to_int_or_float(&self) -> IntOrFloat {
IntOrFloat::Int(*self)
}
}
impl IntOrFloatTrait for f32 {
fn to_int_or_float(&self) -> IntOrFloat {
IntOrFloat::Float(*self)
}
}
fn attempt_3(_x: &dyn IntOrFloatTrait) {}
fn main() {
let i: i32 = 1;
let f: f32 = 3.0;
attempt_3(&i);
attempt_3(&f);
// Better, but the caller still has to explicitly take the reference
}
Is this the closest I can get to method overloading? Is there a cleaner way?
Yes, there is, and you almost got it already. Traits are the way to go, but you don't need trait objects, use generics:
#[derive(Debug)]
enum IntOrFloat {
Int(i32),
Float(f32),
}
trait IntOrFloatTrait {
fn to_int_or_float(&self) -> IntOrFloat;
}
impl IntOrFloatTrait for i32 {
fn to_int_or_float(&self) -> IntOrFloat {
IntOrFloat::Int(*self)
}
}
impl IntOrFloatTrait for f32 {
fn to_int_or_float(&self) -> IntOrFloat {
IntOrFloat::Float(*self)
}
}
fn attempt_4<T: IntOrFloatTrait>(x: T) {
let v = x.to_int_or_float();
println!("{:?}", v);
}
fn main() {
let i: i32 = 1;
let f: f32 = 3.0;
attempt_4(i);
attempt_4(f);
}
See it working here.
Here's another way that drops the enum. It's an iteration on Vladimir's answer.
trait Tr {
fn go(&self) -> ();
}
impl Tr for i32 {
fn go(&self) {
println!("i32")
}
}
impl Tr for f32 {
fn go(&self) {
println!("f32")
}
}
fn attempt_1<T: Tr>(t: T) {
t.go()
}
fn main() {
attempt_1(1 as i32);
attempt_1(1 as f32);
}
Function Overloading is Possible!!! (well, sorta...)
This Rust Playground example has more a more detailed example, and shows usage of a struct variant, which may be better for documentation on the parameters.
For more serious flexible overloading where you want to have sets of any number of parameters of any sort of type, you can take advantage of the From<T> trait for conversion of a tuple to enum variants, and have a generic function that converts tuples passed into it to the enum type.
So code like this is possible:
fn main() {
let f = Foo { };
f.do_something(3.14); // One f32.
f.do_something((1, 2)); // Two i32's...
f.do_something(("Yay!", 42, 3.14)); // A str, i32, and f64 !!
}
First, define the different sets of parameter combinations as an enum:
// The variants should consist of unambiguous sets of types.
enum FooParam {
Bar(i32, i32),
Baz(f32),
Qux(&'static str, i32, f64),
}
Now, the conversion code; a macro can be written to do the tedious From<T> implementations, but here's what it could produce:
impl From<(i32, i32)> for FooParam {
fn from(p: (i32, i32)) -> Self {
FooParam::Bar(p.0, p.1)
}
}
impl From<f32> for FooParam {
fn from(p: f32) -> Self {
FooParam::Baz(p)
}
}
impl From<(&'static str, i32, f64)> for FooParam {
fn from(p: (&'static str, i32, f64)) -> Self {
FooParam::Qux(p.0, p.1, p.2)
}
}
And then finally, implement the struct with generic method:
struct Foo {}
impl Foo {
fn do_something<T: Into<FooParam>>(&self, t: T) {
use FooParam::*;
let fp = t.into();
match fp {
Bar(a, b) => print!("Bar: {:?}, {:?}\n", a, b),
Baz(a) => print!("Baz: {:?}\n", a),
Qux(a, b, c) => {
print!("Qux: {:?}, {:?}, {:?}\n", a, b, c)
}
}
}
}
Note: The trait bound on T needs to be specified.
Also, the variants need to be composed of combinations of types that the compiler wouldn't find ambiguous - which is an expectation for overloaded methods in other languages as well (Java/C++).
This approach has possibilities... it would be awesome if there's a decorator available - or one were written that did the From<T> implementations automatically when applied to an enum. Something like this:
// THIS DOESN'T EXIST - so don't expect the following to work.
// This is just an example of a macro that could be written to
// help in using the above approach to function overloading.
#[derive(ParameterOverloads)]
enum FooParam {
Bar(i32, i32),
Baz(f32),
Qux(&'static str, i32, f64),
}
// If this were written, it could eliminate the tedious
// implementations of From<...>.
The Builder
Another approach that addresses the case where you have multiple optional parameters to an action or configuration is the builder pattern. The examples below deviate somewhat from the recommendations in the link. Typically, there's a separate builder class/struct which finalizes the configuration and returns the configured object when a final method is invoked.
One of the most relevant situations this can apply to is where you want a constructor that takes a variable number of optional arguments - since Rust doesn't have built-in overloading, we can't have multiple versions of ___::new(). But we can get a similar effect using a chain of methods that return self. Playground link.
fn main() {
// Create.
let mut bb = BattleBot::new("Berzerker".into());
// Configure.
bb.flame_thrower(true)
.locomotion(TractorTreads)
.power_source(Uranium);
println!("{:#?}", bb);
}
Each of the configuration methods has a signature similar to:
fn power_source(&mut self, ps: PowerSource) -> &mut Self {
self.power_source = ps;
self
}
These methods could also be written to consume self and return non-reference copies or clones of self.
This approach can also be applied to actions. For instance, we could have a Command object that can be tuned with chained methods, which then performs the command when .exec() is invoked.
Applying this same idea to an "overloaded" method that we want to take a variable number of parameters, we modify our expectations a bit and have the method take an object that can be configured with the builder pattern.
let mut params = DrawParams::new();
graphics.draw_obj(params.model_path("./planes/X15.m3d")
.skin("./skins/x15.sk")
.location(23.64, 77.43, 88.89)
.rotate_x(25.03)
.effect(MotionBlur));
Alternatively, we could decide on having a GraphicsObject struct that has several config tuning methods, then performs the drawing when .draw() is invoked.