1use rkyv::{Archive, Deserialize, Serialize};
7
8use crate::address::ChunkAddress;
9use crate::dtype::DType;
10
11#[derive(Debug, Clone, Archive, Serialize, Deserialize)]
13pub enum AttributeValue {
14 Bool(bool),
16 Int8(i8),
18 Int16(i16),
20 Int32(i32),
22 Int64(i64),
24 UInt8(u8),
26 UInt16(u16),
28 UInt32(u32),
30 UInt64(u64),
32 Float32(f32),
34 Float64(f64),
36 String(String),
38 Binary(Vec<u8>),
40 BoolList(Vec<bool>),
42 Int8List(Vec<i8>),
44 Int16List(Vec<i16>),
46 Int32List(Vec<i32>),
48 Int64List(Vec<i64>),
50 UInt8List(Vec<u8>),
52 UInt16List(Vec<u16>),
54 UInt32List(Vec<u32>),
56 UInt64List(Vec<u64>),
58 Float32List(Vec<f32>),
60 Float64List(Vec<f64>),
62 StringList(Vec<String>),
64 BinaryList(Vec<Vec<u8>>),
66}
67
68impl PartialEq for AttributeValue {
69 fn eq(&self, other: &Self) -> bool {
70 match (self, other) {
71 (Self::Bool(a), Self::Bool(b)) => a == b,
72 (Self::Int8(a), Self::Int8(b)) => a == b,
73 (Self::Int16(a), Self::Int16(b)) => a == b,
74 (Self::Int32(a), Self::Int32(b)) => a == b,
75 (Self::Int64(a), Self::Int64(b)) => a == b,
76 (Self::UInt8(a), Self::UInt8(b)) => a == b,
77 (Self::UInt16(a), Self::UInt16(b)) => a == b,
78 (Self::UInt32(a), Self::UInt32(b)) => a == b,
79 (Self::UInt64(a), Self::UInt64(b)) => a == b,
80 (Self::Float32(a), Self::Float32(b)) => a.to_bits() == b.to_bits(),
81 (Self::Float64(a), Self::Float64(b)) => a.to_bits() == b.to_bits(),
82 (Self::String(a), Self::String(b)) => a == b,
83 (Self::Binary(a), Self::Binary(b)) => a == b,
84 (Self::BoolList(a), Self::BoolList(b)) => a == b,
85 (Self::Int8List(a), Self::Int8List(b)) => a == b,
86 (Self::Int16List(a), Self::Int16List(b)) => a == b,
87 (Self::Int32List(a), Self::Int32List(b)) => a == b,
88 (Self::Int64List(a), Self::Int64List(b)) => a == b,
89 (Self::UInt8List(a), Self::UInt8List(b)) => a == b,
90 (Self::UInt16List(a), Self::UInt16List(b)) => a == b,
91 (Self::UInt32List(a), Self::UInt32List(b)) => a == b,
92 (Self::UInt64List(a), Self::UInt64List(b)) => a == b,
93 (Self::Float32List(a), Self::Float32List(b)) => {
96 a.len() == b.len() && a.iter().zip(b).all(|(x, y)| x.to_bits() == y.to_bits())
97 }
98 (Self::Float64List(a), Self::Float64List(b)) => {
99 a.len() == b.len() && a.iter().zip(b).all(|(x, y)| x.to_bits() == y.to_bits())
100 }
101 (Self::StringList(a), Self::StringList(b)) => a == b,
102 (Self::BinaryList(a), Self::BinaryList(b)) => a == b,
103 _ => false,
104 }
105 }
106}
107
108#[derive(Debug, Clone, Copy, PartialEq, Default, Archive, Serialize, Deserialize)]
110pub enum AttrIndexKind {
111 #[default]
113 U16,
114 U32,
116 U64,
118}
119
120#[derive(Debug, Clone, PartialEq, Archive, Serialize, Deserialize)]
126pub enum Attributes {
127 U16(Vec<(u16, u16)>),
129 U32(Vec<(u32, u32)>),
131 U64(Vec<(u64, u64)>),
133}
134
135impl Attributes {
136 pub fn empty(kind: AttrIndexKind) -> Self {
138 match kind {
139 AttrIndexKind::U16 => Self::U16(Vec::new()),
140 AttrIndexKind::U32 => Self::U32(Vec::new()),
141 AttrIndexKind::U64 => Self::U64(Vec::new()),
142 }
143 }
144
145 pub fn get(&self, key_idx: usize) -> Option<usize> {
147 match self {
148 Self::U16(v) => v
149 .binary_search_by_key(&(key_idx as u16), |(k, _)| *k)
150 .ok()
151 .map(|pos| v[pos].1 as usize),
152 Self::U32(v) => v
153 .binary_search_by_key(&(key_idx as u32), |(k, _)| *k)
154 .ok()
155 .map(|pos| v[pos].1 as usize),
156 Self::U64(v) => v
157 .binary_search_by_key(&(key_idx as u64), |(k, _)| *k)
158 .ok()
159 .map(|pos| v[pos].1 as usize),
160 }
161 }
162
163 pub fn upsert(&mut self, key_idx: usize, val_idx: usize) {
165 match self {
166 Self::U16(v) => {
167 let (ki, vi) = (key_idx as u16, val_idx as u16);
168 match v.binary_search_by_key(&ki, |(k, _)| *k) {
169 Ok(pos) => v[pos].1 = vi,
170 Err(pos) => v.insert(pos, (ki, vi)),
171 }
172 }
173 Self::U32(v) => {
174 let (ki, vi) = (key_idx as u32, val_idx as u32);
175 match v.binary_search_by_key(&ki, |(k, _)| *k) {
176 Ok(pos) => v[pos].1 = vi,
177 Err(pos) => v.insert(pos, (ki, vi)),
178 }
179 }
180 Self::U64(v) => {
181 let (ki, vi) = (key_idx as u64, val_idx as u64);
182 match v.binary_search_by_key(&ki, |(k, _)| *k) {
183 Ok(pos) => v[pos].1 = vi,
184 Err(pos) => v.insert(pos, (ki, vi)),
185 }
186 }
187 }
188 }
189
190 pub fn iter_entries(&self) -> Box<dyn Iterator<Item = (usize, usize)> + '_> {
192 match self {
193 Self::U16(v) => Box::new(v.iter().map(|&(k, v)| (k as usize, v as usize))),
194 Self::U32(v) => Box::new(v.iter().map(|&(k, v)| (k as usize, v as usize))),
195 Self::U64(v) => Box::new(v.iter().map(|&(k, v)| (k as usize, v as usize))),
196 }
197 }
198
199 pub fn max_index(&self) -> usize {
201 match self {
202 Self::U16(_) => u16::MAX as usize,
203 Self::U32(_) => u32::MAX as usize,
204 Self::U64(_) => usize::MAX,
205 }
206 }
207}
208
209#[derive(Debug, Clone, PartialEq, Archive, Serialize, Deserialize)]
215pub struct ArrayLayout {
216 pub shape: Vec<u32>,
218 pub dimension_names: Vec<String>,
220 pub storage: StorageLayout,
222}
223
224#[derive(Debug, Clone, PartialEq, Archive, Serialize, Deserialize)]
230pub struct ChunkEntry {
231 pub coord: Vec<u32>,
233 pub address: ChunkAddress,
235}
236
237#[derive(Debug, Clone, PartialEq, Archive, Serialize, Deserialize)]
242pub struct StorageLayout {
243 pub chunk_shape: Vec<u32>,
245 pub chunks: Vec<ChunkEntry>,
250}
251
252#[derive(Debug, Clone, Archive, Serialize, Deserialize)]
258pub enum FillValue {
259 Bool(bool),
261 Int(i64),
263 UInt(u64),
265 Float(f64),
267 String(String),
269 TimestampNs(i64),
272}
273
274impl PartialEq for FillValue {
275 fn eq(&self, other: &Self) -> bool {
276 match (self, other) {
277 (Self::Bool(a), Self::Bool(b)) => a == b,
278 (Self::Int(a), Self::Int(b)) => a == b,
279 (Self::UInt(a), Self::UInt(b)) => a == b,
280 (Self::Float(a), Self::Float(b)) => a.to_bits() == b.to_bits(),
282 (Self::String(a), Self::String(b)) => a == b,
283 (Self::TimestampNs(a), Self::TimestampNs(b)) => a == b,
284 _ => false,
285 }
286 }
287}
288
289#[derive(Debug, Clone, PartialEq, Archive, Serialize, Deserialize)]
294pub struct ArrayMeta {
295 pub name: String,
297 pub dtype: DType,
299 pub layout: ArrayLayout,
301 pub fill_value: Option<FillValue>,
303 pub deleted: bool,
307 pub attributes: Attributes,
313}
314
315impl ArrayLayout {
316 pub fn get_chunk(&self, coord: &[u32]) -> Option<&ChunkAddress> {
318 self.storage
319 .chunks
320 .iter()
321 .find(|e| e.coord.as_slice() == coord)
322 .map(|e| &e.address)
323 }
324
325 pub fn all_addresses(&self) -> Vec<&ChunkAddress> {
327 self.storage.chunks.iter().map(|e| &e.address).collect()
328 }
329}
330
331#[cfg(test)]
332mod tests {
333 use super::*;
334 use crate::address::BlockId;
335
336 fn sample_addr(block: u32, offset: u32, size: u32) -> ChunkAddress {
337 ChunkAddress {
338 block_id: BlockId(block),
339 offset,
340 size,
341 }
342 }
343
344 fn chunk(coord: Vec<u32>, block: u32, offset: u32, size: u32) -> ChunkEntry {
345 ChunkEntry {
346 coord,
347 address: sample_addr(block, offset, size),
348 }
349 }
350
351 #[test]
352 fn attribute_value_binary_and_list_equality() {
353 assert_eq!(
354 AttributeValue::Binary(vec![1, 2, 3]),
355 AttributeValue::Binary(vec![1, 2, 3])
356 );
357 assert_ne!(
358 AttributeValue::Binary(vec![1, 2, 3]),
359 AttributeValue::Binary(vec![1, 2])
360 );
361 assert_eq!(
362 AttributeValue::Int32List(vec![1, 2, 3]),
363 AttributeValue::Int32List(vec![1, 2, 3])
364 );
365 assert_eq!(
366 AttributeValue::StringList(vec!["a".into(), "b".into()]),
367 AttributeValue::StringList(vec!["a".into(), "b".into()])
368 );
369 assert_eq!(
370 AttributeValue::BinaryList(vec![vec![0], vec![1, 2]]),
371 AttributeValue::BinaryList(vec![vec![0], vec![1, 2]])
372 );
373 assert_ne!(
375 AttributeValue::Int32List(vec![1]),
376 AttributeValue::Int64List(vec![1])
377 );
378 }
379
380 #[test]
381 fn attribute_value_float_list_compares_by_bits() {
382 assert_eq!(
385 AttributeValue::Float64List(vec![f64::NAN, 1.0]),
386 AttributeValue::Float64List(vec![f64::NAN, 1.0])
387 );
388 assert_ne!(
390 AttributeValue::Float32List(vec![0.0]),
391 AttributeValue::Float32List(vec![-0.0])
392 );
393 assert_ne!(
394 AttributeValue::Float64List(vec![1.0, 2.0]),
395 AttributeValue::Float64List(vec![1.0])
396 );
397 }
398
399 #[test]
400 fn flat_layout_addresses() {
401 let layout = ArrayLayout {
402 shape: vec![100],
403 dimension_names: vec!["x".into()],
404 storage: StorageLayout {
405 chunk_shape: vec![100],
406 chunks: vec![chunk(vec![0], 0, 0, 400)],
407 },
408 };
409 assert_eq!(layout.all_addresses().len(), 1);
410 assert!(layout.get_chunk(&[0]).is_some());
411 assert!(layout.get_chunk(&[1]).is_none());
412 }
413
414 #[test]
415 fn chunked_layout_lookup() {
416 let layout = ArrayLayout {
417 shape: vec![128, 128],
418 dimension_names: vec!["x".into(), "y".into()],
419 storage: StorageLayout {
420 chunk_shape: vec![64, 64],
421 chunks: vec![
422 chunk(vec![0, 0], 3, 0, 1000),
423 chunk(vec![0, 1], 7, 2000, 1000),
424 ],
425 },
426 };
427 let addr = layout.get_chunk(&[0, 1]).unwrap();
428 assert_eq!(addr.block_id, BlockId(7));
429 assert_eq!(addr.offset, 2000);
430
431 assert!(layout.get_chunk(&[1, 0]).is_none());
432 }
433
434 #[test]
435 fn chunked_all_addresses() {
436 let layout = ArrayLayout {
437 shape: vec![30],
438 dimension_names: vec!["t".into()],
439 storage: StorageLayout {
440 chunk_shape: vec![10],
441 chunks: vec![
442 chunk(vec![0], 0, 0, 500),
443 chunk(vec![1], 0, 500, 500),
444 chunk(vec![2], 1, 0, 500),
445 ],
446 },
447 };
448 assert_eq!(layout.all_addresses().len(), 3);
449 }
450}