1use std::fmt::{self, Display};
2use std::mem;
3use std::os::raw::c_void;
4
5use crate::array::VarLenArray;
6use crate::references::Reference;
7use crate::string::{FixedAscii, FixedUnicode, VarLenAscii, VarLenUnicode};
8
9#[allow(non_camel_case_types)]
10#[repr(C)]
11#[derive(Copy, Clone)]
12pub(crate) struct hvl_t {
13 pub len: usize,
14 pub ptr: *mut c_void,
15}
16
17#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)]
18pub enum IntSize {
19 U1 = 1,
20 U2 = 2,
21 U4 = 4,
22 U8 = 8,
23}
24
25impl IntSize {
26 pub const fn from_int(size: usize) -> Option<Self> {
27 if size == 1 {
28 Some(Self::U1)
29 } else if size == 2 {
30 Some(Self::U2)
31 } else if size == 4 {
32 Some(Self::U4)
33 } else if size == 8 {
34 Some(Self::U8)
35 } else {
36 None
37 }
38 }
39}
40
41#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)]
42pub enum FloatSize {
43 #[cfg(feature = "f16")]
44 U2 = 2,
45 U4 = 4,
46 U8 = 8,
47}
48
49impl FloatSize {
50 pub const fn from_int(size: usize) -> Option<Self> {
51 #[cfg(feature = "f16")]
52 {
53 if size == 2 {
54 return Some(Self::U2);
55 }
56 }
57 match size {
58 4 => Some(Self::U4),
59 8 => Some(Self::U8),
60 _ => None,
61 }
62 }
63}
64
65#[derive(Clone, Debug, PartialEq, Eq)]
66pub struct EnumMember {
67 pub name: String,
68 pub value: u64,
69}
70
71#[derive(Clone, Debug, PartialEq, Eq)]
72pub struct EnumType {
73 pub size: IntSize,
74 pub signed: bool,
75 pub members: Vec<EnumMember>,
76}
77
78impl EnumType {
79 #[inline]
80 pub fn base_type(&self) -> TypeDescriptor {
81 if self.signed {
82 TypeDescriptor::Integer(self.size)
83 } else {
84 TypeDescriptor::Unsigned(self.size)
85 }
86 }
87}
88
89#[derive(Clone, Debug, PartialEq, Eq)]
90pub struct CompoundField {
91 pub name: String,
92 pub ty: TypeDescriptor,
93 pub offset: usize,
94 pub index: usize,
95}
96
97impl CompoundField {
98 pub fn new(name: &str, ty: TypeDescriptor, offset: usize, index: usize) -> Self {
99 Self { name: name.to_owned(), ty, offset, index }
100 }
101
102 pub fn typed<T: H5Type>(name: &str, offset: usize, index: usize) -> Self {
103 Self::new(name, T::type_descriptor(), offset, index)
104 }
105}
106
107#[derive(Clone, Debug, PartialEq, Eq)]
108pub struct CompoundType {
109 pub fields: Vec<CompoundField>,
110 pub size: usize,
111}
112
113impl CompoundType {
114 pub fn to_c_repr(&self) -> Self {
115 let mut layout = self.clone();
116 layout.fields.sort_by_key(|f| f.index);
117 let mut offset = 0;
118 let mut max_align = 1;
119 for f in &mut layout.fields {
120 f.ty = f.ty.to_c_repr();
121 let align = f.ty.c_alignment();
122 while offset % align != 0 {
123 offset += 1;
124 }
125 f.offset = offset;
126 max_align = max_align.max(align);
127 offset += f.ty.size();
128 layout.size = offset;
129 while layout.size % max_align != 0 {
130 layout.size += 1;
131 }
132 }
133 layout
134 }
135
136 pub fn to_packed_repr(&self) -> Self {
137 let mut layout = self.clone();
138 layout.fields.sort_by_key(|f| f.index);
139 layout.size = 0;
140 for f in &mut layout.fields {
141 f.ty = f.ty.to_packed_repr();
142 f.offset = layout.size;
143 layout.size += f.ty.size();
144 }
145 layout
146 }
147}
148
149#[derive(Clone, Debug, PartialEq, Eq)]
150pub enum TypeDescriptor {
151 Integer(IntSize),
152 Unsigned(IntSize),
153 Float(FloatSize),
154 Boolean,
155 Enum(EnumType),
156 Compound(CompoundType),
157 FixedArray(Box<Self>, usize),
158 FixedAscii(usize),
159 FixedUnicode(usize),
160 VarLenArray(Box<Self>),
161 VarLenAscii,
162 VarLenUnicode,
163 Reference(Reference),
164}
165
166impl Display for TypeDescriptor {
167 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
168 match self {
169 TypeDescriptor::Integer(IntSize::U1) => write!(f, "int8"),
170 TypeDescriptor::Integer(IntSize::U2) => write!(f, "int16"),
171 TypeDescriptor::Integer(IntSize::U4) => write!(f, "int32"),
172 TypeDescriptor::Integer(IntSize::U8) => write!(f, "int64"),
173 TypeDescriptor::Unsigned(IntSize::U1) => write!(f, "uint8"),
174 TypeDescriptor::Unsigned(IntSize::U2) => write!(f, "uint16"),
175 TypeDescriptor::Unsigned(IntSize::U4) => write!(f, "uint32"),
176 TypeDescriptor::Unsigned(IntSize::U8) => write!(f, "uint64"),
177 #[cfg(feature = "f16")]
178 TypeDescriptor::Float(FloatSize::U2) => write!(f, "float16"),
179 TypeDescriptor::Float(FloatSize::U4) => write!(f, "float32"),
180 TypeDescriptor::Float(FloatSize::U8) => write!(f, "float64"),
181 TypeDescriptor::Boolean => write!(f, "bool"),
182 TypeDescriptor::Enum(ref tp) => write!(f, "enum ({})", tp.base_type()),
183 TypeDescriptor::Compound(ref tp) => write!(f, "compound ({} fields)", tp.fields.len()),
184 TypeDescriptor::FixedArray(ref tp, n) => write!(f, "[{tp}; {n}]"),
185 TypeDescriptor::FixedAscii(n) => write!(f, "string (len {n})"),
186 TypeDescriptor::FixedUnicode(n) => write!(f, "unicode (len {n})"),
187 TypeDescriptor::VarLenArray(ref tp) => write!(f, "[{tp}] (var len)"),
188 TypeDescriptor::VarLenAscii => write!(f, "string (var len)"),
189 TypeDescriptor::VarLenUnicode => write!(f, "unicode (var len)"),
190 TypeDescriptor::Reference(Reference::Object) => write!(f, "reference (object)"),
191 TypeDescriptor::Reference(Reference::Region) => write!(f, "reference (region)"),
192 #[cfg(feature = "1.12.0")]
193 TypeDescriptor::Reference(Reference::Std) => write!(f, "reference"),
194 }
195 }
196}
197
198impl TypeDescriptor {
199 pub fn size(&self) -> usize {
201 match *self {
202 Self::Integer(size) | Self::Unsigned(size) => size as _,
203 Self::Float(size) => size as _,
204 Self::Boolean => 1,
205 Self::Enum(ref enum_type) => enum_type.size as _,
206 Self::Compound(ref compound) => compound.size,
207 Self::FixedArray(ref ty, len) => ty.size() * len,
208 Self::FixedAscii(len) | Self::FixedUnicode(len) => len,
209 Self::VarLenArray(_) => mem::size_of::<hvl_t>(),
210 Self::VarLenAscii | Self::VarLenUnicode => mem::size_of::<*const u8>(),
211 Self::Reference(reftyp) => reftyp.size(),
212 }
213 }
214
215 fn c_alignment(&self) -> usize {
216 match *self {
217 Self::Compound(ref compound) => {
218 compound.fields.iter().map(|f| f.ty.c_alignment()).max().unwrap_or(1)
219 }
220 Self::FixedArray(ref ty, _) => ty.c_alignment(),
221 Self::FixedAscii(_) | Self::FixedUnicode(_) => 1,
222 Self::VarLenArray(_) => mem::size_of::<usize>(),
223 _ => self.size(),
224 }
225 }
226
227 pub fn to_c_repr(&self) -> Self {
228 match *self {
229 Self::Compound(ref compound) => Self::Compound(compound.to_c_repr()),
230 Self::FixedArray(ref ty, size) => Self::FixedArray(Box::new(ty.to_c_repr()), size),
231 Self::VarLenArray(ref ty) => Self::VarLenArray(Box::new(ty.to_c_repr())),
232 _ => self.clone(),
233 }
234 }
235
236 pub fn to_packed_repr(&self) -> Self {
237 match *self {
238 Self::Compound(ref compound) => Self::Compound(compound.to_packed_repr()),
239 Self::FixedArray(ref ty, size) => Self::FixedArray(Box::new(ty.to_packed_repr()), size),
240 Self::VarLenArray(ref ty) => Self::VarLenArray(Box::new(ty.to_packed_repr())),
241 _ => self.clone(),
242 }
243 }
244}
245
246pub unsafe trait H5Type: 'static {
247 fn type_descriptor() -> TypeDescriptor;
248}
249
250macro_rules! impl_h5type {
251 ($ty:ty, $variant:ident, $size:expr) => {
252 unsafe impl H5Type for $ty {
253 #[inline]
254 fn type_descriptor() -> TypeDescriptor {
255 $crate::h5type::TypeDescriptor::$variant($size)
256 }
257 }
258 };
259}
260
261impl_h5type!(i8, Integer, IntSize::U1);
262impl_h5type!(i16, Integer, IntSize::U2);
263impl_h5type!(i32, Integer, IntSize::U4);
264impl_h5type!(i64, Integer, IntSize::U8);
265impl_h5type!(u8, Unsigned, IntSize::U1);
266impl_h5type!(u16, Unsigned, IntSize::U2);
267impl_h5type!(u32, Unsigned, IntSize::U4);
268impl_h5type!(u64, Unsigned, IntSize::U8);
269#[cfg(feature = "f16")]
270impl_h5type!(::half::f16, Float, FloatSize::U2);
271impl_h5type!(f32, Float, FloatSize::U4);
272impl_h5type!(f64, Float, FloatSize::U8);
273
274#[cfg(target_pointer_width = "32")]
275impl_h5type!(isize, Integer, IntSize::U4);
276#[cfg(target_pointer_width = "32")]
277impl_h5type!(usize, Unsigned, IntSize::U4);
278
279#[cfg(target_pointer_width = "64")]
280impl_h5type!(isize, Integer, IntSize::U8);
281#[cfg(target_pointer_width = "64")]
282impl_h5type!(usize, Unsigned, IntSize::U8);
283
284unsafe impl H5Type for bool {
285 #[inline]
286 fn type_descriptor() -> TypeDescriptor {
287 TypeDescriptor::Boolean
288 }
289}
290
291unsafe impl<T: H5Type, const N: usize> H5Type for [T; N] {
344 #[inline]
345 fn type_descriptor() -> TypeDescriptor {
346 TypeDescriptor::FixedArray(Box::new(<T as H5Type>::type_descriptor()), N)
347 }
348}
349
350unsafe impl<T: H5Type + Copy> H5Type for VarLenArray<T> {
351 #[inline]
352 fn type_descriptor() -> TypeDescriptor {
353 TypeDescriptor::VarLenArray(Box::new(<T as H5Type>::type_descriptor()))
354 }
355}
356
357unsafe impl<const N: usize> H5Type for FixedAscii<N> {
358 #[inline]
359 fn type_descriptor() -> TypeDescriptor {
360 TypeDescriptor::FixedAscii(N)
361 }
362}
363
364unsafe impl<const N: usize> H5Type for FixedUnicode<N> {
365 #[inline]
366 fn type_descriptor() -> TypeDescriptor {
367 TypeDescriptor::FixedUnicode(N)
368 }
369}
370
371unsafe impl H5Type for VarLenAscii {
372 #[inline]
373 fn type_descriptor() -> TypeDescriptor {
374 TypeDescriptor::VarLenAscii
375 }
376}
377
378unsafe impl H5Type for VarLenUnicode {
379 #[inline]
380 fn type_descriptor() -> TypeDescriptor {
381 TypeDescriptor::VarLenUnicode
382 }
383}
384
385#[cfg(test)]
386pub mod tests {
387 use super::TypeDescriptor as TD;
388 use super::{hvl_t, FloatSize, H5Type, IntSize};
389 use crate::array::VarLenArray;
390 use crate::string::{FixedAscii, FixedUnicode, VarLenAscii, VarLenUnicode};
391 use std::mem;
392
393 #[test]
394 pub fn test_scalar_types() {
395 assert_eq!(bool::type_descriptor(), TD::Boolean);
396 assert_eq!(i8::type_descriptor(), TD::Integer(IntSize::U1));
397 assert_eq!(i16::type_descriptor(), TD::Integer(IntSize::U2));
398 assert_eq!(i32::type_descriptor(), TD::Integer(IntSize::U4));
399 assert_eq!(i64::type_descriptor(), TD::Integer(IntSize::U8));
400 assert_eq!(u8::type_descriptor(), TD::Unsigned(IntSize::U1));
401 assert_eq!(u16::type_descriptor(), TD::Unsigned(IntSize::U2));
402 assert_eq!(u32::type_descriptor(), TD::Unsigned(IntSize::U4));
403 assert_eq!(u64::type_descriptor(), TD::Unsigned(IntSize::U8));
404 assert_eq!(f32::type_descriptor(), TD::Float(FloatSize::U4));
405 assert_eq!(f64::type_descriptor(), TD::Float(FloatSize::U8));
406
407 assert_eq!(bool::type_descriptor().size(), 1);
408 assert_eq!(i16::type_descriptor().size(), 2);
409 assert_eq!(u32::type_descriptor().size(), 4);
410 assert_eq!(f64::type_descriptor().size(), 8);
411 }
412
413 #[test]
414 #[cfg(target_pointer_width = "32")]
415 pub fn test_ptr_sized_ints() {
416 assert_eq!(isize::type_descriptor(), TD::Integer(IntSize::U4));
417 assert_eq!(usize::type_descriptor(), TD::Unsigned(IntSize::U4));
418
419 assert_eq!(usize::type_descriptor().size(), 4);
420 }
421
422 #[test]
423 #[cfg(target_pointer_width = "64")]
424 pub fn test_ptr_sized_ints() {
425 assert_eq!(isize::type_descriptor(), TD::Integer(IntSize::U8));
426 assert_eq!(usize::type_descriptor(), TD::Unsigned(IntSize::U8));
427
428 assert_eq!(usize::type_descriptor().size(), 8);
429 }
430
431 #[test]
432 pub fn test_fixed_array() {
433 type S = [T; 4];
434 type T = [u32; 256];
435 assert_eq!(T::type_descriptor(), TD::FixedArray(Box::new(TD::Unsigned(IntSize::U4)), 256));
436 assert_eq!(S::type_descriptor(), TD::FixedArray(Box::new(T::type_descriptor()), 4));
437 }
438
439 #[test]
440 pub fn test_varlen_array() {
441 type S = VarLenArray<u16>;
442 assert_eq!(S::type_descriptor(), TD::VarLenArray(Box::new(u16::type_descriptor())));
443 assert_eq!(mem::size_of::<VarLenArray<u8>>(), mem::size_of::<hvl_t>());
444 }
445
446 #[test]
447 pub fn test_string_types() {
448 type FA = FixedAscii<16>;
449 type FU = FixedUnicode<32>;
450 assert_eq!(FA::type_descriptor(), TD::FixedAscii(16));
451 assert_eq!(FU::type_descriptor(), TD::FixedUnicode(32));
452 assert_eq!(VarLenAscii::type_descriptor(), TD::VarLenAscii);
453 assert_eq!(VarLenUnicode::type_descriptor(), TD::VarLenUnicode);
454 }
455
456 }