Downcasting a Rc<RefCell<Box<struct>>> to Rc<RefCell<Box<dyn trait>>> - rust

I have the following struct.
It is just a wrapper for a vector of a given data type T:
#[derive(Debug)]
pub struct Port<T: 'static + Copy + Debug> {
pub name: String,
values: Vec<T>,
}
This structure implements the trait PortTrait.
On the other hand, I have the following structure
#[derive(Debug)]
pub struct Component {
pub name: String,
ports: HashMap<String, Rc<RefCell<Box<dyn PortTrait>>>>,
}
Components share ports to communicate. I want to use a method to i) create a new port Port<T>, ii) add this new port to the component, and iii) return a pointer to the newly created port.
So far, I got this:
impl Component {
fn add_in_port<T: 'static + Copy + Debug>(&mut self, port_name: &str) -> RcCell<Box<Port<T>>> {
let port = RcCell::new(Box::new(Port::<T>::new(port_name)));
let x: RcCell<Box<dyn PortTrait>> = RcCell::clone(&port); // this fails
self.ports.insert(port_name.to_string(), x);
port
}
}
This fails in compilation time when trying to downcast the clone of the port to a dyn PortInterface.
Do you know any way to do this?

You need to get rid of the Box.
The problem is that we allocated Rc<RefCell<Box<Port<T>>>>. Box<Port<T>> has a size of 1 usize, but now you want to convert it to Box<dyn PortTrait> which has size of 2 usizes - but there is no place in the Rc to store it!
Luckily, you don't need Box: Rc<RefCell<dyn Trait>> works just fine.
#[derive(Debug)]
pub struct Component {
pub name: String,
ports: HashMap<String, Rc<RefCell<dyn PortTrait>>>,
}
impl Component {
fn add_in_port<T: 'static + Copy + Debug>(&mut self, port_name: &str) -> Rc<RefCell<Port<T>>> {
let port = Rc::new(RefCell::new(Port::<T>::new(port_name)));
let x = Rc::clone(&port) as Rc<RefCell<dyn PortTrait>>;
self.ports.insert(port_name.to_string(), x);
port
}
}
Playground.

Related

Borrow Checker being very careful, ' ' is a reference, so the data it referes to cannot be borrowed as mutable

