Skip to main content

powerio_pkg/
model.rs

1//! The model kind and the single typed IR payload.
2//!
3//! The two IR families never merge. [`ModelKind`] is stored explicitly on the
4//! package; [`ModelPayload`] is the tagged wrapper around exactly one payload.
5//! The payload's `kind()` must agree with the package's `model_kind` (the
6//! package asserts this), but the authoritative kind is the standalone field, so
7//! a reader never infers the kind from which payload field is present.
8
9use serde::{Deserialize, Serialize};
10
11use powerio::BalancedNetwork;
12use powerio_dist::MulticonductorNetwork;
13
14/// Which concrete static-grid IR family the payload is.
15#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
16#[serde(rename_all = "snake_case")]
17#[non_exhaustive]
18pub enum ModelKind {
19    /// Scalar positive-sequence transmission model ([`powerio::BalancedNetwork`]).
20    Balanced,
21    /// Wire-coordinate distribution model ([`powerio_dist::MulticonductorNetwork`]).
22    Multiconductor,
23}
24
25/// The one IR payload a package carries, tagged by `kind` in JSON so the payload
26/// is self-describing in addition to the top-level `model_kind`.
27///
28/// The payload is a direct serde snapshot of the live PowerIO Rust IR
29/// ([`powerio::Network`] / [`powerio_dist::DistNetwork`]). It is experimental: it
30/// grows whenever the IR does, with no envelope version change. Only the envelope
31/// is versioned. See `docs/src/pio-json-schema.md`.
32#[derive(Clone, Debug, Serialize, Deserialize)]
33#[serde(tag = "kind", rename_all = "snake_case")]
34pub enum ModelPayload {
35    Balanced {
36        balanced_network: Box<BalancedNetwork>,
37    },
38    Multiconductor {
39        multiconductor_network: Box<MulticonductorNetwork>,
40    },
41}
42
43impl ModelPayload {
44    pub fn balanced(net: BalancedNetwork) -> Self {
45        Self::Balanced {
46            balanced_network: Box::new(net),
47        }
48    }
49
50    pub fn multiconductor(net: MulticonductorNetwork) -> Self {
51        Self::Multiconductor {
52            multiconductor_network: Box::new(net),
53        }
54    }
55
56    pub fn kind(&self) -> ModelKind {
57        match self {
58            ModelPayload::Balanced { .. } => ModelKind::Balanced,
59            ModelPayload::Multiconductor { .. } => ModelKind::Multiconductor,
60        }
61    }
62
63    /// The balanced payload, if this is one.
64    pub fn as_balanced(&self) -> Option<&BalancedNetwork> {
65        match self {
66            ModelPayload::Balanced { balanced_network } => Some(balanced_network),
67            ModelPayload::Multiconductor { .. } => None,
68        }
69    }
70
71    /// The multiconductor payload, if this is one.
72    pub fn as_multiconductor(&self) -> Option<&MulticonductorNetwork> {
73        match self {
74            ModelPayload::Multiconductor {
75                multiconductor_network,
76            } => Some(multiconductor_network),
77            ModelPayload::Balanced { .. } => None,
78        }
79    }
80}