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 traitstd::marker::Copy
is not implemented forBox<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());
}