I have two types A and B that implement the Fooable trait. I have an array of As, and an array of Bs, 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 As and Bs are more complicated than in my toy example above).