How to create a vector based on an `&[Box<dyn CustomTrait>]`? - rust

I have a custom trait that I use as the element type in a slice:
pub trait IConstraint {
// members here
}
pub struct Scenario<'a> {
pub constraints: &'a [Box<dyn IConstraint>]
}
I would like to offer an add_constraint method that does a copy-on-write of the slice. Something like this:
impl<'a> Scenario<'a> {
pub fn add_constraint(&mut self, constraint: Box<dyn IConstraint<TNodeState>>) {
let mut constraints: Vec<Box<dyn IConstraint<TNodeState>>> = Vec::new();
constraints.copy_from_slice(self.constraints);
constraints.push(constraint);
self.constraints = &constraints;
}
}
The problem is I get this error:
the trait bound Box<dyn IConstraint<TNodeState>>: std::marker::Copy is not satisfied
the trait std::marker::Copy is not implemented for Box<dyn IConstraint<TNodeState>>
Ok, so the Box<T> doesn't implement the Copy trait. Fair enough. But how do I address that? Ideally, I'd reuse the boxes or at least the constraints because they are immutable. But if I can't do that due to rust ownership rules, how can I implement the Copy trait on a box type? I've tried various ways and they all produce errors.
This attempt produces "Copy not allowed on types with destructors":
impl<TNodeState> Copy for Box<dyn IConstraint<TNodeState>> {
}
What about Clone? I can switch to constraints.clone_from_slice(self.constraints);, but then implementing the Clone trait on IConstraint produces a bunch of "IConstraint cannot be made into an object" errors.
Even if I could get box to be cloneable, then of course I get the anticipated borrow lifetime flaw from my add_constraint method:
borrowed value does not live long enough
So do I have to throw out my add_constraint function idea altogether and force the owner of my struct to manually copy it? Given my actual struct contains 3 fields, that gets tedious as the owner now has to deconstruct the fields into locals in order to drop the immutable borrow, allowing the original vector to be mutated:
fn add_remove_constraint() {
let mut scenario = Scenario::<&str, bool, 3_usize>::new(&["A", "B", "C"]);
let mut constraints: Vec<Box<dyn IConstraint<bool>>> = Vec::new();
constraints.push(Box::new(SelectionCountConstraint {
nodes: [1, 2],
min: 1,
max: 2,
}));
scenario = Scenario {
constraints: &constraints,
..scenario
};
assert_eq!(1, scenario.get_constraints().len());
let nodes = scenario.nodes;
let selection_state = scenario.selection_state;
constraints.pop();
scenario = Scenario {
constraints: &constraints,
nodes,
selection_state,
};
assert_eq!(0, scenario.get_constraints().len());
}

I think you got it all wrong. As said in the comments, your add_constraint will never work, because you are referencing something you create in the same function in the first place (which will be dropped after the function scope expires).
You should own a container over those IConstraint trait, but inside you should have an &dyn IConstraint or Box<dyn IConstraint>.
Adding an item to them is trivial in that case:
pub trait IConstraint {
// members here
}
pub struct Scenario<'a> {
pub constraints: Vec<&'a dyn IConstraint>
}
impl<'a> Scenario<'a> {
pub fn add_constraint(&mut self, constraint: &'a dyn IConstraint) {
self.constraints.push(constraint);
}
}
Playground
This should solve your problem since references are Copy.

Related

Pull struct out of associated type returned by iterator

