hugr_persistent/lib.rs
1#![doc(hidden)] // TODO: remove when stable
2
3//! Persistent data structure for HUGR mutations.
4//!
5//! This crate provides a persistent data structure [`PersistentHugr`] that
6//! implements [`HugrView`](hugr_core::HugrView). A persistent data structure:
7//! - is cheap to clone,
8//! - shares as much of the underlying data with other versions of the data
9//! structure as possible, even as it gets mutated (unlike, say the Rust
10//! `Cow` type),
11//! - in our case, multiple versions of the same data structure can even be
12//! merged together (with a notion of "compatibility" between versions).
13//!
14//! Persistent data structures are sometimes called immutable data structures,
15//! as mutations can always be implemented as cheap clone + cheap mutation.
16//! Mutations to the data are stored persistently as a set of [`Commit`]s along
17//! with the dependencies between the commits.
18//!
19//! As a result of persistency, the entire mutation history of a HUGR can be
20//! traversed and references to previous versions of the data remain valid even
21//! as the HUGR graph is "mutated" by applying patches: the patches are in
22//! effect added to the history as new commits.
23//!
24//! Multiple [`PersistentHugr`] may use commits from a common
25//! [`CommitStateSpace`]: [`PersistentHugr`]s derived from mutations of previous
26//! [`PersistentHugr`]s will always share a common state space. A [`Walker`]
27//! can be used on a state space to explore all possible [`PersistentHugr`]s
28//! that can be created from commits in the space.
29//!
30//! ## Overlapping commits
31//!
32//! In general, [`CommitStateSpace`] may contain overlapping commits. Such
33//! mutations are mutually exclusive as they modify the same nodes. It is
34//! therefore not possible to apply all commits in a [`CommitStateSpace`]
35//! simultaneously. A [`PersistentHugr`] on the other hand always contains a
36//! a subset of the commits of a [`CommitStateSpace`], with the guarantee
37//! that they are all non-overlapping, compatible commits. By applying all
38//! commits in a [`PersistentHugr`], we can materialize a
39//! [`Hugr`](hugr_core::Hugr). Traversing the materialized HUGR is equivalent to
40//! using the [`HugrView`](hugr_core::HugrView) implementation of the
41//! corresponding [`PersistentHugr`].
42//!
43//! ## Summary of data types
44//!
45//! - [`Commit`] A modification to a [`Hugr`](hugr_core::Hugr) (currently a
46//! [`SimpleReplacement`](hugr_core::SimpleReplacement)) that forms the atomic
47//! unit of change for a [`PersistentHugr`] (like a commit in git). This is a
48//! reference-counted value that is cheap to clone and will be freed when all
49//! [`PersistentHugr`] and [`CommitStateSpace`] that refer to it are dropped.
50//! - [`PersistentHugr`] A data structure that implements
51//! [`HugrView`][hugr_core::HugrView] and can be used as a drop-in replacement
52//! for a [`Hugr`][hugr_core::Hugr] for read-only access and mutations through
53//! the [`PatchVerification`](hugr_core::hugr::patch::PatchVerification) and
54//! [`Patch`](hugr_core::hugr::Patch) traits. Mutations are stored as a
55//! history of commits. Unlike [`CommitStateSpace`], it maintains the
56//! invariant that all contained commits are compatible with eachother.
57//! - [`CommitStateSpace`] A registry of all commits within the
58//! [`PersistentHugr`]s of the state space. Includes the base HUGR and any
59//! number of possibly incompatible (overlapping) commits. Unlike a
60//! [`PersistentHugr`], a state space can contain mutually exclusive commits.
61//!
62//! ## Usage
63//!
64//! A [`PersistentHugr`] can be created from a base HUGR using
65//! [`PersistentHugr::with_base`]. Replacements can then be applied to it
66//! using [`PersistentHugr::add_replacement`]. Alternatively, if you already
67//! have a populated state space, use [`PersistentHugr::try_new`] to create a
68//! new HUGR with those commits.
69//!
70//! To obtain a [`PersistentHugr`] from your state space, use
71//! [`CommitStateSpace::try_create`]. A [`PersistentHugr`] can always be
72//! materialized into a [`Hugr`][hugr_core::Hugr] type using
73//! [`PersistentHugr::to_hugr`].
74
75pub mod commit;
76pub use commit::{Commit, InvalidCommit};
77
78mod parents_view;
79
80pub mod persistent_hugr;
81pub use persistent_hugr::PersistentHugr;
82
83pub mod state_space;
84use state_space::CommitData;
85pub use state_space::{CommitId, CommitStateSpace, PatchNode};
86
87pub mod subgraph;
88pub use subgraph::PinnedSubgraph;
89
90mod trait_impls;
91
92pub mod walker;
93pub use walker::Walker;
94
95mod wire;
96pub use wire::PersistentWire;
97
98/// A replacement operation that can be applied to a [`PersistentHugr`].
99pub type PersistentReplacement = hugr_core::SimpleReplacement<PatchNode>;
100
101pub mod serial {
102 //! Serialized formats for commits, state spaces and persistent HUGRs.
103 pub use super::persistent_hugr::serial::*;
104 pub use super::state_space::serial::*;
105}
106
107#[cfg(test)]
108mod tests;