I am messing around building a system where the idea is Context
would build and store a singleton ChildContext
. The Context
and ChildContext
itself would be able to clear the ChildContext
by removing the parent Context
from the ChildContext
. Then the ChildContext
will become defunct by checking for parent. Although there is only one ChildContext
in this example, the idea is there will be specialised contexts but will have the same base code handling the contexts' relationships
In my head the natural thing to do would be Context
would own the ChildContext
and the ChildContext
would have a weak reference to the Context
. ChildContext
could then call on Context
to clear it self up. My attempt at rustifying is below. It uses interior mutability to achieve the idea.
My questions are:
- I am not sure if this the right way to handle it
- With the specialised contexts and being able to release from the child and the parent, is there a better way to avoid code duplication?
Updated code
use std::cell::RefCell;
use std::mem;
use std::rc::{Rc, Weak};
struct Context {
internal: Rc<RefCell<ContextInt>>
}
struct ContextInt {
child_context: Option<Rc<RefCell<ChildContextInt>>>
// ...
// other child contexts
}
struct ChildContext {
internal: Rc<RefCell<ChildContextInt>>
}
struct ChildContextInt {
parent_context: Option<Weak<RefCell<ContextInt>>>
// ...
// context data
}
impl Context {
pub fn new() -> Self {
Context {
internal: Rc::new(RefCell::new(ContextInt {
child_context: None
}))
}
}
pub fn child_context(&self) -> ChildContext {
let internal = self.internal.borrow_mut();
let child_context_int: Rc<RefCell<ChildContextInt>>;
if let Some(child_context_ref) = &internal.child_context {
child_context_int = Rc::clone(&child_context_ref);
} else {
child_context_int = Rc::new(
RefCell::new(
ChildContextInt {
parent_context: Some(Rc::downgrade(&self.internal))
}
)
);
self.internal.borrow_mut().child_context = Some(Rc::clone(&child_context_int));
}
ChildContext {
internal: child_context_int
}
}
pub fn release_child_context(&self) {
let mut child_context: Option<Rc<RefCell<ChildContextInt>>> = None;
mem::swap(&mut child_context, &mut self.internal.borrow_mut().child_context);
if let Some(child_context) = child_context {
child_context.borrow_mut().parent_context = None
}
}
}
impl ChildContext {
fn release(&self) {
let mut parent_context: Option<Weak<RefCell<ContextInt>>> = None;
mem::swap(&mut parent_context, &mut self.internal.borrow_mut().parent_context);
if let Some(parent_context_rc) = parent_context {
if let Some(parent_context) = parent_context_rc.upgrade() {
parent_context.borrow_mut().child_context = None
}
}
}
}