How to get mutable struct from boxed trait - rust

I'd like to modify data in a struct based on a trait that is boxed. The following code prints the value but gives me "cannot mutably borrow immutable field" when I try to change it or "cannot borrow as mutable" when calling its function.
My plan is to have a vector of Ai each containing the AiData derived struct and then iterate over them, set some data in it and call the tick() function.
use std::any::Any;
pub trait AiData {
fn tick(&mut self);
fn as_any(&self) -> &Any;
}
pub struct Ai {
pub ai_data: Box<AiData>,
}
impl Ai {
pub fn new(ai_data: Box<AiData>) -> Ai {
Ai { ai_data: ai_data }
}
}
pub struct TestAi {
pub index: u8,
}
impl TestAi {
pub fn new() -> TestAi {
TestAi { index: 1 }
}
}
impl AiData for TestAi {
fn tick(&mut self) {
println!("tick");
}
fn as_any(&self) -> &Any {
self
}
}
fn main() {
let ai_data: TestAi = TestAi::new();
let ai: Ai = Ai::new(Box::new(ai_data));
let b: &TestAi = match ai.ai_data.as_any().downcast_ref::<TestAi>() {
Some(b) => b,
None => panic!("&a isn't a B!"),
};
println!("{:?}", b.index);
b.tick();
b.index = 2;
}
error[E0596]: cannot borrow immutable borrowed content `*b` as mutable
--> src/main.rs:48:5
|
48 | b.tick();
| ^ cannot borrow as mutable
error[E0594]: cannot assign to immutable field `b.index`
--> src/main.rs:49:5
|
49 | b.index = 2;
| ^^^^^^^^^^^ cannot mutably borrow immutable field

How to get mutable struct from boxed trait
You cannot get a struct from the boxed trait object. You can get a reference to the struct, however.
As explained in The Rust Programming Language's chapter on variables and mutability, mutability is a property of the binding. Additionally, as described in the chapter on references and borrowing, a mutable reference (&mut T) is distinct from an immutable reference (&T). Based on these two points, you cannot get a mutable reference from an immutable variable1.
The code has:
An immutable variable
An immutable reference to that variable
Calls Any::downcast_ref, which returns an immutable reference
When you fix all of those, the code works:
use std::any::Any;
pub trait AiData {
fn tick(&mut self);
fn as_any_mut(&mut self) -> &mut Any;
}
pub struct Ai {
pub ai_data: Box<AiData>,
}
impl Ai {
pub fn new(ai_data: Box<AiData>) -> Ai {
Ai { ai_data }
}
}
pub struct TestAi {
pub index: u8,
}
impl TestAi {
pub fn new() -> TestAi {
TestAi { index: 1 }
}
}
impl AiData for TestAi {
fn tick(&mut self) {
println!("tick");
}
fn as_any_mut(&mut self) -> &mut Any {
self
}
}
fn main() {
let ai_data = TestAi::new();
let mut ai = Ai::new(Box::new(ai_data));
let b = ai.ai_data
.as_any_mut()
.downcast_mut::<TestAi>()
.expect("&a isn't a B!");
println!("{:?}", b.index);
b.tick();
b.index = 2;
}
1 You can read about interior mutability which actually does allow you to get a mutable reference from an immutable variable, at the expense of introducing runtime checks to prevent aliasing.
See also:
Rust: downcasting and Box<Any>
How to get a struct reference from a boxed trait?

Related

How to downcast mutable structs not as references

