Skip to content
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 7 additions & 1 deletion hugr-persistent/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,18 @@ license.workspace = true
name = "persistent_walker_example"

[dependencies]
relrc = { workspace = true, features = ["petgraph"] }
hugr-core.path = "../hugr-core"

delegate.workspace = true
derive_more.workspace = true
itertools.workspace = true
petgraph.workspace = true
portgraph.workspace = true
relrc = { workspace = true, features = ["petgraph", "serde"] }
serde.workspace = true
serde_json.workspace = true
thiserror.workspace = true
wyhash = "0.6.0"

[lints]
workspace = true
Expand All @@ -27,3 +31,5 @@ workspace = true
rstest.workspace = true
lazy_static.workspace = true
semver.workspace = true
serde_with.workspace = true
insta.workspace = true
2 changes: 1 addition & 1 deletion hugr-persistent/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ mod trait_impls;
pub mod walker;

pub use persistent_hugr::{Commit, PersistentHugr};
pub use resolver::PointerEqResolver;
pub use resolver::{PointerEqResolver, Resolver, SerdeHashResolver};
pub use state_space::{CommitId, CommitStateSpace, InvalidCommit, PatchNode};
pub use walker::{PinnedWire, Walker};

Expand Down
5 changes: 4 additions & 1 deletion hugr-persistent/src/parents_view.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,10 @@ pub(crate) struct ParentsView<'a> {
}