I'm working with Rust and I'm struggling with a certain situation to overcome the Compiliers Borrow checker.
I have a situation where I need to implement a Struct. During the initialization of the implementation, I need to pass a reference to the Struct, Repo, to another implementation, before its fully initialized.
The 2nd Struct, Backend, implements a connection to a database. After the connection has been made it needs to pull information from the DB, and populates a field of the first Struct. Its during this process the Backend Struct needs to be updated with the information from the DB
Here is a MUC.
use std::{collections::HashMap, borrow::BorrowMut};
use serde_json::Value;
#[derive(Debug)]
pub enum BackendError {
Generic(String),
}
impl From<sqlite::Error> for BackendError{
fn from(error: sqlite::Error) -> Self{
BackendError::Generic(error.to_string())
}
}
pub struct Entry {
pub version: String,
pub val: Value,
}
// Information needed by the repository functionality
pub struct Repo{
pub values: HashMap<String,HashMap<String, Entry>>,
backend: Box<dyn Backend>
}
impl Repo {
pub fn new() -> Repo{
// initialize Persistence backend and load any prior status_values based on backend selection
let inst = init_backend_provider();
let repo = Repo {
values: HashMap::new(),
backend: inst ,
};
match repo.backend.load(&repo){
Ok(s) => s,
Err(e) => log::error!("{:?}", e),
}
repo
}
}
// ---------------------------------------------------
pub trait Backend: Send + Sync{
fn load(&self, repo: &Repo) -> Result<(), BackendError>;
}
pub fn init_backend_provider() -> Box<dyn Backend>{
Box::new(DB::new())
}
pub struct DB{}
impl DB{
fn new () -> Self{
DB{}
}
}
impl Backend for DB{
fn load(&self, repo: &Repo) -> Result<(), BackendError>{
// let key_value = repo.values.entry("key".to_string()).or_insert(HashMap::new());
Ok(())
}
}
fn main(){
let repo = Repo::new();
}
The error I'm getting is obvious. I can't borrow the data as mutable if its a reference.
I've attempted to pass it as a mutable reference, &mut.
... match repo.backend.load(&mut repo) ...
That causes the compiler to complain that I'm trying to borrow as mutable from something that is already an immutable borrow. Ok, no problem, lets just make the instance mutable.
let mut repo = Repo {
values: HashMap::new(),
backend: inst ,
};
match repo.backend.load(&mut repo)
Long story, I've tried multiple combinations of making repo mutable, and the parameters with no success.
What I'm trying to do
When I call load(), I want to pass the Struct reference. This way I can look at the Hashmap, Value. I want to look at that first level entry, either creating a new entry or pulling that entry and updating it. In this situation, it will always need to be created as its part of the initialization process. Once I've created that entry, I'll call the DB and request all available fields of a particular table. This all works, so I'm not overloading the MUC with code that works.
I think the question you should ask yourself is not "How do I make it mutable?" but instead "How should I really design my structs and interfaces?".
The API you have currently means that initializing a Backend requires ... itself? Which is absolute nonsense.
Why do I say that? Because Backend::load requires a &Repo, which contains a Backend. So load takes itself as a parameter.
Rust borrow checker is correct in complaining about this; your interpretation of what it complains about is wrong, though. Your problem is not mutability, but that your API makes no sense.
What you should actually do: don't give Backend::init a reference to itself. It only requires values, so give it that. Then it works:
use serde_json::Value;
use std::collections::HashMap;
#[derive(Debug)]
pub enum BackendError {
Generic(String),
}
impl From<sqlite::Error> for BackendError {
fn from(error: sqlite::Error) -> Self {
BackendError::Generic(error.to_string())
}
}
pub struct Entry {
pub version: String,
pub val: Value,
}
// Information needed by the repository functionality
pub struct Repo {
pub values: HashMap<String, HashMap<String, Entry>>,
backend: Box<dyn Backend>,
}
impl Repo {
pub fn new() -> Repo {
// initialize Persistence backend and load any prior status_values based on backend selection
let inst = init_backend_provider();
let mut repo = Repo {
values: HashMap::new(),
backend: inst,
};
match repo.backend.load(&mut repo.values) {
Ok(s) => s,
Err(e) => log::error!("{:?}", e),
}
repo
}
}
// ---------------------------------------------------
pub trait Backend: Send + Sync {
fn load(
&self,
values: &mut HashMap<String, HashMap<String, Entry>>,
) -> Result<(), BackendError>;
}
pub fn init_backend_provider() -> Box<dyn Backend> {
Box::new(DB::new())
}
pub struct DB {}
impl DB {
fn new() -> Self {
DB {}
}
}
impl Backend for DB {
fn load(
&self,
values: &mut HashMap<String, HashMap<String, Entry>>,
) -> Result<(), BackendError> {
let key_value = values.entry("key".to_string()).or_insert(HashMap::new());
Ok(())
}
}
fn main() {
let repo = Repo::new();
}
There are of course many other architectural ways to solve this self-referential API. The basic problem is that if Repo requires a Backend, but Backend also requires a Repo, your dependency tree isn't a tree, but a circle. You should ask yourself: who really depends on what? And then build a struct layout whose dependencies are actually a tree.

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 do I implement an iterator from a vector of std::Rc<std::RefCell<T>> smart pointers?

