cycle_ptr 0.1.0

Smart pointers, with cycles
//! A small example that shows how to use cyclic references.
//!
//! The example creates a small family tree,
//! where each [Person] (except the first) has parent and multiple children.

use cycle_ptr::prelude::*;
use cycle_ptr::{GcMemberPtr, GcPtr, Metadata};
use indent_write::fmt::IndentWriter;
use std::cell::RefCell;
use std::fmt;

#[derive(Debug)]
struct AddChildError;

/// A person record.
struct Person {
    /// Name of the person.
    name: String,
    /// Parent of the person (if they have one).
    parent: RefCell<Option<GcMemberPtr<Person>>>,
    /// Chidren of the person.
    children: RefCell<Vec<GcMemberPtr<Person>>>,

    /// Metadata is used to create the [member-pointers][GcMemberPtr].
    metadata: Metadata,
}

impl Person {
    fn new(name: String) -> GcPtr<Person> {
        GcPtr::new(|metadata| Person {
            name,
            parent: RefCell::new(None),
            children: RefCell::new(Vec::default()),
            metadata,
        })
    }

    fn new_with_parent(
        name: String,
        parent: &GcPtr<Person>,
    ) -> Result<GcPtr<Person>, AddChildError> {
        let new_person = Person::new(name);
        Self::add_child(parent, &new_person)?;
        Ok(new_person)
    }

    fn add_child(parent: &GcPtr<Self>, child: &GcPtr<Person>) -> Result<(), AddChildError> {
        let mut child_parent = child.parent.borrow_mut();
        if child_parent.is_some() {
            return Err(AddChildError);
        }
        *child_parent = Some(child.metadata.new_pointer(parent.clone()));
        drop(child_parent);

        parent
            .children
            .borrow_mut()
            .push(parent.metadata.new_pointer(child.clone()));
        Ok(())
    }
}

impl Drop for Person {
    fn drop(&mut self) {
        eprintln!("{} died", self.name);
    }
}

impl fmt::Display for Person {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
        use fmt::Write;

        write!(f, "{}\n", self.name)?;

        let mut indent = IndentWriter::new("  ", f);
        if let Some(parent) = self.parent.borrow().as_ref() {
            write!(&mut indent, "parent: {}\n", parent.name)?;
        }

        let children = self.children.borrow();
        if !children.is_empty() {
            write!(&mut indent, "children:\n")?;
            let mut indent = IndentWriter::new("  ", &mut indent);
            for child_ptr in self.children.borrow().iter() {
                write!(&mut indent, "{}", &**child_ptr)?;
            }
        }
        Ok(())
    }
}

fn main() {
    let john = Person::new("John".into());
    let eve = Person::new_with_parent("Eve".into(), &john).unwrap();
    let mary = Person::new_with_parent("Mary".into(), &john).unwrap();
    let sabine = Person::new_with_parent("Sabine".into(), &mary).unwrap();
    let evelyn = Person::new_with_parent("Evelyn".into(), &mary).unwrap();
    let dennis = Person::new_with_parent("Dennis".into(), &eve).unwrap();
    drop(eve);
    drop(mary);
    drop(sabine);
    drop(evelyn);
    drop(dennis);

    print!("Family tree: {}", &*john);
}