I have the following trait definition representing a sub-block within a DSL:
pub trait SubBlock {
fn get_command(&self) -> Command;
fn get_parent_id(&self) -> u32;
}
I also have the following struct/enum definitions:
pub struct StartBlock {
pub parent_id: u32,
pub date: NaiveDate,
pub hour: u32,
}
impl SubBlock for StartBlock {
fn get_command(&self) -> Command {
Command::START
}
fn get_parent_id(&self) -> u32 {
self.parent_id
}
}
pub struct Entry {
pub id: u32,
pub description: String,
pub children: Option<Vec<Box<dyn SubBlock>>>
}
So, as can be seen, some Entry
s have children, which are all SubBlock
s, but there are a series of struct definitions specific to the DSL for these SubBlock
s. For example, a StartBlock
has a date
and hour
.
The problem is that I want to be able to clone an Entry
struct, so I wrote this method:
impl Clone for Entry {
fn clone(&self) -> Self {
let cloned_children: Vec<Box<dyn SubBlock>> = self.children.unwrap()
.iter()
.map(|bsb| {
*bsb
})
.collect();
let mut opt_cloned_children = None;
if cloned_children.len() > 0 {}
opt_cloned_children = Some(cloned_children);
Entry {
id: self.id,
description: String::from(&self.description),
children: opt_cloned_children
}
}
But, when I try to compile this code, I get:
error[E0277]: the size for values of type `dyn SubBlock` cannot be known at compilation time
--> src/entry.rs:22:18
|
22 | .map(|bsb| {
| ______________---_^
| | |
| | required by a bound introduced by this call
23 | | *bsb
24 | | })
| |_____________^ doesn't have a size known at compile-time
|
= help: the trait `Sized` is not implemented for `dyn SubBlock`
Clearly, I know this isn't quite right, since I'm dereferencing the box, which is a pointer (and thus unsized), but all I really want to do is put a copy of the data into a new Box
. I even tried doing something akin to:
.map(|bsb| {
Box::new(StartBlock::try_from(bsb).unwrap())
})
(After implementing try_from
for a StartBlock
, which uses the mopa
crate to downref:
pub trait SubBlock: mopa::Any {
fn get_command(&self) -> Command;
fn get_parent_id(&self) -> u32;
}
mopafy!(SubBlock);
impl TryFrom<Box<dyn SubBlock>> for StartBlock {
type Error = ConversionError;
fn try_from(value: Box<dyn SubBlock>) -> Result<Self, Self::Error> {
if value.get_command() != Command::START {
return Err(ConversionError {
initial_type: Command::START
});
}
let converted_opt: Option<&StartBlock> = value.downcast_ref::<StartBlock>();
if converted_opt.is_none() {
return Err(ConversionError {
initial_type: Command::START
});
}
let dc_ref = converted_opt.unwrap();
Ok(StartBlock {
parent_id: dc_ref.parent_id,
date: dc_ref.date.clone(),
hour: dc_ref.hour
})
}
}
But, then this results in:
error[E0277]: a value of type `Vec<Box<dyn PlaSubBlock>>` cannot be built from an iterator over elements of type `Box<sub_blocks::PlaStartBlock>`
--> src/entry.rs:25:14
|
25 | .collect();
| ^^^^^^^ value of type `Vec<Box<dyn SubBlock>>` cannot be built from `std::iter::Iterator<Item=Box<sub_blocks::StartBlock>>`
|
= help: the trait `FromIterator<Box<sub_blocks::StartBlock>>` is not implemented for `Vec<Box<dyn SubBlock>>`
Can I directly implement FromIterator<Box<StartBlock>>
on Vec<Box<dyn SubBlock>>
? That doesn't seem likely. I'm having a difficult time understanding how I can clone something when I don't have a concrete type (or if that is even possible).