Skip to content

Commit 268cd29

Browse files
authored
Merge pull request aldanor#203 from ajtribick/field-renaming
Add hdf5 helper attribute with rename functionality
2 parents 27a59c2 + 2559e0a commit 268cd29

File tree

5 files changed

+151
-21
lines changed

5 files changed

+151
-21
lines changed

CHANGELOG.md

Lines changed: 14 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
### Added
66

77
- Support for HDF5 version 1.13.0.
8+
- Support field renaming via `#[hdf5(rename = "new_name")]` helper attribute.
89

910
### Changed
1011

@@ -25,7 +26,7 @@ Release date: Nov 21, 2021.
2526
extents (like tuples of integers) where `impl TryInto<Extents>` is required.
2627
- Support for HDF5 versions 1.12.1 and 1.10.8.
2728
- `#[derive(H5Type)]` now supports structs / tuple structs with `repr(packed)`.
28-
- `#[derive(H5Type)]` now supports structs / tuple structs with
29+
- `#[derive(H5Type)]` now supports structs / tuple structs with
2930
`repr(transparent)` (the generated HDF5 type is equivalent to the type of
3031
the field and is not compound).
3132

@@ -93,7 +94,7 @@ Release date: Oct 23, 2021.
9394
memchecker option enabled. This option is force-enabled by default if using
9495
a dll version of the HDF5 library on Windows.
9596
- Added new `DynValue` type which represents a dynamic self-describing HDF5
96-
object that also knows how to deallocate itself. It supports all the HDF5
97+
object that also knows how to deallocate itself. It supports all the HDF5
9798
types including compound types, strings and arrays.
9899
- Added support for attributes and a new `Attribute` object type. The attribute
99100
API uses the new dataset API with some restrictions imposed by HDF5 library
@@ -113,7 +114,7 @@ Release date: Oct 23, 2021.
113114
- `get_all_of_type`: find all objects in a group of a given type.
114115
- Shortcut methods for finding all objects in a group of a given type:
115116
`datasets`, `groups`, `named_datatypes`, `link_external`.
116-
- Added to `Handle`:
117+
- Added to `Handle`:
117118
- `id_type`: get native HDF5 object type.
118119
- `try_borrow`: instantiate a handle but don't take ownership of the object.
119120
- `Handle` now implements `Debug`.
@@ -169,7 +170,7 @@ Release date: Oct 23, 2021.
169170
### Fixed
170171

171172
- A potential memory leak of identifier handles has been identified and fixed.
172-
- A potential race condition occurring in multi-thread library initialisation
173+
- A potential race condition occurring in multi-thread library initialisation
173174
has been identified and fixed.
174175

175176
### Removed
@@ -189,7 +190,7 @@ Release date: Jan 27, 2021.
189190

190191
### Changed
191192

192-
- Dependencies are bumped to the newest major versions; `ndarray` users may
193+
- Dependencies are bumped to the newest major versions; `ndarray` users may
193194
now use both version `0.13` and version `0.14`.
194195