I'm trying to understand how to work with interior mutability. This question is strongly related to my previous question.
I have a generic struct Port<T> that owns a Vec<T>. We can "chain" port B to port A so, when reading the content of port A, we are able to read the content of port B. However, this chaining is hidden to port A's reader. That is why I implemented the iter(&self) method:
use std::rc::Rc;
pub struct Port<T> {
values: Vec<T>,
ports: Vec<Rc<Port<T>>>,
}
impl <T> Port<T> {
pub fn new() -> Self {
Self { values: vec![], ports: vec![] }
}
pub fn add_value(&mut self, value: T) {
self.values.push(value);
}
pub fn is_empty(&self) -> bool {
self.values.is_empty() && self.ports.is_empty()
}
pub fn chain_port(&mut self, port: Rc<Port<T>>) {
if !port.is_empty() {
self.ports.push(port)
}
}
pub fn iter(&self) -> impl Iterator<Item = &T> {
self.values.iter().chain(
self.ports.iter()
.flat_map(|p| Box::new(p.iter()) as Box<dyn Iterator<Item = &T>>)
)
}
pub fn clear(&mut self) {
self.values.clear();
self.ports.clear();
}
}
The application has the following pseudo-code behavior:
create ports
loop:
fill ports with values
chain ports
iterate over ports' values
clear ports
The main function should look like this:
fn main() {
let mut port_a = Rc::new(Port::new());
let mut port_b = Rc::new(Port::new());
loop {
port_a.add_value(1);
port_b.add_value(2);
port_a.chain_port(port_b.clone());
for val in port_a.iter() {
// read data
};
port_a.clear();
port_b.clear();
}
}
However, the compiler complains:
error[E0596]: cannot borrow data in an `Rc` as mutable
--> src/modeling/port.rs:46:9
|
46 | port_a.add_value(1);
| ^^^^^^ cannot borrow as mutable
|
= help: trait `DerefMut` is required to modify through a dereference, but it is not implemented for `Rc<Port<i32>>`
I've been reading several posts etc., and it seems that I need to work with Rc<RefCell<Port<T>>> to be able to mutate the ports. I changed the implementation of Port<T>:
use std::cell::RefCell;
use std::rc::Rc;
pub struct Port<T> {
values: Vec<T>,
ports: Vec<Rc<RefCell<Port<T>>>>,
}
impl<T> Port<T> {
// snip
pub fn chain_port(&mut self, port: Rc<RefCell<Port<T>>>) {
if !port.borrow().is_empty() {
self.ports.push(port)
}
}
pub fn iter(&self) -> impl Iterator<Item = &T> {
self.values.iter().chain(
self.ports
.iter()
.flat_map(|p| Box::new(p.borrow().iter()) as Box<dyn Iterator<Item = &T>>),
)
}
// snip
}
This does not compile either:
error[E0515]: cannot return value referencing temporary value
--> src/modeling/port.rs:35:31
|
35 | .flat_map(|p| Box::new(p.borrow().iter()) as Box<dyn Iterator<Item = &T>>),
| ^^^^^^^^^----------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| | |
| | temporary value created here
| returns a value referencing data owned by the current function
I think I know what the problem is: p.borrow() returns a reference to the port being chained. We use that reference to create the iterator, but as soon as the function is done, the reference goes out of scope and the iterator is no longer valid.
I have no clue on how to deal with this. I managed to implement the following unsafe method:
pub fn iter(&self) -> impl Iterator<Item = &T> {
self.values.iter().chain(self.ports.iter().flat_map(|p| {
Box::new(unsafe { (&*p.as_ref().as_ptr()).iter() }) as Box<dyn Iterator<Item = &T>>
}))
}
While this works, it uses unsafe code, and there must be a safe workaround.
I set a playground for more details of my application. The application compiles and outputs the expected result (but uses unsafe code).
You can't modify anything behind an Rc, that's correct. While this might be solved with a RefCell, you don't want to go down that road. You might come into a situation where you'd need to enforce a specific clean() order or similar horrors.
More important: your main is fundamentally flawed, ownership-wise. Take these lines:
let mut port_a = Port::new();
let mut port_b = Port::new();
loop {
// Creates an iummutable borrow of port_b with same lifetime as port_a!
port_a.chain_port(port_b);
// ...
// A mutable borrow of port_b.
// But the immutable borrow from above persists across iterations.
port_b.clear();
// Or, even if you do fancy shenanigans at least until this line.
port_a.clear();
}
To overcome this, just constrain the ports lifetime to one iteration. You currently manually clean them up anyway, so that's already what you're doing conceptually.
Also, I got rid of that recursive iteration, just to simplify things a little more.
#[derive(Clone)]
pub struct Port<'a, T> {
values: Vec<T>,
ports: Vec<&'a Port<'a, T>>,
}
impl<'a, T> Port<'a, T> {
pub fn new() -> Self {
Self {
values: vec![],
ports: vec![],
}
}
pub fn add_value(&mut self, value: T) {
self.values.push(value);
}
pub fn is_empty(&self) -> bool {
self.values.is_empty() && self.ports.is_empty()
}
pub fn chain_port(&mut self, port: &'a Port<T>) {
if !port.is_empty() {
self.ports.push(&port)
}
}
pub fn iter(&self) -> impl Iterator<Item = &T> {
let mut port_stack: Vec<&Port<T>> = vec![self];
// Sensible estimate I guess.
let mut values: Vec<&T> = Vec::with_capacity(self.values.len() * (self.ports.len() + 1));
while let Some(port) = port_stack.pop() {
values.append(&mut port.values.iter().collect());
port_stack.extend(port.ports.iter());
}
values.into_iter()
}
}
fn main() {
loop {
let mut port_a = Port::new();
let mut port_b = Port::new();
port_a.add_value(1);
port_b.add_value(2);
port_a.chain_port(&port_b);
print!("values in port_a: [ ");
for val in port_a.iter() {
print!("{} ", val);
}
println!("]");
}
}