I have this trait and implementation:
#[async_trait]
pub trait AsyncKeyProvider {
async fn get_key_async(&mut self, key_id: &str) -> Result<Option<Jwk>, ()>;
fn as_any(&self) -> &dyn Any;
}
#[async_trait]
impl AsyncKeyProvider for GoogleKeyProvider {
async fn get_key_async(&mut self, key_id: &str) -> Result<Option<Jwk>, ()> {
{...}
}
fn as_any(&self) -> &dyn Any {
self
}
}
In order to pass it into my handler in actix-web, I'm passing through a GoogleKeyProvider like this:
let key_provider = web::Data::from(Arc::new(GoogleKeyProvider::default()));
let server = HttpServer::new(move || {
App::new()
.app_data(key_provider.clone())
.route("/validate", web::post().to(validate))
})
With the handler doing this:
pub async fn validate(jwt_body: web::Json<JwtBody>, provider: web::Data<Box<dyn AsyncKeyProvider>>) -> impl Responder {
let provider_object: &GoogleKeyProvider = provider.as_any().downcast_ref::<GoogleKeyProvider>().expect("Wasn't a GoogleKeyProvider");
match validate_jwt(&jwt_body.jwt, provider_object).await {
{...}
}
}
validate_jwt then tries to call a method on the provider struct like this:
async fn validate_jwt(jwt: &String, provider: &GoogleKeyProvider) -> Result<bool, Box<dyn std::error::Error>> {
let key_to_use = provider.get_key_async(<thing>).await.unwrap();
}
Which presents me with this error:
error[E0596]: cannot borrow `*provider` as mutable, as it is behind a `&` reference
--> src\routes\validate.rs:48:22
|
48 | let key_to_use = provider.get_key_async(<thing>).await.unwrap();
| ^^^^^^^^ `provider` is a `&` reference, so the data it refers to cannot be borrowed as mutable
As far as I can understand, this is happening because the result of my downcasting is a reference (due to downcast_ref), but I think I'd be wanting the plain GoogleKeyProvider type instead - I'm not sure on that though. I believe the provider needs to be mutable as the values inside it (see below) can change during the lifetime of the provider (it's intended to provide a temporary cache for some keys, and automatically update them if they're out of date)
#[derive(Clone)]
pub struct GoogleKeyProvider {
cached: Option<JwkSet>,
expiration_time: Instant,
}
I'm not sure how to get this working with downcasting, though. Is anyone able to help me see where I've gone wrong?
You have to choice if get_key_async update somme thing at the struct.
The simple code below show you the error
trait Atrait {
fn afn(&mut self) -> i32;
}
struct Astruct {}
impl Atrait for Astruct {
fn afn(&mut self) -> i32 {
2
}
}
fn main()
{
// test should be mutable
let test = Astruct{};
let value = test.afn();
println!("Value {}", value);
}
This work because afn(self) is not declared mutable afn(&mut self)
trait Atrait {
fn afn(&self) -> i32;
}
struct Astruct {}
impl Atrait for Astruct {
fn afn(&self) -> i32 {
2
}
}
fn main()
{
let test = Astruct{};
let value = test.afn();
println!("Value {}", value);
}

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!("]");
}
}

How can I extend the lifetime of a temporary variable inside of an iterator adaptor in Rust?

I have a method make_iter() which creates an Iterator with multiple adapters in Rust, which can be simplified as the following MCVE:
fn make_iter(first: &First) -> Box<dyn Iterator<Item = String> + '_> {
Box::new(first.make_objects().flat_map(|second| {
second
.iter()
.filter(|third| third.as_str() != "t2")
.flat_map(|third| vec![format!("{}.A", third), format!("{}.B", third)].into_iter())
.chain(
vec![
format!("{}.A", second.name()),
format!("{}.B", second.name()),
]
.into_iter(),
)
}))
}
pub fn main() {
let first = First {};
for i in make_iter(&first) {
println!("{}", i);
}
}
struct First {}
impl First {
fn make_objects(&self) -> Box<dyn Iterator<Item = Second> + '_> {
Box::new(
vec![
Second::new("s1".to_string()),
Second::new("s2".to_string()),
Second::new("s3".to_string()),
]
.into_iter(),
)
}
}
struct Second {
name: String,
objects: Vec<String>,
}
impl Second {
fn new(name: String) -> Second {
Second {
name,
objects: vec!["t1".to_string(), "t2".to_string(), "t3".to_string()],
}
}
fn name(&self) -> &str {
&self.name
}
fn iter(&self) -> Box<dyn Iterator<Item = &String> + '_> {
Box::new(self.objects.iter())
}
}
Trying to compile this example yields a lifetime error:
error[E0597]: `second` does not live long enough
--> src/main.rs:3:9
|
3 | second
| ^^^^^^ borrowed value does not live long enough
...
14 | }))
| - `second` dropped here while still borrowed
This is understandable, as the second object is a temporary, and the iterator returned from the same closure attempts to borrow it, failing as second is dropped at the closure's end.
My objective would be to extend the lifetime of this object until the Iterator referencing it is dropped, but I don't know how.
Note that the structure implementations cannot be changed. Rust version is 1.34.2, edition 2018
extend the lifetime of this object
You cannot do this, period. It's simply not how things work.
See also:
Extend lifetime of variable
Extending borrowed lifetime for String slice
Is there any way to return a reference to a variable created in a function?
Here's a simpler reproduction:
use std::iter;
fn example(outer: impl Iterator<Item = Inner>) {
outer.flat_map(|i| i.iter().map(|v| v.clone()));
}
struct Inner;
impl Inner {
fn iter(&self) -> impl Iterator<Item = &()> + '_ {
iter::empty()
}
}
Since you have the restriction of being unable to change Inner, the easiest solution is to be more eager and proactively collect:
fn example(outer: impl Iterator<Item = Inner>) {
outer.flat_map(|i| i.iter().map(|v| v.clone()).collect::<Vec<_>>());
}
The only possibility I know of to avoid that would be to use a crate like rental or owning_ref.
See also:
Is there an owned version of String::chars?
How can I store a Chars iterator in the same struct as the String it is iterating on?
If you had the possibility of changing Inner, you should make a consuming iterator variant. Then the value does not need to live beyond the closure because the iterator has taken ownership.
use std::iter;
fn example(outer: impl Iterator<Item = Inner>) {
outer.flat_map(|i| i.into_iter().map(|v| v));
}
struct Inner;
impl Inner {
fn into_iter(self) -> impl Iterator<Item = ()> {
iter::empty()
}
}

