Skip to main content

powerio/
ir.rs

1//! PowerIO IR serialization and deserialization.
2
3use powerio_core::{
4    ArtifactPath, Diagnostic, EmitResult, Error, Fidelity, MemoryArtifact, PioModule,
5};
6
7use crate::PioValue;
8
9/// Serialize a diagnostics list as the JSON array of PowerIO IR diagnostic
10/// records: the encoding a module's `diagnostics` field carries, with an
11/// identity minted for every record that has none.
12///
13/// # Errors
14/// The records cannot be encoded as JSON.
15pub fn serialize_diagnostics(diagnostics: &[Diagnostic]) -> Result<String, Error> {
16    let records = crate::stored::encode_diagnostics(diagnostics);
17    serde_json::to_string(&records).map_err(|cause| {
18        Error::new(
19            &crate::codes::READ_MODULE_INVALID,
20            format!("diagnostics could not be encoded as JSON: {cause}"),
21        )
22        .with_cause(cause)
23    })
24}
25
26/// Generate the JSON Schema for this build's PowerIO IR document.
27#[cfg(feature = "schema")]
28#[must_use]
29pub fn generate_ir_schema() -> schemars::Schema {
30    schemars::schema_for!(crate::stored::StoredModule)
31}
32
33/// Serialize a dynamic module as PowerIO IR.
34///
35/// PowerIO IR is the durable representation of a complete [`PioModule`]. It
36/// is separate from the grid exchange formats handled by [`crate::emit`].
37///
38/// # Errors
39/// The module cannot be represented by the current IR schema, or the
40/// destination refuses the artifact.
41pub fn serialize<T>(
42    module: &PioModule<T>,
43    output: impl powerio_core::IntoDestination,
44) -> Result<EmitResult, Error>
45where
46    T: Clone + Into<PioValue>,
47{
48    let module = module.clone().map_value(Into::into);
49    let text = crate::stored::emit_module(&module)?;
50    let artifact = MemoryArtifact::new(ArtifactPath::new("module.pio.json")?, text.into_bytes());
51    output.into_destination()?.__commit_artifacts(
52        false,
53        Fidelity::Canonical,
54        vec![artifact],
55        Vec::new(),
56    )
57}
58
59/// Deserialize one PowerIO IR input: a file name, content in memory, or a
60/// [`powerio_core::Source`].
61///
62/// # Errors
63/// The source is not one UTF-8 IR document, or its schema is unsupported or
64/// invalid.
65pub fn deserialize(input: impl powerio_core::IntoSource) -> Result<PioModule<PioValue>, Error> {
66    let source = input.into_source()?;
67    let buffer = source.primary_buffer()?;
68    let text = std::str::from_utf8(buffer.content_bytes()).map_err(|cause| {
69        Error::new(
70            &crate::codes::READ_MODULE_INVALID,
71            format!("PowerIO IR is not valid UTF-8: {cause}"),
72        )
73        .with_cause(cause)
74        .with_source(source.clone())
75    })?;
76    crate::stored::read_module(text)
77        .map(|module| module.with_source(source.clone()))
78        .map_err(|error| error.with_source(source))
79}