I am implementing a double linked list in rust. I have created an iterator that works fine.
#[derive(Clone, Debug)]
pub struct LLCursor<T: Copy> {
pub cur: Option<Rc<RefCell<Node<T>>>>,
}
impl<T> IntoIterator for List<T>
where
T: Clone + Copy,
{
type Item = Rc<RefCell<Node<T>>>;
type IntoIter = LLCursor<T>;
fn into_iter(self) -> Self::IntoIter {
LLCursor {
cur: self.head.clone(),
}
}
}
impl<T> Iterator for LLCursor<T>
where
T: Copy,
{
type Item = Rc<RefCell<Node<T>>>;
fn next(&mut self) -> Option<Rc<RefCell<Node<T>>>> {
match self.cur.clone() {
Some(node) => {
self.cur = node.borrow().next.clone();
Some(node)
}
None => None,
}
}
}
I would like to make a function that can access the contents of the Nodes of the linked list as it is iterated over. Something like this:
pub fn print(self)
where
List<T>: IntoIterator,
<List<T> as IntoIterator>::Item: std::fmt::Debug,
{
for i in self {
println!("{:?}", Some(i.borrow().clone().item));
}
}
Error:
error[E0599]: no method named `borrow` found for associated type `<List<T> as IntoIterator>::Item` in the current scope
--> src/list.rs:90:51
|
90 | println!("{:?}", i.borrow().clone().item);
| ^^^^^^ method not found in `<List<T> as IntoIterator>::Item`
|
= help: items from traits can only be used if the trait is in scope
= note: the following trait is implemented but not in scope; perhaps add a `use` for it:
`use std::borrow::Borrow;`
I understand that i in this context is of type <List<T> as IntoIterator>::Item. I am new to rust so I do not see how it is useful that the iterator returns the associated type in this manner. I would expect i to be of type Option<Rc<RefCell<Node<T>>>>. Is there a way that I can pull this out of the associated type so I am able to access the elements of each individual Node?
None of the iterator code actually requires T: Copy, I suggest you remove it since it is obfuscating your problem. Then, since you know <List<T> as IntoIterator>::Item is actually T, you can use it directly:
pub fn print(self) where T: Debug {
for i in self {
println!("{:?}", i.borrow().item);
}
}
I also removed the .clone() when printing since its unnecessary and avoids the T: Clone constraint. See it working on the playground.
The reason for the error you got is because constraining that List<T>: IntoIterator and Item: Debug does not mean that Item is a Rc<RefCell<_>>. You would need an additional constraint T: Copy for it to deduce the correct IntoIterator implementation. No other implementations exist as far as your demonstrated code shows, but a non-conflicting implementation could in theory exist and the compiler does not make guesses.
As a side note, constraining on the Self type (here explicitly as List<T>) is pretty uncommon except in traits as you typically know what is needed for Self to satisfy those constraints, and its more descriptive to list that directly. (i.e. if Self needed to be Clone, but you know that Self is Clone if T is Clone, you would use T: Clone as the constraint).

Copying local variable into vector in Rust

I'm new to Rust, and I'm trying to copy a local variable into a vector. Here's my attempt:
#[derive(Copy, Clone)]
struct DFAItem<'a> {
reading: usize,
production: &'a grammar::CFGProduction<'a>,
next_terminal: i32,
}
fn add_nonterminal<'a>(cfg: &'a grammar::CFG, nonterminal: usize, itemset: &'a mut Vec<DFAItem>) {
let productions = &cfg.productions[nonterminal];
for prod in productions {
let item = DFAItem {
reading: 0,
production: prod,
next_terminal: 0,
};
itemset.push(item); //here, I get a lifetime error (lifetime 'a required).
match prod.rhs[0] {
grammar::Symbol::Nonterminal(x) if x != nonterminal => add_nonterminal(cfg, x, itemset),
_ => (),
}
}
}
I understand that I can't modify the lifetime of item to make it match itemset, so what I'm trying to do is copy item into the vector, so that would have the vector's lifetime. Any help/tips would be appreciated.
Also, anybody know the syntax so that I could change cfg to have at least as long of a lifetime as itemset instead of the same? Would I just declare a second lifetime or is there a better way to do it?
EDIT: here are the definitions of CFG and CFGProduction:
pub enum Symbol {
Terminal(i32),
Nonterminal(usize),
}
pub struct CFGProduction<'a> {
pub nonterminal: usize,
pub rhs: &'a Vec<Symbol>,
}
pub struct CFG<'a> {
pub terminals: Vec<i32>,
pub productions: Vec<Vec<CFGProduction<'a>>>,
}
First, the lifetime of the itemset vec is not relevant and doesn't need to be constrained to anything. Second, CFG and DFAItem have generic lifetime parameters, so they should be indicated as such when using them in function arguments.
Here's my take, there's two big lifetimes involved here:
'a: the lifetime needed by CFGProduction's
'b: the lifetime of cfg and its subsequent references stored in DFAItems
Therefore, DFAItem should have two lifetimes:
struct DFAItem<'a, 'b> {
// ...
production: &'b grammar::CFGProduction<'a>,
// ...
}
and add_nonterminal()'s signature would look like so:
fn add_nonterminal<'a, 'b>(cfg: &'b grammar::CFG<'a>, nonterminal: usize, itemset: &mut Vec<DFAItem<'a, 'b>>) {
// ...
}
With these lifetime changes, the function body compiles as is. See it on the playground.
You can choose not to do that and just use 'a for everything:
struct DFAItem<'a> {
// ...
production: &'a grammar::CFGProduction<'a>,
// ...
}
fn add_nonterminal<'a>(cfg: &'a grammar::CFG<'a>, nonterminal: usize, itemset: &mut Vec<DFAItem<'a>>) {
// ...
}
but I'd advise against it. Types with the pattern &'a Type<'a>, where the generic lifetime is linked with itself can cause problems down the line; especially with mutability.

