1use serde::{Deserialize, Serialize};
8use std::collections::BTreeMap;
9
10pub const FORMAT_NAME: &str = "rlxp";
12
13pub const FORMAT_VERSION: u32 = 1;
15
16pub const COMPAT_VERSION: u32 = 1;
18
19#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
21pub struct GraphRef {
22 pub path: String,
23 pub encoding: String,
25}
26
27#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
29pub struct WeightsRef {
30 pub index: String,
31}
32
33#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
35pub struct SidecarRef {
36 pub id: String,
37 pub path: String,
38 #[serde(default, skip_serializing_if = "Option::is_none")]
39 pub media_type: Option<String>,
40 #[serde(default)]
41 pub codec: crate::tier::Codec,
42}
43
44#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Default)]
46pub struct DistRef {
47 #[serde(default, skip_serializing_if = "Option::is_none")]
48 pub placement: Option<String>,
49}
50
51#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
53pub struct Manifest {
54 pub format: String,
55 pub format_version: u32,
56 pub compat_version: u32,
57 pub name: String,
58 #[serde(default, skip_serializing_if = "Option::is_none")]
59 pub producer: Option<String>,
60 #[serde(default, skip_serializing_if = "Vec::is_empty")]
61 pub features: Vec<String>,
62 pub graph: GraphRef,
63 #[serde(default, skip_serializing_if = "Option::is_none")]
64 pub weights: Option<WeightsRef>,
65 #[serde(default, skip_serializing_if = "Vec::is_empty")]
66 pub sidecars: Vec<SidecarRef>,
67 #[serde(default, skip_serializing_if = "Option::is_none")]
68 pub dist: Option<DistRef>,
69 #[serde(default, skip_serializing_if = "Option::is_none")]
70 pub created_unix: Option<u64>,
71 #[serde(default, skip_serializing_if = "BTreeMap::is_empty")]
72 pub extensions: BTreeMap<String, serde_json::Value>,
73}
74
75impl Manifest {
76 pub fn new_v1(name: impl Into<String>) -> Self {
78 Self {
79 format: FORMAT_NAME.to_string(),
80 format_version: FORMAT_VERSION,
81 compat_version: COMPAT_VERSION,
82 name: name.into(),
83 producer: None,
84 features: Vec::new(),
85 graph: GraphRef {
86 path: "graph/mir.bin".into(),
87 encoding: "bincode_graph_v1".into(),
88 },
89 weights: Some(WeightsRef {
90 index: "weights/index.json".into(),
91 }),
92 sidecars: Vec::new(),
93 dist: None,
94 created_unix: None,
95 extensions: BTreeMap::new(),
96 }
97 }
98
99 pub fn validate(&self) -> anyhow::Result<()> {
101 if self.format != FORMAT_NAME {
102 anyhow::bail!(
103 "unknown package format {:?} (expected {:?})",
104 self.format,
105 FORMAT_NAME
106 );
107 }
108 if self.format_version > FORMAT_VERSION {
109 anyhow::bail!(
110 "package format_version {} newer than loader {}",
111 self.format_version,
112 FORMAT_VERSION
113 );
114 }
115 if self.compat_version > COMPAT_VERSION {
116 anyhow::bail!(
117 "package requires compat_version {} (loader supports {})",
118 self.compat_version,
119 COMPAT_VERSION
120 );
121 }
122 if self.graph.encoding != "bincode_graph_v1" && self.graph.encoding != "none" {
123 anyhow::bail!("unsupported graph encoding {:?}", self.graph.encoding);
124 }
125 Ok(())
126 }
127}