Access a composition field of a struct from Trait - rust

In the following example, is there any way to access the comp_field within the implementation of BaseTrait for MyStruct?
pub trait CompositionTrait {
//methods
}
pub trait BaseTrait {
fn get_comp_field(&self) -> Box<dyn CompositionTrait>;
}
pub struct MyStruct {
pub comp_field: Box<dyn CompositionTrait>
}
impl MyStruct {
pub fn new(config: Config) -> Result<Self, Error> {
// here based on config, comp_field is assigned with different structs, all of which implements CompositionTrait.
}
}
impl BaseTrait for MyStruct {
fn get_comp_field(&self) -> Box<dyn CompositionTrait> {
self.comp_field // Error
}
}
The following error is presented for the current implementation:
cannot move out of `self.comp_field` which is behind a shared reference
move occurs because `self.comp_field` has type `std::boxed::Box<dyn BaseTrait::CompositionTrait>`, which does not implement the `Copy` trait
The eventual need for such implementation would be accessing the methods of comp_field in the functions which are based on BaseTrait.

The error occurs because you're trying to move the box out of the struct, but the struct is not mutable (and even if it was you would need to put something else in place of the box you're removing). Instead you should return a reference to the CompositionTrait:
pub trait CompositionTrait {
//methods
}
pub trait BaseTrait {
fn get_comp_field(&self) -> &dyn CompositionTrait;
}
pub struct MyStruct {
pub comp_field: Box<dyn CompositionTrait>
}
impl BaseTrait for MyStruct {
fn get_comp_field(&self) -> &dyn CompositionTrait {
&*self.comp_field // Or self.comp_field.as_ref()
}
}
Playground

Related

Implement methods for trait without additional traits

Looking for "blanket" implementation of the method(s) for trait.
Let's say for a trait
pub trait A {
fn do_a(&self);
}
want to have boxed method that wraps with box, without introducing any additional traits:
fn boxed(self) -> Box<Self>;
I can have another trait to achieve that (playground)
pub trait A {
fn do_a(&self);
}
pub trait Boxed {
fn boxed(self) -> Box<Self>;
}
impl<T> Boxed for T
where
T: A,
{
fn boxed(self) -> Box<Self> {
Box::new(self)
}
}
However, new trait Boxed is required for that.
You can add boxed directly to A with a default implementation so that structs won't need to implement it themselves:
trait A {
fn do_a(&self);
fn boxed (self) -> Box<Self>
where Self: Sized
{
Box::new (self)
}
}
struct Foo{}
impl A for Foo {
fn do_a (&self) {
todo!();
}
// No need to redefine `boxed` here
}
fn main() {
let foo = Foo{};
let _object: Box<dyn A> = foo.boxed();
}
Playground

Is it possible to change generic lifetime of a struct?

