uazu / qcell

Statically-checked alternatives to RefCell and RwLock
Apache License 2.0
356 stars 22 forks source link

Retrieving the wrapped value from `QCell` and friends #35

Closed maroider closed 2 years ago

maroider commented 2 years ago

Cell, RefCell, and Mutex all have an into_inner method which allows you to extract the wrapped value, but QCell (and TCell and LCell) doesn't seem to have such a method.

uazu commented 2 years ago

Do you have an example of a practical use of this? i.e. some scenario that requires this. This is just to get a handle on the requirement.

I'm unsure as yet whether this would need involvement of the owner or not. It is a drop situation so maybe not, but all this needs thinking through.

maroider commented 2 years ago

Do you have an example of a practical use of this? i.e. some scenario that requires this. This is just to get a handle on the requirement.

I'm mucking around with making a GUI library, and for this reason I have a Widget trait that looks roughly like this:

trait Widget: Any {
    type State;

    fn init(&mut self, cx: Cx<'_>) -> Self::State;
    fn update(&mut self, cx: Cx<'_>, state: &mut Self::State);
    fn destroy(&mut self, cx: Cx<'_>, state: Self::State);
}

Implementors of this trait get stored in a tree, and then they can hold unique/owning handles to other nodes in the tree, where the handle contains a QCellOwner. Since they're stored as trait objects, the trait must be object-safe, and thus I can't have associated methods or methods which take self by-value, which is why I've introduced Widget::State, as sometimes widget-internal state might need access to things that aren't there upon initial construction (but which are available during Widget::init). I originally also couldn't figure out how to get &mut self to work for anything but Widget::init, but that has since been solved.

Under the hood, I'm storing Widgets and the associated Widget::State behind QCells (although I could also store both behind the same QCell). When the time comes to call Widget::destroy, I want to extract the Widget::State from its QCell, as the use of QCell is supposed to be purely an implementation detail. I can currently get around this since I'm using QCell<Box<dyn Any>> to store the Widget::State, which lets me swap out the Widget::State in with a ().

I'm unsure as yet whether this would need involvement of the owner or not. It is a drop situation so maybe not, but all this needs thinking through.

I am personally of the mind that this shouldn't require the QCellOwner, but I can see how one could make the case for requiring it.

uazu commented 2 years ago

Thanks for the explanation. I can see that it makes sense to pull out the inner value when you're tearing stuff down.

I'm only concerned about the safety aspect, i.e. whether it would be unsafe to allow into_inner without access to the owner. But if self is moved to that method, then Rust must have checked that all borrows have been terminated (similar to when it is dropped). So according to this reasoning it should be safe, although I will look into it further to convince myself.

uazu commented 2 years ago

into_inner is implemented for all cell types in crate release 0.5.2