-
Notifications
You must be signed in to change notification settings - Fork 1
Description
Ok, here is some complicated issue and the reason, why I think we need to have a "ExtensionsAreNotRegistered" error somewhere in our codebase.
I moved ExtensionRegistry to engine::Options.
pub struct Options {
pub debug: bool,
`// ...
pub extensions: ExtensionRegistry,
}
Now Setup does this
// init extensions
try_chain!(self.options.extensions.init( /* foo */ );
The problem is with foo.
Lets look at ExtensionRegistry::init()
pub fn init(&mut self, options: &/*mut?*/ Options) -> Result<(), ExtensionRegistryError> {
if self.initialized {
return err!(ExtensionRegistryErrorCode::AlreadyInitialized)
}
for (_, ext) in self.ext.iter() {
ext.init(options);
// ...
Notice the &mut self in init()
This loops over extensions implementing something like this
/// Extends the Twig Engine with new behaviour.
pub trait Extension : fmt::Debug {
/// Initialize the engine.
/// This is where you can load some file that contains filter functions for instance.
fn init(&mut self, _options: &engine::Options) {} // TODO: add error handling ???
// ...
>>> Uh oh. Now we have to fight the borrow checker. Why?
(a) extensions are part of engine::Options
(b) each extensions might want to initialize itself (via &mut self borrow). Due to (a) this implies a mutable borrow to engine::Options
(c) It would be reasonable for extensions to read the options, but we can't have another borrow due to the mutable borrow of one extension.
How can we solve this? Safe or Unsafe?
- extensions are part of engine::Options - but nullable, i.e. wrapped inside
Option<ExtensionRegistry>. During initializiation, we set this to None, so we have separate borrows. After initialization we move extensions inside options. The catch: All following code must deal with nullable Extensions inside Options... This is the "ExtensionsAreNotRegistered" error.
Are you ok with this approach, or do you have a different suggestion?