1use std::marker::PhantomData;
2
3use schemars::JsonSchema;
4use serde::{Deserialize, Serialize};
5
6#[cfg(feature = "parquet")]
7use crate::data::write_checks::ArrayWriteCheck;
8use crate::{SubblockMode, validate::Reason};
9
10pub trait ArrayType {
11 const DATA_TYPE: DataType;
12}
13
14macro_rules! array_types {
15 ($(#[doc = $doc:literal] $name:ident,)*) => {
16 #[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize, JsonSchema)]
17 pub enum DataType {
18 $($name,)*
19 }
20
21 pub mod array_type {
22 use super::*;
23 $(
24 #[derive(Debug, Default, Clone, Copy, PartialEq, Serialize, Deserialize, JsonSchema)]
25 pub struct $name {}
26 impl ArrayType for $name {
27 const DATA_TYPE: DataType = DataType::$name;
28 }
29 )*
30 }
31 };
32}
33
34array_types! {
35 Image,
37 Scalar,
39 Vertex,
41 Segment,
43 Triangle,
45 Name,
47 Gradient,
49 Texcoord,
51 Boundary,
53 RegularSubblock,
55 FreeformSubblock,
57 Number,
59 Index,
61 Vector,
63 Text,
65 Boolean,
67 Color,
69}
70
71#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, JsonSchema)]
72pub struct Array<T> {
73 filename: String,
74 item_count: u64,
75 #[serde(default, skip_serializing, skip_deserializing)]
76 private: ArrayPrivate,
77 #[serde(default, skip_serializing, skip_deserializing)]
78 _marker: PhantomData<T>,
79}
80
81impl<T: ArrayType> Array<T> {
82 pub(crate) fn new(filename: String, item_count: u64) -> Self {
83 Self {
84 filename,
85 item_count,
86 private: Default::default(),
87 _marker: Default::default(),
88 }
89 }
90
91 pub(crate) fn constrain(&mut self, constraint: Constraint) -> Result<(), Reason> {
92 assert_eq!(
93 constraint.data_type(),
94 self.data_type(),
95 "invalid constraint {constraint:?} for {:?} array",
96 self.data_type()
97 );
98 self.private.constraint = Some(constraint);
99 Ok(())
100 }
101
102 pub(crate) fn constraint(&self) -> &Constraint {
103 self.private
104 .constraint
105 .as_ref()
106 .expect("array should have been validated")
107 }
108
109 pub(crate) fn filename(&self) -> &str {
111 &self.filename
112 }
113
114 pub fn item_count(&self) -> u64 {
116 self.item_count
117 }
118
119 pub fn data_type(&self) -> DataType {
121 T::DATA_TYPE
122 }
123}
124
125#[cfg(feature = "parquet")]
126impl<T: ArrayType> Array<T> {
127 pub(crate) fn add_write_checks(mut self, checks: Vec<ArrayWriteCheck>) -> Self {
128 self.private.checks.extend(checks);
129 self
130 }
131
132 pub(crate) fn run_write_checks(&self) -> Vec<Reason> {
133 let mut reasons = Vec::new();
134 for check in &self.private.checks {
135 if let Err(r) = check.check(self) {
136 reasons.push(r);
137 }
138 }
139 reasons
140 }
141}
142
143#[cfg(not(feature = "parquet"))]
144impl<T: ArrayType> Array<T> {
145 pub(crate) fn run_write_checks(&self) -> Vec<Reason> {
146 Vec::new()
147 }
148}
149
150#[derive(Debug, Default, Clone)]
151struct ArrayPrivate {
152 constraint: Option<Constraint>,
153 #[cfg(feature = "parquet")]
154 checks: Vec<ArrayWriteCheck>,
155}
156
157impl PartialEq for ArrayPrivate {
158 fn eq(&self, _other: &Self) -> bool {
159 true
161 }
162}
163
164#[derive(Debug, Clone, PartialEq)]
165pub(crate) enum Constraint {
166 Image,
167 Scalar,
168 Size,
169 Vertex,
170 Segment(u64),
171 Triangle(u64),
172 Name,
173 Gradient,
174 Texcoord,
175 Boundary,
176 RegularSubblock {
177 block_count: [u32; 3],
178 subblock_count: [u32; 3],
179 mode: Option<SubblockMode>,
180 },
181 FreeformSubblock {
182 block_count: [u32; 3],
183 },
184 Number,
185 Index(u64),
186 Vector,
187 String,
188 Boolean,
189 Color,
190}
191
192impl Constraint {
193 pub fn data_type(&self) -> DataType {
194 match self {
195 Self::Image => DataType::Image,
196 Self::Scalar | Self::Size => DataType::Scalar,
197 Self::Vertex => DataType::Vertex,
198 Self::Segment(_) => DataType::Segment,
199 Self::Triangle(_) => DataType::Triangle,
200 Self::Name => DataType::Name,
201 Self::Gradient => DataType::Gradient,
202 Self::Texcoord => DataType::Texcoord,
203 Self::Boundary => DataType::Boundary,
204 Self::RegularSubblock { .. } => DataType::RegularSubblock,
205 Self::FreeformSubblock { .. } => DataType::FreeformSubblock,
206 Self::Number => DataType::Number,
207 Self::Index(_) => DataType::Index,
208 Self::Vector => DataType::Vector,
209 Self::String => DataType::Text,
210 Self::Boolean => DataType::Boolean,
211 Self::Color => DataType::Color,
212 }
213 }
214}