nodedb_array/schema/
array_schema.rs1use serde::{Deserialize, Serialize};
13
14use super::attr_spec::AttrSpec;
15use super::cell_order::{CellOrder, TileOrder};
16use super::dim_spec::DimSpec;
17
18#[derive(
20 Debug,
21 Clone,
22 PartialEq,
23 Eq,
24 Serialize,
25 Deserialize,
26 zerompk::ToMessagePack,
27 zerompk::FromMessagePack,
28)]
29pub struct ArraySchema {
30 pub name: String,
31 pub dims: Vec<DimSpec>,
32 pub attrs: Vec<AttrSpec>,
33 pub tile_extents: Vec<u64>,
36 pub cell_order: CellOrder,
37 pub tile_order: TileOrder,
38}
39
40impl ArraySchema {
41 pub fn arity(&self) -> usize {
42 self.dims.len()
43 }
44
45 pub fn dim(&self, name: &str) -> Option<&DimSpec> {
46 self.dims.iter().find(|d| d.name == name)
47 }
48
49 pub fn attr(&self, name: &str) -> Option<&AttrSpec> {
50 self.attrs.iter().find(|a| a.name == name)
51 }
52
53 pub fn content_msgpack(&self) -> Vec<u8> {
59 let payload = SchemaContent {
62 dims: &self.dims,
63 attrs: &self.attrs,
64 tile_extents: &self.tile_extents,
65 cell_order: self.cell_order,
66 tile_order: self.tile_order,
67 };
68 zerompk::to_msgpack_vec(&payload).unwrap_or_default()
69 }
70}
71
72#[derive(zerompk::ToMessagePack)]
75struct SchemaContent<'a> {
76 dims: &'a Vec<DimSpec>,
77 attrs: &'a Vec<AttrSpec>,
78 tile_extents: &'a Vec<u64>,
79 cell_order: CellOrder,
80 tile_order: TileOrder,
81}
82
83#[cfg(test)]
84mod tests {
85 use super::super::attr_spec::AttrType;
86 use super::super::dim_spec::DimType;
87 use super::*;
88 use crate::types::domain::{Domain, DomainBound};
89
90 #[test]
91 fn content_msgpack_excludes_name() {
92 let mk = |name: &str| ArraySchema {
96 name: name.into(),
97 dims: vec![DimSpec::new(
98 "x",
99 DimType::Int64,
100 Domain::new(DomainBound::Int64(0), DomainBound::Int64(15)),
101 )],
102 attrs: vec![AttrSpec::new("v", AttrType::Float64, true)],
103 tile_extents: vec![4],
104 cell_order: CellOrder::Hilbert,
105 tile_order: TileOrder::Hilbert,
106 };
107 let a = mk("alpha");
108 let b = mk("beta");
109 assert_ne!(a.name, b.name);
110 assert_eq!(a.content_msgpack(), b.content_msgpack());
111 }
112
113 #[test]
114 fn schema_arity_matches_dim_count() {
115 let s = ArraySchema {
116 name: "g".into(),
117 dims: vec![
118 DimSpec::new(
119 "chrom",
120 DimType::Int64,
121 Domain::new(DomainBound::Int64(0), DomainBound::Int64(24)),
122 ),
123 DimSpec::new(
124 "pos",
125 DimType::Int64,
126 Domain::new(DomainBound::Int64(0), DomainBound::Int64(300_000_000)),
127 ),
128 ],
129 attrs: vec![AttrSpec::new("variant", AttrType::String, false)],
130 tile_extents: vec![1, 1_000_000],
131 cell_order: CellOrder::Hilbert,
132 tile_order: TileOrder::Hilbert,
133 };
134 assert_eq!(s.arity(), 2);
135 assert!(s.dim("chrom").is_some());
136 assert!(s.attr("variant").is_some());
137 assert!(s.dim("missing").is_none());
138 }
139}