Hey there, so basically there's a config file that contains information like different user profiles, and this config can be reloaded during operation so these profiles can changed or be deleted. The thing is, I don't necessarily want to delete profiles until I know nothing is going to attempt to re-read them, and I also want to be able to access them centrally, so just storing them in an Rc<RefCell<T>>
and relying on the individual widgets to keep it alive doesn't fully work because the central mainloop also needs to be able to read them (I could use a Weak<T>
here and kind of get what I want, but it's messy).
Now the thing reading the information is going to be a UI element implemented with gkt4rs, which heavily restricts how I handle borrowing, and basically requires that I overly rely on Rc<RefCell<T>>
or Rc<T>
for shared data. I could conceivably implement this with a hashmap containing Rc<RefCell<T>>
and make each widget using the data hold a strong reference, but that wouldn't get rid of the need for the d
field and that would mean I have to mutate shared data, which I'd prefer to avoid if possible. Also, I see this as an opportunity to learn more about the borrowing system, which is still a weak spot of mine.
Anyway, as you can see in the code below, there is the main storage structure (field s
), and two additional collections, c
and d
, which use &'a K
as their key types. All keys present in both c
and d
are references to keys within s
, and those fields will be cleared before the referenced field in s
is removed.
use std::{
cmp::Eq,
collections::{HashMap, HashSet},
hash::Hash,
};
#[derive(Debug)]
pub struct Store<'a, K: 'a, V> {
// use a hashmap to store items
s: HashMap<K, V>,
// HashMap containing the counts of how many things are currently using a
// an item (kind of like a reference count, except the users aren't
// directly holding references).
c: HashMap<&'a K, u32>,
// HashSet specifying what information should be deleted once nothing
// else is using it
d: HashSet<&'a K>,
}
#[derive(Debug)]
pub struct StoreBuilder<'a, K, V>(Store<'a, K, V>);
impl<'a, K, V> !Sync for Store<'a, K, V> {}
impl<'a, K, V> Default for Store<'a, K, V>
where
K: Eq + Hash + 'a,
{
fn default() -> Self {
Self {
s: HashMap::default(),
c: HashMap::default(),
d: HashSet::default(),
}
}
}
impl<'a, K, V> Store<'a, K, V>
where
K: Eq + Hash + 'a,
{
pub fn builder() -> StoreBuilder<'a, K, V> {
StoreBuilder(Self::default())
}
pub fn insert(&mut self, key: K, item: V) {
// self.c.insert(&key, 0);
// ^ uncommenting this line causes a compiler error
self.s.insert(key, item);
}
pub fn peek(&self, key: &K) -> Option<&V> {
self.s.get(key)
}
}
impl<'a, K: Eq + Hash + 'a, V> StoreBuilder<'a, K, V>
where
K: Eq + Hash + 'a,
{
pub fn with(mut self, key: K, item: V) -> Self {
self.0.insert(key, item);
self
}
pub fn build(self) -> Store<'a, K, V> {
self.0
}
}
The first issue I am running into is within the Store::insert()
function. Obviously there is a problem that I can't insert a reference to the key into c
after inserting it into s
because the value was moved into s
, and I can't insert a reference into c
before I move it into s
because that's after borrow.
Are there any safe ways to insert an item into c
that uses key: &'a K
(owned by s
) with cloning?
Thanks