Borrow checker error after adding generic parameter to struct

I have code that works, but it stops compiling with a borrow checker error after a change. I don't understand how the change could affect borrow checking.
Common part to both working and non-working code:
/// Some struct that has references inside
#[derive(Debug)]
struct MyValue<'a> {
number: &'a u32,
}
/// There are many structs similar to `MyValue` and there is a
/// trait common to them all that can create them. In this
/// example I use the `From` trait.
impl<'a> From<&'a u32> for MyValue<'a> {
fn from(value: &'a u32) -> Self {
MyValue { number: value }
}
}
/// `Producer` makes objects that hold references into it. So
/// the produced object must be first dropped before any new
/// one can be made.
trait Producer<'a, T: 'a> {
fn make(&'a mut self) -> T;
}
Here is the working code:
struct MyProducer {
number: u32,
}
impl MyProducer {
fn new() -> Self {
Self { number: 0 }
}
}
impl<'a, T: 'a + From<&'a u32>> Producer<'a, T> for MyProducer {
fn make(&'a mut self) -> T {
self.number += 1;
T::from(&self.number)
}
}
fn main() {
let mut producer = MyProducer::new();
println!(
"made this: {:?}",
<MyProducer as Producer<MyValue>>::make(&mut producer)
);
println!(
"made this: {:?}",
<MyProducer as Producer<MyValue>>::make(&mut producer)
);
}
This compiles and prints the expected output:
made this: MyValue { number: 1 }
made this: MyValue { number: 2 }
I don't like that MyProducer actually implements Producer for every T as it makes it impossible to call make directly on it. I would like to have a type that is a MyProducer for a specific T (for example for MyValue).
To achieve this, I want to add a generic parameter to MyProducer. Because the MyProducer does not really use the T, I use PhantomData to prevent the compiler from complaining.
Here is the code after changes:
use std::marker::PhantomData;
struct MyProducer<'a, T: 'a + From<&'a u32>> {
number: u32,
_phantom: PhantomData<&'a T>,
}
impl<'a, T: 'a + From<&'a u32>> MyProducer<'a, T> {
fn new() -> Self {
Self {
number: 0,
_phantom: PhantomData::default(),
}
}
}
impl<'a, T: From<&'a u32>> Producer<'a, T> for MyProducer<'a, T> {
fn make(&'a mut self) -> T {
self.number += 1;
T::from(&self.number)
}
}
fn main() {
let mut producer = MyProducer::<MyValue>::new();
println!("made this: {:?}", producer.make());
println!("made this: {:?}", producer.make());
}
The main function now looks exactly as I would like it to look like. But the code does not compile. This is the error:
error[E0499]: cannot borrow `producer` as mutable more than once at a time
--> src/main.rs:50:33
|
49 | println!("made this: {:?}", producer.make());
| -------- first mutable borrow occurs here
50 | println!("made this: {:?}", producer.make());
| ^^^^^^^^
| |
| second mutable borrow occurs here
| first borrow later used here
I don't understand why it no longer works. The produced object is still dropped before the next one is made.
If I call the make function just once, it compiles and works.
I am using edition 2018, so NLL is active.
Rust Playground: working version before change
Rust Playground: broken version after change
I reduced the noise from the code so the following is an even shorter version of the broken case which demonstrates the same problem: (test in the playground)
use std::marker::PhantomData;
#[derive(Debug)]
struct MyValue<'a>(&'a u32);
impl<'a> From<&'a u32> for MyValue<'a> {
fn from(value: &'a u32) -> Self {
MyValue(value)
}
}
struct MyProducer<'a, T>(u32, PhantomData<&'a T>);
impl<'a, T> MyProducer<'a, T>
where
T: From<&'a u32>,
{
fn new() -> Self {
Self(0, PhantomData)
}
fn make(&'a mut self) -> T {
self.0 += 1;
T::from(&self.0)
}
}
fn main() {
let mut producer = MyProducer::<MyValue>::new();
println!("made this: {:?}", producer.make());
println!("made this: {:?}", producer.make());
}
The main problem here is that the mutable borrow's lifetime is the lifetime of MyProducer, that is, the lifetime of the instance called producer is the same as the mutable borrow taken in its make method. Because the producer instance does not go out of scope (if it would then MyValue wouldn't be able to hold a reference to a value stored in it) so the mutable borrow lives until the end of main's scope. The first rule of borrowing is that there can only be a single mutable borrow of a given value in a scope at any time, hence the compiler error.
If you are looking at my solution here, which is actually working and does what I think you wanted it to: (test in the playground):
#[derive(Debug)]
struct MyValue<'a>(&'a u32);
impl<'a> From<&'a u32> for MyValue<'a> {
fn from(value: &'a u32) -> Self {
MyValue(value)
}
}
struct MyProducer(u32);
impl MyProducer {
fn new() -> Self {
Self(0)
}
fn make<'a, T>(&'a mut self) -> T
where
T: From<&'a u32>,
{
self.0 += 1;
T::from(&self.0)
}
}
fn main() {
let mut producer = MyProducer::new();
println!("made this: {:?}", producer.make::<MyValue>());
println!("made this: {:?}", producer.make::<MyValue>());
}
then you can see that the mutable borrow only lives as long as the make method, therefore after the invocation there's no more living mutable borrow to producer in main's scope, thus you can have another one.