195196
### Fixed
@@ -207,8 +208,8 @@ Release date: Aug 9, 2020.
207208
via `hdf5-sys/static` feature (as of this release, the version of the bundled
208209
sources of HDF5 is 1.10.6). CMake is required for building. For further
209210
details, see the docs for `hdf5-sys`.
210-
- Thanks to static build option, the documentation will now be built on
211-
[docs.rs](https://docs.rs/crate/hdf5); if it builds successfully, this
211+
- Thanks to static build option, the documentation will now be built on
212+
[docs.rs](https://docs.rs/crate/hdf5); if it builds successfully, this
212213
will be the official documentation source from now on.
213214
- Add support for HDF5 1.12 on all platforms and include it in CI.
214215

@@ -227,8 +228,8 @@ Release date: Aug 9, 2020.
227228
- We now force the variable-length allocator that HDF5 uses when reading data
228229
to use `libc::malloc` and `libc::free`, so that they can be deallocated
229230
properly by `VarLenString` and `VarLenArray` in `hdf5-types`. Previously,
230-
this could cause a rare but serious failure for Windows builds when the
231-
default allocator used for vlen types by HDF5 was not matching the
231+
this could cause a rare but serious failure for Windows builds when the
232+
default allocator used for vlen types by HDF5 was not matching the
232233
libc deallocator.
233234
- Use `std::panic::catch_unwind` in all cases where we use extern C callbacks,
234235
so that they are panic-safe.
@@ -404,7 +405,7 @@ Release date: Mar 8, 2019.
404405
`Deref`-based hierarchy instead (53eff4f). `ID` and `FromID` traits have been
405406
removed. Traits like `Location`, `Object` and a few others have been replaced
406407
with real types (wrappers around HDF5 handles, same as the concrete types
407-
like `File`). Subtypes then dereference into parent types, so the user can
408+
like `File`). Subtypes then dereference into parent types, so the user can
408409
call methods of the parent type without having to import any traits into
409410
scope (for instance, `File` dereferences into `Group`, which dereferences
410411
into `Location`, which dereferences into `Object`).
@@ -441,11 +442,11 @@ Release date: Jul 29, 2015.
441442
### Added
442443

443444
- Full support of `msvc` target on Windows. CI tests on AppVeyor now use
444-
official releases of HDF5 binaries (1.8.16, VS2015, x86_x64). The `gnu`
445+
official releases of HDF5 binaries (1.8.16, VS2015, x86_x64). The `gnu`
445446
target are still unofficially supported but won't be tested.
446447
- If `HDF5_LIBDIR` is not specified when building on Windows and `PATH`
447448
contains what looks like the `bin` folder of HDF5 installation, the library
448-
directory will be inferred automatically. The official HDF5 installers add
449+
directory will be inferred automatically. The official HDF5 installers add
449450
the `bin` folder to user path, so the official MSVC releases should just work
450451
out of the box without having to set any environment variables.
451452
- The library is now split into three crates: `hdf5-lib` (requests linkage to
@@ -475,7 +476,7 @@ Release date: Jul 29, 2015.
475476

476477
### Fixed
477478

478-
- Fixed dangling pointer problems when strings were passed as pointers to
479+
- Fixed dangling pointer problems when strings were passed as pointers to
479480
the C API.
480481
- Fixed target path not being passed correctly in `Container::link_soft`.
481482

hdf5-derive/src/lib.rs

Lines changed: 39 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,11 @@ use proc_macro2::{Ident, Span, TokenStream};
88
use proc_macro_error::{abort, proc_macro_error};
99
use quote::{quote, ToTokens};
1010
use syn::{
11-
parse_macro_input, AttrStyle, Attribute, Data, DeriveInput, Expr, Fields, Index, Meta,
11+
parse_macro_input, AttrStyle, Attribute, Data, DeriveInput, Expr, Fields, Index, Lit, Meta,
1212
NestedMeta, Type, TypeGenerics, TypePath,
1313
};
1414

15-
#[proc_macro_derive(H5Type)]
15+
#[proc_macro_derive(H5Type, attributes(hdf5))]
1616
#[proc_macro_error]
1717
pub fn derive(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
1818
let input = parse_macro_input!(input as DeriveInput);
@@ -67,7 +67,7 @@ fn impl_transparent(ty: &Type) -> TokenStream {
6767
}
6868
}
6969

70-
fn impl_enum(names: &[Ident], values: &[Expr], repr: &Ident) -> TokenStream {
70+
fn impl_enum(names: &[String], values: &[Expr], repr: &Ident) -> TokenStream {
7171
let size = Ident::new(
7272
&format!(
7373
"U{}",
@@ -84,7 +84,7 @@ fn impl_enum(names: &[Ident], values: &[Expr], repr: &Ident) -> TokenStream {
8484
signed: #signed,
8585
members: vec![#(
8686
_h5::types::EnumMember {
87-
name: stringify!(#names).to_owned(),
87+
name: #names.to_owned(),
8888
value: (#values) as #repr as _,
8989
}
9090
),*],
@@ -132,6 +132,28 @@ fn find_repr(attrs: &[Attribute], expected: &[&str]) -> Option<Ident> {
132132
None
133133
}
134134

135+
fn find_hdf5_rename(attrs: &[Attribute]) -> Option<String> {
136+
if let Some(attr) = attrs.iter().find(|a| a.path.is_ident("hdf5")) {
137+
if let Ok(Meta::List(meta_list)) = attr.parse_meta() {
138+
let rename_literal = meta_list.nested.iter().find_map(|n| {
139+
if let NestedMeta::Meta(Meta::NameValue(name_value)) = n {
140+
if name_value.path.is_ident("rename") {
141+
return Some(&name_value.lit);
142+
}
143+
}
144+
145+
None
146+
});
147+
148+
if let Some(Lit::Str(renamed)) = rename_literal {
149+
return Some(renamed.value());
150+
}
151+
}
152+
}
153+
154+
None
155+
}
156+
135157
fn pluck<'a, I, F, T, S>(iter: I, func: F) -> Vec<S>
136158
where
137159
I: Iterator<Item = &'a T>,
@@ -166,8 +188,11 @@ fn impl_trait(
166188
impl_transparent(&fields[0].ty)
167189
} else {
168190
let types = pluck(fields.iter(), |f| f.ty.clone());
191+
let names = pluck(fields.iter(), |f| {
192+
find_hdf5_rename(&f.attrs)
193+
.unwrap_or_else(|| f.ident.as_ref().unwrap().to_string())
194+
});
169195
let fields = pluck(fields.iter(), |f| f.ident.clone().unwrap());
170-
let names = fields.iter().map(ToString::to_string).collect::<Vec<_>>();
171196
impl_compound(ty, ty_generics, &fields, &names, &types)
172197
}
173198
}
@@ -191,7 +216,11 @@ fn impl_trait(
191216
assert_eq!(fields.len(), 1);
192217
impl_transparent(&fields[0].ty)
193218
} else {
194-
let names = (0..fields.len()).map(|f| f.to_string()).collect::<Vec<_>>();
219+
let names = fields
220+
.iter()
221+
.enumerate()
222+
.map(|(n, f)| find_hdf5_rename(&f.attrs).unwrap_or_else(|| n.to_string()))
223+
.collect::<Vec<_>>();
195224
let types = pluck(fields.iter(), |f| f.ty.clone());
196225
impl_compound(ty, ty_generics, &index, &names, &types)
197226
}
@@ -213,7 +242,10 @@ fn impl_trait(
213242
let repr = find_repr(attrs, enum_reprs).unwrap_or_else(|| {
214243
abort!(ty, "`H5Type` can only be derived for enums with explicit representation")
215244
});
216-
let names = pluck(variants.iter(), |v| v.ident.clone());
245+
let names = variants
246+
.iter()
247+
.map(|v| find_hdf5_rename(&v.attrs).unwrap_or_else(|| v.ident.to_string()))
248+
.collect::<Vec<_>>();
217249
let values = pluck(variants.iter(), |v| v.discriminant.clone().unwrap().1);
218250
impl_enum(&names, &values, &repr)
219251
}

tests/common/gen.rs

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -230,3 +230,42 @@ impl Gen for VarLenStruct {
230230
VarLenStruct { va: Gen::gen(rng), vu: Gen::gen(rng), vla: Gen::gen(rng) }
231231
}
232232
}
233+
234+
#[derive(H5Type, Clone, Debug, PartialEq)]
235+
#[repr(C)]
236+
pub struct RenameStruct {
237+
first: i32,
238+
#[hdf5(rename = "field.second")]
239+
second: i64,
240+
}
241+
242+
impl Gen for RenameStruct {
243+
fn gen<R: Rng + ?Sized>(rng: &mut R) -> Self {
244+
RenameStruct { first: Gen::gen(rng), second: Gen::gen(rng) }
245+
}
246+
}
247+
248+
#[derive(H5Type, Clone, Copy, Debug, PartialEq)]
249+
#[repr(C)]
250+
pub struct RenameTupleStruct(#[hdf5(rename = "my_boolean")] bool, #[hdf5(rename = "my_enum")] Enum);
251+
252+
impl Gen for RenameTupleStruct {
253+
fn gen<R: Rng + ?Sized>(rng: &mut R) -> Self {
254+
RenameTupleStruct(Gen::gen(rng), Gen::gen(rng))
255+
}
256+
}
257+
258+
#[derive(H5Type, Clone, Copy, Debug, PartialEq)]
259+
#[repr(i16)]
260+
pub enum RenameEnum {
261+
#[hdf5(rename = "coord.x")]
262+
X = -2,
263+
#[hdf5(rename = "coord.y")]
264+
Y = 3,
265+
}
266+
267+
impl Gen for RenameEnum {
268+
fn gen<R: Rng + ?Sized>(rng: &mut R) -> Self {
269+
*[RenameEnum::X, RenameEnum::Y].choose(rng).unwrap()
270+
}
271+
}

tests/test_dataset.rs

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,10 @@ use hdf5_types::TypeDescriptor;
88

99
mod common;
1010

11-
use self::common::gen::{gen_arr, gen_slice, Enum, FixedStruct, Gen, TupleStruct, VarLenStruct};
11+
use self::common::gen::{
12+
gen_arr, gen_slice, Enum, FixedStruct, Gen, RenameEnum, RenameStruct, RenameTupleStruct,
13+
TupleStruct, VarLenStruct,
14+
};
1215
use self::common::util::new_in_memory_file;
1316

1417
fn test_write_slice<T, R>(
@@ -267,3 +270,11 @@ fn test_create_on_databuilder() {
267270
let _ds = file.new_dataset::<i32>().create("ds3").unwrap();
268271
let _ds = file.new_dataset::<i32>().shape(2).create("ds4").unwrap();
269272
}
273+
274+
#[test]
275+
fn test_read_write_rename_fields() -> hdf5::Result<()> {
276+
test_read_write::<RenameStruct>()?;
277+
test_read_write::<RenameTupleStruct>()?;
278+
test_read_write::<RenameEnum>()?;
279+
Ok(())
280+
}

tests/test_datatypes.rs

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,24 @@ pub fn test_datatype_roundtrip() {
5353
});
5454
check_roundtrip!(X, x_desc);
5555

56+
#[allow(dead_code)]
57+
#[derive(H5Type)]
58+
#[repr(i64)]
59+
enum Y {
60+
#[hdf5(rename = "variant.a")]
61+
A = 1,
62+
B = -2,
63+
}
64+
let y_desc = TD::Enum(EnumType {
65+
size: IntSize::U8,
66+
signed: true,
67+
members: vec![
68+
EnumMember { name: "variant.a".into(), value: 1 },
69+
EnumMember { name: "B".into(), value: -2i64 as _ },
70+
],
71+
});
72+
check_roundtrip!(Y, y_desc);
73+
5674
#[derive(H5Type)]
5775
#[repr(C)]
5876
struct A {
@@ -84,6 +102,35 @@ pub fn test_datatype_roundtrip() {
84102
size: 2 * 8 + 4 * 32 * 16,
85103
});
86104
check_roundtrip!(C, c_desc);
105+
106+
#[derive(H5Type)]
107+
#[repr(C)]
108+
struct D {
109+
#[hdf5(rename = "field.one")]
110+
a: f64,
111+
#[hdf5(rename = "field.two")]
112+
b: u64,
113+
}
114+
let d_desc = TD::Compound(CompoundType {
115+
fields: vec![
116+
CompoundField::typed::<f64>("field.one", 0, 0),
117+
CompoundField::typed::<u64>("field.two", 8, 1),
118+
],
119+
size: 16,
120+
});
121+
check_roundtrip!(D, d_desc);
122+
123+
#[derive(H5Type)]
124+
#[repr(C)]
125+
struct E(#[hdf5(rename = "alpha")] u64, f64);
126+
let e_desc = TD::Compound(CompoundType {
127+
fields: vec![
128+
CompoundField::typed::<u64>("alpha", 0, 0),
129+
CompoundField::typed::<f64>("1", 8, 1),
130+
],
131+
size: 16,
132+
});
133+
check_roundtrip!(E, e_desc);
87134
}
88135

89136
#[test]

0 commit comments

Comments
 (0)