impl<'a> ParentsView<'a> {
pub(crate) fn from_commit(commit_id: CommitId, state_space: &'a CommitStateSpace) -> Self {
pub(crate) fn from_commit<R>(
commit_id: CommitId,
state_space: &'a CommitStateSpace<R>,
) -> Self {
let mut hugrs = BTreeMap::new();
for parent in state_space.parents(commit_id) {
hugrs.insert(parent, state_space.commit_hugr(parent));
Expand Down
35 changes: 20 additions & 15 deletions hugr-persistent/src/persistent_hugr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,11 @@ use relrc::RelRc;

use crate::{
CommitData, CommitId, CommitStateSpace, InvalidCommit, PatchNode, PersistentReplacement,
Resolver,
};

pub mod serial;

/// A patch that can be applied to a [`PersistentHugr`] or a
/// [`CommitStateSpace`] as an atomic commit.
///
Expand All @@ -41,9 +44,9 @@ impl Commit {
/// If any of the parents of the replacement are not in the commit state
/// space, this function will return an [`InvalidCommit::UnknownParent`]
/// error.
pub fn try_from_replacement(
pub fn try_from_replacement<R>(
replacement: PersistentReplacement,
graph: &CommitStateSpace,
graph: &CommitStateSpace<R>,
) -> Result<Commit, InvalidCommit> {
if replacement.subgraph().nodes().is_empty() {
return Err(InvalidCommit::EmptyReplacement);
Expand Down Expand Up @@ -190,15 +193,15 @@ impl<'a> From<&'a RelRc<CommitData, ()>> for &'a Commit {
/// Currently, only patches that apply to subgraphs within dataflow regions
/// are supported.
#[derive(Clone, Debug)]
pub struct PersistentHugr {
pub struct PersistentHugr<R = crate::PointerEqResolver> {
/// The state space of all commits.
///
/// Invariant: all commits are "compatible", meaning that no two patches
/// invalidate the same node.
state_space: CommitStateSpace,
state_space: CommitStateSpace<R>,
}

impl PersistentHugr {
impl<R: Resolver> PersistentHugr<R> {
/// Create a [`PersistentHugr`] with `hugr` as its base HUGR.
///
/// All replacements added in the future will apply on top of `hugr`.
Expand Down Expand Up @@ -228,13 +231,6 @@ impl PersistentHugr {
graph.try_extract_hugr(graph.all_commit_ids())
}

/// Construct a [`PersistentHugr`] from a [`CommitStateSpace`].
///
/// Does not check that the commits are compatible.
pub(crate) fn from_state_space_unsafe(state_space: CommitStateSpace) -> Self {
Self { state_space }
}

/// Add a replacement to `self`.
///
/// The effect of this is equivalent to applying `replacement` to the
Expand Down Expand Up @@ -314,6 +310,15 @@ impl PersistentHugr {
}
Ok(commit_id.expect("new_commits cannot be empty"))
}
}

impl<R> PersistentHugr<R> {
/// Construct a [`PersistentHugr`] from a [`CommitStateSpace`].
///
/// Does not check that the commits are compatible.
pub(crate) fn from_state_space_unsafe(state_space: CommitStateSpace<R>) -> Self {
Self { state_space }
}

/// Convert this `PersistentHugr` to a materialized Hugr by applying all
/// commits in `self`.
Expand Down Expand Up @@ -373,12 +378,12 @@ impl PersistentHugr {
}

/// Get a reference to the underlying state space of `self`.
pub fn as_state_space(&self) -> &CommitStateSpace {
pub fn as_state_space(&self) -> &CommitStateSpace<R> {
&self.state_space
}

/// Convert `self` into its underlying [`CommitStateSpace`].
pub fn into_state_space(self) -> CommitStateSpace {
pub fn into_state_space(self) -> CommitStateSpace<R> {
self.state_space
}

Expand Down Expand Up @@ -654,7 +659,7 @@ impl PersistentHugr {
}
}

impl IntoIterator for PersistentHugr {
impl<R> IntoIterator for PersistentHugr<R> {
type Item = Commit;

type IntoIter = vec::IntoIter<Commit>;
Expand Down
82 changes: 82 additions & 0 deletions hugr-persistent/src/persistent_hugr/serial.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
//! Serialized format for [`PersistentHugr`]

use hugr_core::Hugr;

use crate::{CommitStateSpace, SerdeHashResolver, state_space::serial::SerialCommitStateSpace};

use super::PersistentHugr;

/// Serialized format for [`PersistentHugr`]
#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
pub struct SerialPersistentHugr<H> {
/// The state space of all commits.
state_space: SerialCommitStateSpace<H>,
}

impl<H: Into<Hugr> + From<Hugr> + serde::Serialize> PersistentHugr<SerdeHashResolver<H>> {
/// Create a new [`CommitStateSpace`] from its serialized format
pub fn from_serial(value: SerialPersistentHugr<H>) -> Self {
let SerialPersistentHugr { state_space } = value;
let state_space = CommitStateSpace::from_serial(state_space);
Self { state_space }
}

/// Convert a [`CommitStateSpace`] into its serialized format
pub fn into_serial(self) -> SerialPersistentHugr<H> {
let Self { state_space } = self;
let state_space = state_space.into_serial();
SerialPersistentHugr { state_space }
}

/// Create a serialized format from a reference to [`CommitStateSpace`]
pub fn to_serial(&self) -> SerialPersistentHugr<H>
where
H: From<Hugr>,
{
let Self { state_space } = self;
let state_space = state_space.to_serial();
SerialPersistentHugr { state_space }
}
}

impl<H: Into<Hugr> + From<Hugr> + serde::Serialize> From<PersistentHugr<SerdeHashResolver<H>>>
for SerialPersistentHugr<H>
{
fn from(value: PersistentHugr<SerdeHashResolver<H>>) -> Self {
value.into_serial()
}
}

impl<H: Into<Hugr> + From<Hugr> + serde::Serialize> From<SerialPersistentHugr<H>>
for PersistentHugr<SerdeHashResolver<H>>
{
fn from(value: SerialPersistentHugr<H>) -> Self {
PersistentHugr::from_serial(value)
}
}

#[cfg(test)]
mod tests {
use super::*;
use crate::{
CommitId,
tests::{WrappedHugr, test_state_space},
};

use rstest::rstest;

#[rstest]
fn test_serde_persistent_hugr(
test_state_space: (
CommitStateSpace<SerdeHashResolver<WrappedHugr>>,
[CommitId; 4],
),
) {
let (state_space, [cm1, cm2, _, cm4]) = test_state_space;

let per_hugr = state_space.try_extract_hugr([cm1, cm2, cm4]).unwrap();
let ser_per_hugr = per_hugr.to_serial();

insta::assert_snapshot!(serde_json::to_string_pretty(&ser_per_hugr).unwrap());
}
}
Loading
Loading