hugr_core/envelope/
package_json.rs1use derive_more::{Display, Error, From};
3use itertools::Itertools;
4use std::io;
5
6use super::{ExtensionBreakingError, WithGenerator, check_breaking_extensions};
7use crate::extension::ExtensionRegistry;
8use crate::extension::resolution::ExtensionResolutionError;
9use crate::package::Package;
10use crate::{Extension, Hugr};
11
12pub(super) fn from_json_reader(
14 reader: impl io::Read,
15 extension_registry: &ExtensionRegistry,
16) -> Result<Package, PackageEncodingError> {
17 let val: serde_json::Value = serde_json::from_reader(reader)?;
18
19 let PackageDeser {
20 modules,
21 extensions: pkg_extensions,
22 } = serde_json::from_value::<PackageDeser>(val.clone())?;
23 let mut modules = modules.into_iter().map(|h| h.0).collect_vec();
24 let pkg_extensions = ExtensionRegistry::new_with_extension_resolution(
25 pkg_extensions,
26 &extension_registry.into(),
27 )
28 .map_err(|err| WithGenerator::new(err, &modules))?;
29
30 let mut combined_registry = extension_registry.clone();
32 combined_registry.extend(&pkg_extensions);
33
34 for module in &modules {
35 check_breaking_extensions(module, &combined_registry)
36 .map_err(|err| WithGenerator::new(err, &modules))?;
37 }
38 modules
39 .iter_mut()
40 .try_for_each(|module| module.resolve_extension_defs(&combined_registry))
41 .map_err(|err| WithGenerator::new(err, &modules))?;
42
43 Ok(Package {
44 modules,
45 extensions: pkg_extensions,
46 })
47}
48
49pub(super) fn to_json_writer<'h>(
51 hugrs: impl IntoIterator<Item = &'h Hugr>,
52 extensions: &ExtensionRegistry,
53 writer: impl io::Write,
54) -> Result<(), PackageEncodingError> {
55 let pkg_ser = PackageSer {
56 modules: hugrs.into_iter().map(HugrSer).collect(),
57 extensions: extensions.iter().map(std::convert::AsRef::as_ref).collect(),
58 };
59
60 #[cfg(all(test, not(miri)))]
65 if std::env::var("HUGR_TEST_SCHEMA").is_ok_and(|x| !x.is_empty()) {
66 use crate::hugr::serialize::test::check_hugr_serialization_schema;
67
68 for hugr in &pkg_ser.modules {
69 check_hugr_serialization_schema(hugr.0);
70 }
71 }
72
73 serde_json::to_writer(writer, &pkg_ser)?;
74 Ok(())
75}
76
77#[derive(Debug, Display, Error, From)]
79#[non_exhaustive]
80#[display("Error reading or writing a package in JSON format.")]
81pub enum PackageEncodingError {
82 JsonEncoding(#[from] serde_json::Error),
84 IOError(#[from] io::Error),
86 ExtensionResolution(#[from] WithGenerator<ExtensionResolutionError>),
88 ExtensionVersion(#[from] WithGenerator<ExtensionBreakingError>),
90}
91
92#[derive(Debug, serde::Serialize)]
97struct PackageSer<'h> {
98 pub modules: Vec<HugrSer<'h>>,
99 pub extensions: Vec<&'h Extension>,
100}
101#[derive(Debug, serde::Serialize)]
102#[serde(transparent)]
103struct HugrSer<'h>(#[serde(serialize_with = "Hugr::serde_serialize")] pub &'h Hugr);
104
105#[derive(Debug, serde::Deserialize)]
110struct PackageDeser {
111 pub modules: Vec<HugrDeser>,
112 pub extensions: Vec<Extension>,
113}
114#[derive(Debug, serde::Deserialize)]
115#[serde(transparent)]
116struct HugrDeser(#[serde(deserialize_with = "Hugr::serde_deserialize")] pub Hugr);