I’m using Rust and its trait system to build out a large library. The idea: leave room for testing out multiple implementations and get some succinct contracts. This will give me the ability to A/B test and benchmark different parts as the library grows. The first round of implementations will use the simplest data types (read: Vec s with linear scans).

Now I’m running in to issues with the type checker and PartialEq and I think my use of traits has something to do with it. I was hoping #[derive(PartialEq)] would suffice but I’m missing something.

Let’s back up and look at the trait code:

// history_cache_trait.rs pub use super :: super :: super :: common_types :: * ; pub type ErrorStr = & ' static str ; pub type HistoryCacheResult = Result < (), ErrorStr > ; pub trait HistoryCacheTrait { fn new () -> Self ; fn add_change ( & mut self , change : CacheChange ) -> HistoryCacheResult ; fn remove_change ( & mut self , change : CacheChange ) -> HistoryCacheResult ; fn get_change (); fn get_seq_num_min (); fn get_seq_num_max (); }

The code above is used for tracking state changes. I imagine it will grow to become one of the more complex bits of my library. A cache change is a wrapper around a buffer with a simple definition:

# [ derive ( PartialEq )] pub struct CacheChange { kind : ChangeKind , writer_guid : Guid , instance_handle : InstanceHandle , sequence_number : SequenceNumber , data : Vec < u8 > }

The first implementer makes heavy use of the unimplemented!() macro to side step actual implementation but here’s the suspicious implentation:

// history_cache/mod.rs use std :: default :: Default ; use super :: super :: common_types :: * ; use super ::{ HistoryCacheTrait , HistoryCacheResult }; #[derive(Default)] pub struct HistoryCache { changes : Vec < CacheChange > } impl HistoryCacheTrait for HistoryCache { // SNIP fn remove_change ( & mut self , change : CacheChange ) -> HistoryCacheResult { for c in & self .changes { if c == change { } } unimplemented! () } // SNIP }

when compiling the code I get this error (courtesy of new formatting in Rust nightly):

Compiling rtps v0.1.0 (file:///Users/xavierlange/code/dds/rtps) error[E0277]: the trait bound `&common_types::cache_change::CacheChange: std::cmp::PartialEq<common_types::cache_change::CacheChange>` is not satisfied --> src/entity/history_cache/mod.rs:23:16 | 23 | if c == change { | ^^^^^^^^^^^ | = help: the following implementations were found: = help: <common_types::cache_change::CacheChange as std::cmp::PartialEq>

I added the #[derive(PartialEq)] to CacheChange and even then I’m using the concrete type CacheChange and not some interface. I am using the PartialEq inside of the HistoryCache ’s HistoryCacheTrait impl. Is that the issue? The one interesting bit I see in the error is &common_types::cache_change::CacheChange (focus on the ampersand) – looks like a borrow is perhaps messing things up?

It can get confusing to read the error. I’m pretty confident it’s not the #[derive(PartialEq)] causing the issue. And I have read code which derefs ( * ) values. And I think I read somewhere that for makes an iterator which borrows values. That would explain the & in the error! Let’s try this definition:

fn remove_change ( & mut self , change : CacheChange ) -> HistoryCacheResult { for c in & self .changes { if * c == change { } } unimplemented! () }

Now we have success:

Compiling rtps v0.1.0 (file:///Users/xavierlange/code/dds/rtps) Finished debug [unoptimized + debuginfo] target(s) in 0.90 secs