Feedback on attempt to design a system with parent/child relationship

⚓ Rust    📅 2025-04-29    👤 surdeus    👁️ 4      

surdeus

Warning

This post was published 114 days ago. The information described in this article may have changed.

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:

  1. I am not sure if this the right way to handle it
  2. 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
            }
        }
    }
}

5 posts - 3 participants

Read full topic

🏷️ rust_feed