Info
This post is auto-generated from RSS feed The Rust Programming Language Forum - Latest topics. Source: Rust Borrow Checker: Why does reordering assertions affect mutable borrow lifetime from &mut dyn Trait in tests?
I have a struct in rust defined as below:
pub struct ObjectDictionary<'a> {
entries: BTreeMap<u16, ObjectEntry>,
storage: Option<&'a mut dyn ObjectDictionaryStorage>,
}
The ObjectDictionary
has a storage
attribute which I use to store data. ObjectDictionaryStorage
is a trait because the storage could be of many different types.
pub trait ObjectDictionaryStorage {
fn load(&mut self) -> Result<BTreeMap<(u16, u8), ObjectValue>, Error>;
fn save(&mut self, parameters: &BTreeMap<(u16, u8), ObjectValue>) -> Result<(), Error>;
fn clear(&mut self) -> Result<(), Error>;
fn restore_defaults_requested(&self) -> bool;
}
Now, I am trying to run some tests and I created the following mock to emulate storage:
struct MockStorage {
saved_data: BTreeMap<(u16, u8), ObjectValue>,
restore_requested: bool,
save_called: bool,
load_called: bool,
clear_called: bool,
}
impl MockStorage {
fn new() -> Self {
// Not shown here for brevity.
}
}
impl ObjectDictionaryStorage for MockStorage {
fn load(&mut self) -> Result<BTreeMap<(u16, u8), ObjectValue>, Error> {
// Not shown here for brevity.
}
fn save(
&mut self,
params: &BTreeMap<(u16, u8), ObjectValue>,
) -> Result<(), Error> {
// Not shown here for brevity.
}
fn clear(&mut self) -> Result<(), Error> {
self.clear_called = true;
self.saved_data.clear();
Ok(())
}
fn restore_defaults_requested(&self) -> bool {
self.restore_requested
}
fn request_restore_defaults(&mut self) -> Result<(), Error> {
self.restore_requested = true;
Ok(())
}
fn clear_restore_defaults_flag(&mut self) -> Result<(), Error> {
self.restore_requested = false;
Ok(())
}
}
Now, during my tests, I would like to check if the restore_requested
and clear_called
flags have changed. I can easily check restore_requested
because one of the traits' functions return it. But since none of the trait functions return clear_called
, I am not being able to access it because the MockStorage
is mutably borrowed to the ObjectDictionary
.
See below an example of a test that would fail.
#[test]
fn test_init_restores_defaults_if_flagged() {
let mut storage = MockStorage::new();
storage
.saved_data
.insert((0x6000, 0), ObjectValue::Unsigned32(999));
storage.restore_requested = true;
let mut od = ObjectDictionary::new(Some(&mut storage));
od.insert(
0x6000,
ObjectEntry {
object: Object::Variable(ObjectValue::Unsigned32(0)),
name: "StorableVar",
access: AccessType::ReadWriteStore,
},
);
od.init().unwrap();
assert!(storage.clear_called); // Test fails here.
assert!(!od
.storage
.as_ref()
.unwrap()
.restore_defaults_requested());
assert_eq!(od.read_u32(0x6000, 0).unwrap(), 0); // Back to default
}
The error message reads
cannot use
storage.clear_called
because it was mutably borrowed; use of borrowedstorage
.
Weirdly enough, I just realized that if I place assert!(storage.clear_called)';
at the end of the test as the last command, everything builds!
#[test]
fn test_init_restores_defaults_if_flagged() {
let mut storage = MockStorage::new();
storage
.saved_data
.insert((0x6000, 0), ObjectValue::Unsigned32(999));
storage.restore_requested = true;
let mut od = ObjectDictionary::new(Some(&mut storage));
od.insert(
0x6000,
ObjectEntry {
object: Object::Variable(ObjectValue::Unsigned32(0)),
name: "StorableVar",
access: AccessType::ReadWriteStore,
},
);
od.init().unwrap();
assert!(!od
.storage
.as_ref()
.unwrap()
.restore_defaults_requested());
assert_eq!(od.read_u32(0x6000, 0).unwrap(), 0);
assert!(storage.clear_called); // Test doesn't fail anymore!
}
Can someone explain to me what is happening and what am I missing? Probably something about the assert!
macro that I am not familiar with I guess...
8 posts - 3 participants
🏷️ Rust_feed