Cannot Add needed Traits to an Imported Crate Struct's Constructor Function

I'm trying to implement a globally accessible undo/redo functionality in my Rust app via the undo crate.
I start by creating a lazy static which contains my app's data model, APP_STATE:AppState, which has field history of type undo::history::History. My problem is that lazy static requires Send+Sync for all of my states field, and while I'm able to define the proper trait constraints in the AppState definition (history: History<Box<dyn AppAction>, Box<dyn FnMut(Signal) + Send + Sync>>), I don't see any option for adding these traits when I call History::new() inside of AppState::new():
use undo::{History};
lazy_static::lazy_static!{
static ref APP_STATE: AppState = AppState::new();
}
pub struct AppState{
names: Vec<String>,
history: History<Box<dyn AppAction>, Box<dyn FnMut(Signal) + Send + Sync>>
//correct trait constraints
}
impl AppState{
pub fn new()->Self{
AppState{
names: vec![],
history: History::new(),
//not sure how to add these trait constraints here
}
}
}
//..
Gives error:
history: History::new(),
^^^^^^^^^^^^^^ expected trait `FnMut(Signal) + Send + Sync`, found trait `FnMut(Signal)`
If History::new() does not provide any way for me to add Send+Sync, does that mean I manually instantiate a History struct? What are some work around for this problem?
impl AppState{
pub fn new()->Self{
AppState{
names: vec![],
history: History{
//field 1
//field 2
//..
},
}
}
}
Definition of the undo::history::History struct from the source code:
pub struct History<A, F = Box<dyn FnMut(Signal)>> {
root: usize,
next: usize,
pub(crate) saved: Option<At>,
pub(crate) record: Record<A, F>,
pub(crate) branches: BTreeMap<usize, Branch<A>>,
}

Can I implement a trait which adds information to an external type in Rust?

I just implemented a simple trait to keep the history of a struct property:
fn main() {
let mut weight = Weight::new(2);
weight.set(3);
weight.set(5);
println!("Current weight: {}. History: {:?}", weight.value, weight.history);
}
trait History<T: Copy> {
fn set(&mut self, value: T);
fn history(&self) -> &Vec<T>;
}
impl History<u32> for Weight {
fn set(&mut self, value: u32) {
self.history.push(self.value);
self.value = value;
}
fn history(&self) -> &Vec<u32> {
&self.history
}
}
pub struct Weight {
value: u32,
history: Vec<u32>,
}
impl Weight {
fn new(value: u32) -> Weight {
Weight {
value,
history: Vec::new(),
}
}
}
I don't expect this is possible, but could you add the History trait (or something equivalent) to something which doesn't already have a history property (like u32 or String), effectively tacking on some information about which values the variable has taken?
No. Traits cannot add data members to the existing structures. Actually, only a programmer can do that by modifying the definition of a structure. Wrapper structures or hash-tables are the ways to go.
No, traits can only contain behavior, not data. But you could make a struct.
If you could implement History for u32, you'd have to keep the entire history of every u32 object indefinitely, in case one day someone decided to call .history() on it. (Also, what would happen when you assign one u32 to another? Does its history come with it, or does the new value just get added to the list?)
Instead, you probably want to be able to mark specific u32 objects to keep a history. A wrapper struct, as red75prime's answer suggests, will work:
mod hist {
use std::mem;
pub struct History<T> {
value: T,
history: Vec<T>,
}
impl<T> History<T> {
pub fn new(value: T) -> Self {
History {
value,
history: Vec::new(),
}
}
pub fn set(&mut self, value: T) {
self.history.push(mem::replace(&mut self.value, value));
}
pub fn get(&self) -> T
where
T: Copy,
{
self.value
}
pub fn history(&self) -> &[T] {
&self.history
}
}
}
It's generic, so you can have a History<u32> or History<String> or whatever you want, but the get() method will only be implemented when the wrapped type is Copy.* Your Weight type could just be an alias for History<u32>. Here it is in the playground.
Wrapping this code in a module is a necessary part of maintaining the abstraction. That means you can't write weight.value, you have to call weight.get(). If value were marked pub, you could assign directly to weight.value (bypassing set) and then history would be inaccurate.
As a side note, you almost never want &Vec<T> when you can use &[T], so I changed the signature of history(). Another thing you might consider is returning an iterator over the previous values (perhaps in reverse order) instead of a slice.
* A better way of getting the T out of a History<T> is to implement Deref and write *foo instead of foo.get().

Resources