How do I return an Iterator over a collection encapsulated by a RefCell/RwLock Ref/Guard using unsafe code?

Multiple questions were already asked regarding this topic:
Returning iterator of a Vec in a RefCell
How do I return an iterator that has a reference to something inside a RefCell?
How can I return an iterator over a locked struct member in Rust?
The answers are more or less: It's not possible (without unsafe).
I tried the unsafe variant myself and want to ask if this way is safe.
The idea is that I wrap the guard in a struct that implements Iterator. Besides the guard, an iterator is stored which will be created from the stored guard:
struct MapIter<'a> {
guard: RwLockReadGuard<'a, HashMap<i32, i32>>,
iter: Iter<'a, i32, i32>,
}
It's created with these lines:
impl<'a> MapIter<'a> {
fn new(map: &'a RwLock<HashMap<i32, i32>>) -> Box<Self> {
// create a `box Self`
// the iterator remains uninitialized.
let mut boxed = Box::new(Self {
guard: map.read().expect("ToDo"),
iter: unsafe { mem::uninitialized() },
});
// create the iterator from `box Self`.
boxed.iter = unsafe {
(*(&boxed.guard as *const RwLockReadGuard<'a, HashMap<i32, i32>>)).iter()
};
boxed
}
}
Now it can implement Iterator:
impl<'a> Iterator for MapIter<'a> {
type Item = (&'a i32, &'a i32);
fn next(&mut self) -> Option<Self::Item> {
self.iter.next()
}
}
Is this code safe?
See this code in action at the playground.
Additionally I get a trivial cast warning
warning: trivial cast: warning: trivial cast: `&std::sync::RwLockReadGuard<'_, std::collections::HashMap<i32, i32>>` as `*const std::sync::RwLockReadGuard<'a, std::collections::HashMap<i32, i32>>`. Cast can be replaced by coercion, this might require type ascription or a temporary variable
|
| unsafe { (*(&boxed.guard as *const RwLockReadGuard<'a, HashMap<i32, i32>>)).iter() };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
How to get around this?
No, it's not safe. I can use Container to create a dangling reference in safe code:
let container = Container::new(); // create a container
let r = {
let mut it = container.iter();
it.next() // obtain a reference to part of it
};
container.map.write().unwrap().clear(); // empty the container
println!("{:?}", r); // oh dear.
In the playground this compiles, which isn't good, because r contains references to data that are invalidated when the HashMap is cleared.
Vladimir Matveev's answer to a similar question explains in more detail why this is unsound, and contains the following concise summary:
You cannot do this because it would allow you to circumvent runtime checks for uniqueness violations.

How to prevent autoimplementation of Sync

I have a struct containing unsafe code with the following method:
use std::sync::Arc;
use std::thread;
#[derive(Debug)]
struct Foo<T> {
items: Vec<Box<(T, String)>>,
}
impl<T> Foo<T> {
pub fn add_element(&self, element: T, key: String) {
if !(self.items.iter().any( |i| i.1 == key)) {
let mut items = unsafe {change_mut(&(self.items))};
items.push(Box::new((element,key)));
}
}
}
unsafe fn change_mut<T>(x: &T) -> &mut T { // changes &self to &mut self
&mut *(x as *const T as *mut T)
}
fn main() {
let foo = Arc::new(Foo { items: vec!() });
let clone = foo.clone();
// This should not be possible, as it might lead to UB
thread::spawn(move || clone.add_element(1, String::from("one")));
println!("{:?}", *foo);
}
This struct is completely safe until someone starts using this method while multithreading. However, due to the fact the struct only contains a Vec<Box<T,String>>, Syncis implemented by default, which I would like to prevent.
I have found two ways to do this, both of which are not that great...
Add a struct field which does not implement Sync for example *const u8, this is obviously rather bad, as it ends up resulting in unnecessary and unclear code and does not clearly show my intent.
impl !Sync for Struct {} is not available on stable and will be removed according to this issue.
The corresponding error is telling me to use marker types instead, but the documention does not present a way to solve my problem either.
error: negative trait bounds are not yet fully implemented; use marker types for
now (see issue #13231)
--> src\holder.rs:44:1
|
44 | impl !Sync for Struct {}
| ^^^^^^^^^^^^^^^^^^^^^^^^
Interior mutability in Rust requires1 the use of UnsafeCell as a hint to the compiler that the normal rules do not apply.
Your structure should therefore look such:
#[derive(Debug)]
struct Foo<T> {
items: UnsafeCell<Vec<Box<(T, String)>>>,
}
And then, the implementation of add_element is adjusted to:
impl<T> Foo<T> {
pub fn add_element(&self, element: T, key: String) {
if !(self.items.iter().any( |i| i.1 == key)) {
let mut items = unsafe { &mut *self.items.get() };
// ^~~~~~~~~~~~~~~~~~~~~~
items.push(Box::new((element,key)));
}
}
}
The use of UnsafeCell makes change_mut completely unnecessary: it is the purpose of UnsafeCell, after all, to allow interior mutability. Note how its get method returns a raw pointer, which cannot be dereferenced without an unsafe block.
Since UnsafeCell does not implement Sync, Foo<T> will not implement Sync either, and therefore it becomes unnecessary to use negative implementations or any marker.
1 If you do not use it directly, chances are the abstractions you do use are built on it. It is as special as it could be: it is a lang item, as denoted by its attribute #[lang = "unsafe_cell"].

How do I pass Rc<RefCell<Box<MyStruct>>> to a function accepting Rc<RefCell<Box<dyn MyTrait>>>?

I have originally asked this question here, but it was marked as duplicate, although it duplicates only a part of it in my opinion, so I have created a more specific one:
Consider the following code:
use std::rc::Rc;
trait MyTrait {
fn trait_func(&self);
}
struct MyStruct1;
impl MyStruct1 {
fn my_fn(&self) {
// do something
}
}
impl MyTrait for MyStruct1 {
fn trait_func(&self) {
// do something
}
}
fn my_trait_fn(t: Rc<dyn MyTrait>) {
t.trait_func();
}
fn main() {
let my_str: Rc<MyStruct1> = Rc::new(MyStruct1);
my_trait_fn(my_str.clone());
my_str.my_fn();
}
This code works fine. Now I want to change the definition of trait_func to accept a &mut self, but it won't work as Rc works with immutable data only. The solution I use is to wrap MyTrait into RefCell:
use std::cell::RefCell;
fn my_trait_fn(t: Rc<RefCell<Box<dyn MyTrait>>>) {
t.borrow_mut().trait_func();
}
fn main() {
let my_str: Rc<RefCell<Box<MyStruct1>>> = Rc::new(RefCell::new(Box::new(MyStruct1)));
my_trait_fn(my_str.clone());
my_str.my_fn();
}
When I compile it I get an error:
error[E0308]: mismatched types
--> src/main.rs:27:17
|
27 | my_trait_fn(my_str.clone());
| ^^^^^^^^^^^^^^ expected trait MyTrait, found struct `MyStruct1`
|
= note: expected type `std::rc::Rc<std::cell::RefCell<std::boxed::Box<dyn MyTrait + 'static>>>`
found type `std::rc::Rc<std::cell::RefCell<std::boxed::Box<MyStruct1>>>`
= help: here are some functions which might fulfill your needs:
- .into_inner()
What's the best way to go around this problem?
(An older revision of this answer essentially advised to clone the underlying struct and put it in a new Rc<RefCell<Box<MyTrait>> object; this was necessary at the time on stable Rust, but since not long after that time, Rc<RefCell<MyStruct>> will coerce to Rc<RefCell<MyTrait>> without trouble.)
Drop the Box<> wrapping, and you can coerce Rc<RefCell<MyStruct>> to Rc<RefCell<MyTrait>> freely and easily. Recalling that cloning an Rc<T> just produces another Rc<T>, increasing the refcount by one, you can do something like this:
use std::rc::Rc;
use std::cell::RefCell;
trait MyTrait {
fn trait_func(&self);
}
#[derive(Clone)]
struct MyStruct1;
impl MyStruct1 {
fn my_fn(&self) {
// do something
}
}
impl MyTrait for MyStruct1 {
fn trait_func(&self) {
// do something
}
}
fn my_trait_fn(t: Rc<RefCell<MyTrait>>) {
t.borrow_mut().trait_func();
}
fn main() {
// (The type annotation is not necessary here, but helps explain it.
// If the `my_str.borrow().my_fn()` line was missing, it would actually
// be of type Rc<RefCell<MyTrait>> instead of Rc<RefCell<MyStruct1>>,
// essentially doing the coercion one step earlier.)
let my_str: Rc<RefCell<MyStruct1>> = Rc::new(RefCell::new(MyStruct1));
my_trait_fn(my_str.clone());
my_str.borrow().my_fn();
}
As a general rule, see if you can make things take the contained value by reference, ideally even generically—fn my_trait_fn<T: MyTrait>(t: &T) and similar, which can typically be called as my_str.borrow() with automatic referencing and dereferencing taking care of the rest—rather than the whole Rc<RefCell<MyTrait>> thing.

Resources