I'm trying to implement a type-safe interface to a native library and encountered an interesting problem.
The main idea is that each "state" the library is in will contain a &'lib mut Library
to ensure the associated functions can only be called when the library is in the appropriate state, and that nothing else can use the library at the time.
For correctness reasons I need to call a function when entering a state (usually done in the constructor) and another when the state gets destroyed. When transitioning between two states we also need to pass the &mut Library
reference around, however the naive way of doing this doesn't compile.
error[E0713]: borrow may still be in use when destructor runs
##[error] --> src/lib.rs:142:23
|
129 | impl<'lib> RecipeBuilder<'lib> {
| ---- lifetime `'lib` defined here
...
141 | / Recipe {
142 | | _library: self._library,
| | ^^^^^^^^^^^^^
143 | | }
| |_________- returning this value requires that `*self._library` is borrowed for `'lib`
144 | }
| - here, drop of `self` needs exclusive access to `*self._library`, because the type `RecipeBuilder<'_>` implements the `Drop` trait
(see the CI run for more)
There are a couple places where I trigger this error and while I understand exactly why this error occurs, I can't think of a way to tell the compiler it's okay to move self._library
because it doesn't get used in the destructor. The nightly #[may_dangle]
attribute also doesn't do anything.
Any ideas? I'd prefer to avoid wrapping the _library
reference in an Option
for ergonomics, and likewise mem::swap()
ing in an uninitialized &mut Library
(while also being UB) feels like a bit too hacky for my liking.
This is also part of a blog post so if possible I'd prefer to avoid hacky solutions which might teach people bad habits...