I have an existing library which exposes a necessary data via reference to a struct with lifetime parameter. The problem is that I need to expose it using wasm_bindgen. For that I've created a separate struct in my wasm module:
#[wasm_bindgen]
struct Event {
// doesn't compile - passed from another lib
inner: &'a InnerEvent<'b>
}
impl<'a,'b> From<&'a InnerEvent<'b>> for Event {
fn from(e: &'a InnerEvent<'b>) -> Self {
Event { inner: e }
}
}
Now, the problem is that 'a and 'b are lifetimes that are passed from an outer library, but wasm-bindgen limitations doesn't allow for a Rust struct that's about to be accessible via WebAssembly to contain any generic params on its own - therefore Event cannot define any references to 'a or 'b.
While I can get rid of 'a by using raw pointers, I cannot do the same with 'b. Technically I can mock it with 'static, however I'm unable to change struct's generic lifetime param from 'a to 'static.
How can I keep reference to an &'a InnerEvent<'b> in a way that doesn't collide with wasm-bindgen restrictions?
EDIT:
My particular use case looks like follows - I'm writing a wrapper over a library, that enables a pub/sub for custom user data:
pub struct Transaction<'txn> {
// .. omitted fields
}
pub struct SomeStruct {
pub fn subscribe<F>(&mut self, f: F) -> Subscription
where F: Fn(&Transaction, &Event) -> () + 'static {
// .. method body
}
}
Now I need to expose SomeStruct over to WebAssembly. For this I'm creating a wasm-bingen wrapper, and I need it to be able to expose its subscribe capabilities over to a JavaScript side:
#[wasm_bindgen]
pub struct SomeStructWrapper(SomeStruct);
#[wasm_bindgen]
impl SomeStructWrapper {
#[wasm_bindgen]
pub fn observe(&mut self, f: js_sys::Function) -> SubscriptionWrapper {
let sub = self.0.observe(move |transaction, event| {
// transaction is: &'a Transaction<'txn> and event: &'a Event
let e = EventWrapper::new(e, txn);
let arg: JsValue = e.into();
f.call1(&JsValue::UNDEFINED, &arg);
});
SubscriptionWrapper(sub)
}
}
#[wasm_bindgen]
pub struct SubscriptionWrapper(Subscription);
Now the problem is that I need to references to both of the rust callback parameters (transaction and event) inside of JavaScript callback. This means that EventWrapper needs to store them as fields:
// code below won't compile because
// wasm_bindgen doesn't allow its structs to declare lifecycle parameters
#[wasm_bindgen]
pub struct EventWrapper {
transaction: &'a Transaction<'txn>,
inner_event: &'a Event,
}
// we can get rid of 'a by casting references to raw pointers
// but this won't fix issue with 'txn lifecycle
#[wasm_bindgen]
pub struct EventWrapper {
transaction: *const Transaction<'txn>,
inner_event: *const Event,
}
In the below code, it get error `error: structs with #[wasm_bindgen] cannot have lifetime or type parameters currently?
use wasm_bindgen::prelude::*;
struct InnerEvent<'a> {
_a: &'a str
}
#[wasm_bindgen]
struct Event<'a,'b> where 'a: 'b {
inner: &'a InnerEvent<'b>
}
impl<'a,'b> From<&'a InnerEvent<'b>> for Event<'a,'b> {
fn from(e: &'a InnerEvent<'b>) -> Self {
Event { inner: e }
}
}
Output
error: structs with #[wasm_bindgen] cannot have lifetime or type parameters currently
--> src\lib.rs:8:13
|
8 | struct Event<'a,'b> where 'a: 'b {
| ^^^^^^^
You can get around like that
use wasm_bindgen::prelude::*;
struct InnerEvent<'a> {
_a: &'a str
}
struct Event<'a,'b> where 'a: 'b {
inner: &'a InnerEvent<'b>
}
impl<'a,'b> From<&'a InnerEvent<'b>> for Event<'a,'b> {
fn from(e: &'a InnerEvent<'b>) -> Self {
Event { inner: e }
}
}
#[wasm_bindgen]
struct WrapEvent
{
i: Event<'static, 'static>
}
But this meet your requierement?
This issue is also discussed here How to get rid of lifetime in wrapper struct for wasm_bindgen

How can a Rust trait object return another trait object?

How can I attempt something like the following in Rust?
The builder class is a trait object which returns another trait object (type erasure) where the implementation that is selected is defined by the specific object of the builder trait that we are using.
trait Builder {
// I want this trait to return a trait object
fn commits(&self) -> dyn Commit;
fn finish(&self);
}
trait Commit {
}
struct FooBuilder {
}
struct FooCommit {
}
impl Builder for FooBuilder {
fn commits(&self) -> impl Commit {
FooCommit{ }
}
fn finish(&self) {
}
}
fn get_commits(b: &Builder) {
// trait object returns a trait
let c = b.commits();
}
fn main() {
let b = FooBuilder{};
get_commits(&b);
b.finish();
}
There is no problem returning trait objects from trait methods in Rust:
trait Foo {
fn bar(&self) -> Box<dyn Bar>;
}
One thing to notice is that you need to return Box<dyn Bar>, not dyn Bar, since size of dyn Bar is not known at compiled time, which renders it useless.
When you implement this trait, the signature has to match, so it should return Box<dyn Bar>, not impl Bar:
impl Foo for MyFoo {
fn bar(&self) -> Box<dyn Bar> {
Box::new(MyBar{})
}
}

Trying to apply polymorphism with Box<_> has the error "cannot move a value ... the size cannot be statically determined"

I am applying the polymorphism solution in Rust to my problem. I would like to use this solution with Box<_> as it seems the most straight and simple, but it doesn't work.
#[derive(Clone, Copy)]
pub struct NewPost;
#[derive(Clone, Copy)]
pub struct Post;
#[derive(Clone, Copy)]
pub struct PgConnection;
#[derive(Clone, Copy)]
pub struct DBPost;
pub trait DBAdapter {
fn create(self, post: NewPost) -> Post;
fn read(self) -> Vec<Post>;
}
impl DBPost {
// DATABASE classes
pub fn establish_connection(self) -> PgConnection {
unimplemented!()
}
}
impl DBAdapter for DBPost {
fn create(self, _post: NewPost) -> Post {
unimplemented!()
}
fn read(self) -> Vec<Post> {
unimplemented!()
}
}
struct GetPostsCase {
db: Box<dyn DBAdapter>,
}
impl GetPostsCase {
pub fn new(db: Box<dyn DBAdapter>) -> GetPostsCase {
GetPostsCase { db: db }
}
pub fn run(&self) -> Vec<Post> {
let result = self.db.read();
result
}
}
The error is:
error[E0161]: cannot move a value of type dyn DBAdapter: the size of dyn DBAdapter cannot be statically determined
--> src/lib.rs:45:22
|
45 | let result = self.db.read();
| ^^^^^^^
error[E0507]: cannot move out of `*self.db` which is behind a shared reference
--> src/lib.rs:45:22
|
45 | let result = self.db.read();
| ^^^^^^^ move occurs because `*self.db` has type `dyn DBAdapter`, which does not implement the `Copy` trait
Your read method takes the (unsized) value instead of taking a reference (whose size is always the same).
You can solve the problem by changing the contract of DBAdapter
from
fn read(self) -> Vec<Post> {
to
fn read(&self) -> Vec<Post> {
// ^--- added the ampersand
(depending on your implementation you might need &mut)

Two similar code snippets but only one triggers a lifetime error

#![feature(rustc_private)]
extern crate rustc;
use rustc::hir::intravisit as hir_visit;
use rustc::hir;
use std::marker::PhantomData;
// ----------------------------------------------------------------------------
// Why does this compile?
// ----------------------------------------------------------------------------
pub struct Map<'a> {
pub _m: PhantomData<&'a ()>,
}
pub struct SomeVisitor<'a, 'tcx: 'a> {
pub map: &'a Map<'tcx>,
}
pub enum NestedVisitorMap<'this, 'tcx: 'this> {
None,
OnlyBodies(&'this Map<'tcx>),
All(&'this Map<'tcx>),
}
pub trait Visitor<'v>: Sized {
fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'v>;
}
impl<'v, 'tcx> Visitor<'v> for SomeVisitor<'v, 'tcx> {
fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'v> {
NestedVisitorMap::All(self.map)
}
}
// ----------------------------------------------------------------------------
// Why does this *not* compile?
// ----------------------------------------------------------------------------
pub struct SomeVisitor2<'a, 'tcx: 'a> {
pub map: &'a hir::map::Map<'tcx>,
}
impl<'v, 'tcx> hir_visit::Visitor<'v> for SomeVisitor2<'v, 'tcx> {
fn nested_visit_map<'this>(&'this mut self) -> hir_visit::NestedVisitorMap<'this, 'v> {
hir_visit::NestedVisitorMap::All(self.map)
}
}
fn main() {}
playground
NestedVisitorMap and Visitor
I recently ran into a lifetime issue and I decided to recreate it without any dependencies. The odd thing is that I can not recreate the lifetime error. To me both implementations look the same from the outside, but only one compiles successfully. Why is that?
rustc 1.21.0-nightly (e26688824 2017-08-27)
Update:
The problem seems to be the RefCell inside Map.
#[derive(Clone)]
pub struct Map<'hir> {
inlined_bodies: RefCell<rustc::util::nodemap::DefIdMap<&'hir hir::Body>>,
}
If there is a RefCell with a inner lifetime, it will trigger an error.
playground
Update2:
It turns out that I just mixed up lifetime subtyping. playground
I still don't know why only RefCell causes the error.

Resources