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 the serde snapshot of the PowerIO Rust IR
29/// ([`powerio::Network`] / [`powerio_dist::DistNetwork`]), declared by the
30/// package's `payload_schema` / `payload_schema_version` fields and versioned
31/// independently of the envelope: additive IR growth bumps the payload minor
32/// with no envelope version change. See `docs/src/pio-json-schema.md`.
33#[derive(Clone, Debug, Serialize, Deserialize)]
34#[serde(tag = "kind", rename_all = "snake_case")]
35pub enum ModelPayload {
36 Balanced {
37 balanced_network: Box<BalancedNetwork>,
38 },
39 Multiconductor {
40 multiconductor_network: Box<MulticonductorNetwork>,
41 },
42}
43
44impl ModelPayload {
45 pub fn balanced(net: BalancedNetwork) -> Self {
46 Self::Balanced {
47 balanced_network: Box::new(net),
48 }
49 }
50
51 pub fn multiconductor(net: MulticonductorNetwork) -> Self {
52 Self::Multiconductor {
53 multiconductor_network: Box::new(net),
54 }
55 }
56
57 pub fn kind(&self) -> ModelKind {
58 match self {
59 ModelPayload::Balanced { .. } => ModelKind::Balanced,
60 ModelPayload::Multiconductor { .. } => ModelKind::Multiconductor,
61 }
62 }
63
64 /// The balanced payload, if this is one.
65 pub fn as_balanced(&self) -> Option<&BalancedNetwork> {
66 match self {
67 ModelPayload::Balanced { balanced_network } => Some(balanced_network),
68 ModelPayload::Multiconductor { .. } => None,
69 }
70 }
71
72 /// The multiconductor payload, if this is one.
73 pub fn as_multiconductor(&self) -> Option<&MulticonductorNetwork> {
74 match self {
75 ModelPayload::Multiconductor {
76 multiconductor_network,
77 } => Some(multiconductor_network),
78 ModelPayload::Balanced { .. } => None,
79 }
80 }
81}