I have two types A
and B
that implement the Fooable
trait. I have an array of A
s, and an array of B
s, and create an iterator over the two arrays, the iterator having Item type &dyn Fooable
. I want to write a test to confirm that the iterator outputs the correct objects, something like:
struct C {
as_array: [A; 2],
bs_arry: [B; 2],
}
impl C {
fn contents_iter(&self) -> FoosIterator {
FoosIterator {
a_iter: (&self.as_array).into_iter(),
b_iter: (&self.bs_arry).into_iter(),
}
}
}
struct FoosIterator<'a> {
a_iter: <&'a [A; 2] as IntoIterator>::IntoIter,
b_iter: <&'a [B; 2] as IntoIterator>::IntoIter,
}
impl<'a> Iterator for FoosIterator<'a> {
type Item = &'a dyn Fooable;
fn next(&mut self) -> Option<Self::Item> {
match self.a_iter.next() {
Some(upper_slot) => Some(upper_slot),
None => self.b_iter.next().map(|x| x as &dyn Fooable),
}
}
}
trait Fooable: std::fmt::Debug {
fn calculate_num(&self) -> i32;
}
#[derive(PartialEq, Debug)]
struct A {
value: i32,
}
impl Fooable for A {
fn calculate_num(&self) -> i32 {
self.value
}
}
#[derive(PartialEq, Debug)]
struct B {
value_1: i32,
value_2: i32,
}
impl Fooable for B {
fn calculate_num(&self) -> i32 {
self.value_1 * 5 + self.value_2
}
}
#[test]
fn test_contents_iter() {
let c = C {
as_array: [A { value: 3 }, A { value: 5 }],
bs_arry: [
B {
value_1: 3,
value_2: 1,
},
B {
value_1: 5,
value_2: 2,
},
],
};
let mut iter = c.contents_iter();
assert_eq!(
*iter
.next()
.expect("Should have initial element from iterator"),
A { value: 3 }
);
assert_eq!(
*iter
.next()
.expect("Should have second element from iterator"),
A { value: 5 }
);
assert_eq!(
*iter
.next()
.expect("Should have third element from iterator"),
B {
value_1: 3,
value_2: 1
}
);
assert_eq!(
*iter
.next()
.expect("Should have fourth element from iterator"),
B {
value_1: 5,
value_2: 2
}
);
}
The problem is that objects of type &dyn Fooable
do not implement the PartialEq
trait, so cannot be compared for equality:
error[E0369]: binary operation `==` cannot be applied to type `dyn Fooable`
--> src/lib.rs:73:5
|
73 | / assert_eq!(
74 | | *iter
75 | | .next()
76 | | .expect("Should have initial element from iterator"),
77 | | A { value: 3 }
78 | | );
| | ^
| | |
| |______dyn Fooable
| A
|
= note: an implementation of `std::cmp::PartialEq` might be missing for `dyn Fooable`
= note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info)
As I understand it (for instance from How to test for equality between trait objects?) there is no way to implement this trait for a dynamic type. Is there any way to achieve something like the aim here? I suppose one could instead expose some of the data constituting objects of type A
and B
in the Fooable
trait, and use this to check that the objects outputted are the correct ones (in my actual use case the A
s and B
s are more complicated than in my toy example above).