deferred-cell

Crates.iodeferred-cell
lib.rsdeferred-cell
version0.6.1
created_at2025-06-30 17:52:12.691152+00
updated_at2025-06-30 20:29:26.817104+00
descriptionA single-assignment, weak reference wrapper for cyclic node graphs with late initialization
homepagehttps://github.com/BernardIgiri/deferred-cell
repositoryhttps://github.com/BernardIgiri/deferred-cell
max_upload_size
id1732136
size16,283
Bernard Igiri (BernardIgiri)

documentation

https://docs.rs/deferred-cell

README

deferred-cell

Crates.io Docs.rs CI

A single-assignment, weak reference wrapper for cyclic node graphs with write-once, late initialization.

This crate provides a lightweight alternative to RefCell<Option<Weak<T>>> when building write-once reference graphs, such as cyclic trees, linked lists, and bidirectional or circular structures. It enables you to cleanly and safely establish weak links between nodes after they are constructed.


✨ Features

  • ✅ Write-once semantics using OnceCell<Weak<T>>
  • ✅ Safe and ergonomic API for deferred initialization
  • ✅ Strong test coverage
  • ✅ Optional helper type for setting values: SetOnce
  • ✅ Iterator extension trait for working with collections

📦 Installation

Add to your Cargo.toml:

[dependencies]
deferred-cell = "0.6"

🧠 Motivation

In Rust, it’s often tricky to build cyclic data structures due to ownership rules. A common workaround is:

RefCell<Option<Weak<T>>>

However, this allows re-assignment and mutation, which is overkill in cases where the weak reference should be set only once. deferred-cell simplifies this pattern with explicit, single-assignment behavior and no runtime borrow checking.


🚀 Example

use deferred_cell::{Deferred, SetOnce, DeferredError};
use std::rc::Rc;

struct Node {
    value: String,
    neighbor: Deferred<Node>,
}

fn main() -> Result<(), DeferredError> {
    let node = Rc::new(Node {
        value: "A".into(),
        neighbor: Deferred::default(),
    });

    let neighbor = Rc::new(Node {
        value: "B".into(),
        neighbor: Deferred::default(),
    });

    // Assign weak reference after both nodes are constructed
    SetOnce::from(&node.neighbor).try_set(&neighbor)?;

    // Access the neighbor
    let linked = node.neighbor.try_get()?;
    assert_eq!(linked.value, "B");

    Ok(())
}

🔧 API Highlights

let d: Deferred<T> = Deferred::default();
let rc: Rc<T> = ...;

// One-time set
SetOnce::from(&d).try_set(&rc)?;

// Later access
let strong: Rc<T> = d.try_get()?;

// Optional checks
if d.is_ready() { ... }

Also includes a DeferredIteratorExt trait to streamline iteration:

let values: Vec<_> = list
    .into_iter()
    .get_deferred()
    .map(|rc| rc.value.clone())
    .collect();

⚠️ Errors

Two error types are defined:

  • DeferredError::DuplicateInitialization – if try_set() is called more than once
  • DeferredError::NotInitializedError – if get() or try_get() is called before a value is set

Commit count: 0

cargo fmt