1pub use ndarray::ArrayD;
2use ndarray::IxDyn;
3use std::io::{Read, Seek};
4
5#[derive(Debug, Default, Clone, PartialEq)]
6pub enum IdxData {
7 #[default]
8 None,
9 UnsignedByte(u8),
10 SignedByte(i8),
11 Short(i16),
12 Int(i32),
13 Float(f32),
14 Double(f64),
15}
16
17impl std::ops::Add for IdxData {
18 type Output = Self;
19
20 fn add(self, rhs: Self) -> Self::Output {
21 if self != rhs {
22 return Self::None;
23 }
24 match self {
25 Self::None => Self::None,
26 Self::UnsignedByte(val1) => {
27 if let Self::UnsignedByte(val2) = rhs {
28 Self::UnsignedByte(val1 + val2)
29 } else {
30 unreachable!();
31 }
32 }
33 Self::SignedByte(val1) => {
34 if let Self::SignedByte(val2) = rhs {
35 Self::SignedByte(val1 + val2)
36 } else {
37 unreachable!();
38 }
39 }
40 Self::Short(val1) => {
41 if let Self::Short(val2) = rhs {
42 Self::Short(val1 + val2)
43 } else {
44 unreachable!();
45 }
46 }
47 Self::Int(val1) => {
48 if let Self::Int(val2) = rhs {
49 Self::Int(val1 + val2)
50 } else {
51 unreachable!();
52 }
53 }
54 Self::Float(val1) => {
55 if let Self::Float(val2) = rhs {
56 Self::Float(val1 + val2)
57 } else {
58 unreachable!();
59 }
60 }
61 Self::Double(val1) => {
62 if let Self::Double(val2) = rhs {
63 Self::Double(val1 + val2)
64 } else {
65 unreachable!();
66 }
67 }
68 }
69 }
70}
71
72impl num_traits::identities::Zero for IdxData {
73 fn zero() -> Self {
74 Self::None
75 }
76
77 fn is_zero(&self) -> bool {
78 self == &Self::None
79 }
80}
81
82#[derive(Debug)]
83enum IdxType {
84 UnsignedByte,
85 SignedByte,
86 Short,
87 Int,
88 Float,
89 Double,
90}
91
92#[derive(Debug, Clone)]
93struct IdxError;
94
95impl std::fmt::Display for IdxError {
96 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
97 write!(f, "Error")
98 }
99}
100
101impl std::error::Error for IdxError {}
102
103fn recurser(
104 idx_source: &mut (impl Read + Seek),
105 data: &mut ArrayD<IdxData>,
106 dimension_sizes: &[usize],
107 data_type: &IdxType,
108 past_idxes: &mut Vec<usize>,
109) -> Result<(), Box<dyn std::error::Error>> {
110 let current_idx = past_idxes.len();
111 if current_idx == dimension_sizes.len() {
113 match data_type {
115 IdxType::UnsignedByte => {
116 let mut buf = [0u8; 1];
117 idx_source.read_exact(&mut buf)?;
118 data[&past_idxes[..]] = IdxData::UnsignedByte(u8::from_be_bytes(buf));
119 }
120 IdxType::SignedByte => {
121 let mut buf = [0u8; 1];
122 idx_source.read_exact(&mut buf)?;
123 data[&past_idxes[..]] = IdxData::SignedByte(i8::from_be_bytes(buf));
124 }
125 IdxType::Short => {
126 let mut buf = [0u8; 2];
127 idx_source.read_exact(&mut buf)?;
128 data[&past_idxes[..]] = IdxData::Short(i16::from_be_bytes(buf));
129 }
130 IdxType::Int => {
131 let mut buf = [0u8; 4];
132 idx_source.read_exact(&mut buf)?;
133 data[&past_idxes[..]] = IdxData::Int(i32::from_be_bytes(buf));
134 }
135 IdxType::Float => {
136 let mut buf = [0u8; 4];
137 idx_source.read_exact(&mut buf)?;
138 data[&past_idxes[..]] = IdxData::Float(f32::from_be_bytes(buf));
139 }
140 IdxType::Double => {
141 let mut buf = [0u8; 8];
142 idx_source.read_exact(&mut buf)?;
143 data[&past_idxes[..]] = IdxData::Double(f64::from_be_bytes(buf));
144 }
145 }
146 Ok(())
147 } else {
148 let my_idx = past_idxes.len();
149 past_idxes.push(0);
150 for i in 0..dimension_sizes[current_idx] {
152 past_idxes[my_idx] = i;
153 recurser(idx_source, data, dimension_sizes, data_type, past_idxes)?;
154 }
155 past_idxes.pop();
157 Ok(())
158 }
159}
160
161fn process_dimensions(
162 idx_source: &mut (impl Read + Seek),
163 data: &mut ArrayD<IdxData>,
164 dimension_sizes: &[usize],
165 data_type: &IdxType,
166) -> Result<(), Box<dyn std::error::Error>> {
167 recurser(idx_source, data, dimension_sizes, data_type, &mut vec![])
168}
169
170pub fn read_idx(
171 idx_source: &mut (impl Read + Seek),
172) -> Result<ArrayD<IdxData>, Box<dyn std::error::Error>> {
173 idx_source.seek_relative(2)?;
175
176 let mut data_type_buf = [0u8; 1];
178 let mut dimension_count_buf = [0u8; 1];
179
180 idx_source.read_exact(&mut data_type_buf)?;
181 idx_source.read_exact(&mut dimension_count_buf)?;
182
183 let data_type = match u8::from_be_bytes(data_type_buf) {
184 0x08u8 => IdxType::UnsignedByte,
185 0x09u8 => IdxType::SignedByte,
186 0x0Bu8 => IdxType::Short,
187 0x0Cu8 => IdxType::Int,
188 0x0Du8 => IdxType::Float,
189 0x0Eu8 => IdxType::Double,
190 _ => return Err(IdxError.into()),
191 };
192 let dimension_count = u8::from_be_bytes(dimension_count_buf);
193
194 let mut dimension_sizes = Vec::with_capacity(dimension_count as usize);
195
196 for _ in 0..dimension_count {
197 let mut dimension_size_buf = [0u8; 4];
198 idx_source.read_exact(&mut dimension_size_buf)?;
199 dimension_sizes.push(i32::from_be_bytes(dimension_size_buf) as usize);
200 }
201
202 let mut data: ArrayD<IdxData> = ArrayD::zeros(IxDyn(&dimension_sizes));
205
206 process_dimensions(idx_source, &mut data, &dimension_sizes, &data_type)?;
207
208 Ok(data)
209}