Closed alkis closed 6 years ago
There's no way to do it without a lifetime on TopLevel
. Here is what it would look like:
struct TopLevel<'a> {
slab: &'a Slab<Item>,
ids: HashMap<u64, usize>,
ord: RBTree<ItemAdapter<'a>>,
}
let slab = Slab::new(...);
let top_level = TopLevel {
slab: &slab,
ids: ...,
ord: ...,
};
By the way, this is the same pattern that is used in the Rust compiler. The compiler crates a GlobalContext
struct with a lifetime which is then passed on to almost every other function in the compiler.
I see. Having the slab outside is a lot better! Thanks @Amanieu!
One more question. I tried to implement a stateful adapter such that I stop dealing with references and deal with usize
instead which I would use to index into the slab. I didn't manage to make it work. Is there an example where this is done?
It would look something like this:
struct MyAdapter<'a>(&'a Slab<Item>);
impl<'a> Adapter for MyAdapter<'a> {
type Link = RBTreeLink;
type Value = Item;
type Pointer = usize;
#[inline]
unsafe fn get_value(&self, link: *const RBTreeLink) -> usize {
let ptr = container_of!(link, Item, link);
// ptr is a pointer to an element in the slab, convert it to an index somehow
}
#[inline]
unsafe fn get_link(&self, value: usize) -> *const RBTreeLink {
&self.0.get_from_index(value).link
}
}
Thanks Amanieu. I went as far as that and got stuck at the comment. I opened an issue against slab, maybe this API is possible to implement: https://github.com/carllerche/slab/issues/45
I have a working implementation now except for one limitation: when composing data structures together, the inner nodes cannot be modified. For example:
struct Bucket {
link: RBTreeLink,
list: LinkedList,
...
}
struct Item {
link: LinkedListLink,
...
}
I want to be able to get a Bucket
from an RBTree and then add Items
to its linked list. Is it possible to add a get_mut
to CursorMut
for each container? I understand that this is unsafe since the user can break the data structure's invariants by getting a mutable reference to the item but I don't see another way. What do you think?
You're supposed to use inner mutability here. Basically, put the Bucket.list
in a RefCell
(or UnsafeCell
).
Thanks @Amanieu. Closing.
I am trying to use a slab instead of arena and use intrusive collections to the elements in the slab. But I can't seem to make this work without polluting the top level type with a lifetime.
Sample code:
If I add lifetime to
TopLevel
then it will need to be specified wheneverTopLevel
is a member of another struct.Is what I am trying to do possible? If so how?