Lifetime on trait returning iterator

I'm working with a trait requiring a function returning an iterator without consuming the object. The iterator itself returns copies of data values, not references. As the iterator implementation requires a reference to the object it is iterating over, I end up having to declare lots of lifetimes (more than I would have thought necessary, but could not get it to compile otherwise). I then run into trouble with borrow duration - a minimal "working" example is as follows:
pub trait MyTrait<'a> {
type IteratorType: Iterator<Item=u32>;
fn iter(&'a self) -> Self::IteratorType;
fn touch(&'a mut self, value: u32);
}
struct MyStruct {
data: Vec<u32>
}
struct MyIterator<'a> {
structref: &'a MyStruct,
next: usize,
}
impl<'a> Iterator for MyIterator<'a> {
type Item = u32;
fn next(&mut self) -> Option<u32> {
if self.next < self.structref.data.len() {
self.next += 1;
return Some(self.structref.data[self.next-1]);
} else {
return None;
}
}
}
impl<'a> MyTrait<'a> for MyStruct {
type IteratorType = MyIterator<'a>;
fn iter(&'a self) -> Self::IteratorType {
return MyIterator { structref: &self, next: 0 };
}
fn touch(&'a mut self, value: u32) {
}
}
fn touch_all<'a,T>(obj: &'a mut T) where T: MyTrait<'a> {
let data: Vec<u32> = obj.iter().collect();
for value in data {
obj.touch(value);
}
}
Compiling this gives me the error:
error[E0502]: cannot borrow `*obj` as mutable because it is also borrowed as immutable
|
39 | let data: Vec<u32> = obj.iter().collect();
| --- immutable borrow occurs here
40 | for value in data {
41 | obj.touch(value);
| ^^^ mutable borrow occurs here
42 | }
43 | }
| - immutable borrow ends here
By my limited understanding of lifetimes, I would have thought the immutable borrow only extends to the line where I make it - after all the iterator is consumed and I no longer hold any references to obj or data contained in it. Why does the lifetime of the borrow extend to the entire function, and how do I fix this?
Here is a sequence of steps on how I arrived here - running the code should provide the associated compiler errors.
no explicit lifetimes
IteratorType needs lifetime
Unconstrained lifetime parameter
To clarify: I'd like to be able to make calls like this:
fn main() {
let obj: MyStruct = MyStruct { data : vec![] };
touch_all(&mut obj);
}
rather than having to call
touch_all(&mut &obj);
which would be needed for the proposal by mcarton (1st and 2nd comment).

Resources