Skip to content

Commit 514f851

Browse files
authored
Merge pull request #30 from aldanor/feature/clone-copy
Make all high-level objects cloneable
2 parents cf6b0bc + f4a6fc0 commit 514f851

12 files changed

+75
-46
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
- Added basic support for reading and writing dataset slices.
2323
- When creating datasets, in-memory type layouts are normalized (converted to C repr).
2424
- Added `packed` option to `DatasetBuilder` (for creating packed HDF5 datasets).
25+
- All high-level objects now implement `Clone` (shallow copy, increases refcount).
2526

2627
### Changed
2728

@@ -46,6 +47,7 @@
4647
user can user methods of the parent type without having to import any traits into scope
4748
(for instance, `File` dereferences into `Group`, which dereferences into `Location`,
4849
which dereferences into `Object`).
50+
- Dataspaces and property lists can now be copied via `.copy()` method (instead of `.clone()`).
4951

5052
### Fixed
5153

hdf5-rs/src/dim.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,9 @@ use std::slice;
44
pub type Ix = usize;
55

66
/// A trait for the shape and index types.
7-
pub trait Dimension: Clone {
7+
pub trait Dimension {
88
fn ndim(&self) -> usize;
9+
910
fn dims(&self) -> Vec<Ix>;
1011

1112
fn size(&self) -> Ix {
@@ -22,6 +23,7 @@ impl<'a, T: Dimension> Dimension for &'a T {
2223
fn ndim(&self) -> usize {
2324
Dimension::ndim(*self)
2425
}
26+
2527
fn dims(&self) -> Vec<Ix> {
2628
Dimension::dims(*self)
2729
}
@@ -31,6 +33,7 @@ impl Dimension for Vec<Ix> {
3133
fn ndim(&self) -> usize {
3234
self.len()
3335
}
36+
3437
fn dims(&self) -> Vec<Ix> {
3538
self.clone()
3639
}
@@ -74,6 +77,7 @@ impl Dimension for Ix {
7477
fn ndim(&self) -> usize {
7578
1
7679
}
80+
7781
fn dims(&self) -> Vec<Ix> {
7882
vec![*self]
7983
}

hdf5-rs/src/hl/container.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ use std::fmt::{self, Debug};
22
use std::mem;
33
use std::ops::Deref;
44

5-
use ndarray::{Array, Array1, Array2, ArrayD, ArrayView, ArrayView1, Ix1, Ix2};
5+
use ndarray::{Array, Array1, Array2, ArrayD, ArrayView, ArrayView1};
66
use ndarray::{SliceInfo, SliceOrIndex};
77

88
use libhdf5_sys::h5a::{H5Aget_space, H5Aget_storage_size, H5Aget_type, H5Aread, H5Awrite};
@@ -386,6 +386,7 @@ impl<'a> Writer<'a> {
386386
}
387387

388388
#[repr(transparent)]
389+
#[derive(Clone)]
389390
pub struct Container(Handle);
390391

391392
impl ObjectClass for Container {

hdf5-rs/src/hl/dataset.rs

Lines changed: 22 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ use crate::internal_prelude::*;
2222

2323
/// Represents the HDF5 dataset object.
2424
#[repr(transparent)]
25+
#[derive(Clone)]
2526
pub struct Dataset(Handle);
2627

2728
impl ObjectClass for Dataset {
@@ -311,7 +312,7 @@ impl<T: H5Type> DatasetBuilder<T> {
311312

312313
let dims = match self.chunk {
313314
Chunk::Manual(ref c) => c.clone(),
314-
_ => infer_chunk_size(shape.clone(), datatype.size()),
315+
_ => infer_chunk_size(&shape, datatype.size()),
315316
};
316317

317318
ensure!(
@@ -399,7 +400,7 @@ impl<T: H5Type> DatasetBuilder<T> {
399400
}
400401
}
401402

402-
fn infer_chunk_size<D: Dimension>(shape: D, typesize: usize) -> Vec<Ix> {
403+
fn infer_chunk_size<D: Dimension>(shape: &D, typesize: usize) -> Vec<Ix> {
403404
// This algorithm is borrowed from h5py, though the idea originally comes from PyTables.
404405

405406
const CHUNK_BASE: f64 = (16 * 1024) as _;
@@ -452,27 +453,27 @@ pub mod tests {
452453

453454
#[test]
454455
pub fn test_infer_chunk_size() {
455-
assert_eq!(infer_chunk_size((), 1), vec![]);
456-
assert_eq!(infer_chunk_size(0, 1), vec![1]);
457-
assert_eq!(infer_chunk_size((1,), 1), vec![1]);
456+
assert_eq!(infer_chunk_size(&(), 1), vec![]);
457+
assert_eq!(infer_chunk_size(&0, 1), vec![1]);
458+
assert_eq!(infer_chunk_size(&(1,), 1), vec![1]);
458459

459460
// generated regression tests vs h5py implementation
460-
assert_eq!(infer_chunk_size((65682868,), 1), vec![64144]);
461-
assert_eq!(infer_chunk_size((56755037,), 2), vec![27713]);
462-
assert_eq!(infer_chunk_size((56882283,), 4), vec![27775]);
463-
assert_eq!(infer_chunk_size((21081789,), 8), vec![10294]);
464-
assert_eq!(infer_chunk_size((5735, 6266), 1), vec![180, 392]);
465-
assert_eq!(infer_chunk_size((467, 4427), 2), vec![30, 554]);
466-
assert_eq!(infer_chunk_size((5579, 8323), 4), vec![88, 261]);
467-
assert_eq!(infer_chunk_size((1686, 770), 8), vec![106, 49]);
468-
assert_eq!(infer_chunk_size((344, 414, 294), 1), vec![22, 52, 37]);
469-
assert_eq!(infer_chunk_size((386, 192, 444), 2), vec![25, 24, 56]);
470-
assert_eq!(infer_chunk_size((277, 161, 460), 4), vec![18, 21, 58]);
471-
assert_eq!(infer_chunk_size((314, 22, 253), 8), vec![40, 3, 32]);
472-
assert_eq!(infer_chunk_size((89, 49, 91, 59), 1), vec![12, 13, 23, 15]);
473-
assert_eq!(infer_chunk_size((42, 92, 60, 80), 2), vec![6, 12, 15, 20]);
474-
assert_eq!(infer_chunk_size((15, 62, 62, 47), 4), vec![4, 16, 16, 12]);
475-
assert_eq!(infer_chunk_size((62, 51, 55, 64), 8), vec![8, 7, 7, 16]);
461+
assert_eq!(infer_chunk_size(&(65682868,), 1), vec![64144]);
462+
assert_eq!(infer_chunk_size(&(56755037,), 2), vec![27713]);
463+
assert_eq!(infer_chunk_size(&(56882283,), 4), vec![27775]);
464+
assert_eq!(infer_chunk_size(&(21081789,), 8), vec![10294]);
465+
assert_eq!(infer_chunk_size(&(5735, 6266), 1), vec![180, 392]);
466+
assert_eq!(infer_chunk_size(&(467, 4427), 2), vec![30, 554]);
467+
assert_eq!(infer_chunk_size(&(5579, 8323), 4), vec![88, 261]);
468+
assert_eq!(infer_chunk_size(&(1686, 770), 8), vec![106, 49]);
469+
assert_eq!(infer_chunk_size(&(344, 414, 294), 1), vec![22, 52, 37]);
470+
assert_eq!(infer_chunk_size(&(386, 192, 444), 2), vec![25, 24, 56]);
471+
assert_eq!(infer_chunk_size(&(277, 161, 460), 4), vec![18, 21, 58]);
472+
assert_eq!(infer_chunk_size(&(314, 22, 253), 8), vec![40, 3, 32]);
473+
assert_eq!(infer_chunk_size(&(89, 49, 91, 59), 1), vec![12, 13, 23, 15]);
474+
assert_eq!(infer_chunk_size(&(42, 92, 60, 80), 2), vec![6, 12, 15, 20]);
475+
assert_eq!(infer_chunk_size(&(15, 62, 62, 47), 4), vec![4, 16, 16, 12]);
476+
assert_eq!(infer_chunk_size(&(62, 51, 55, 64), 8), vec![8, 7, 7, 16]);
476477
}
477478

478479
#[test]

hdf5-rs/src/hl/datatype.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ macro_rules! be_le {
4646

4747
/// Represents the HDF5 datatype object.
4848
#[repr(transparent)]
49+
#[derive(Clone)]
4950
pub struct Datatype(Handle);
5051

5152
impl ObjectClass for Datatype {

hdf5-rs/src/hl/file.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ use crate::internal_prelude::*;
1818

1919
/// Represents the HDF5 file object.
2020
#[repr(transparent)]
21+
#[derive(Clone)]
2122
pub struct File(Handle);
2223

2324
impl ObjectClass for File {

hdf5-rs/src/hl/group.rs

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ use crate::internal_prelude::*;
1313

1414
/// Represents the HDF5 group object.
1515
#[repr(transparent)]
16+
#[derive(Clone)]
1617
pub struct Group(Handle);
1718

1819
impl ObjectClass for Group {
@@ -198,6 +199,25 @@ pub mod tests {
198199
})
199200
}
200201

202+
#[test]
203+
pub fn test_clone() {
204+
with_tmp_file(|file| {
205+
file.create_group("a").unwrap();
206+
let a = file.group("a").unwrap();
207+
assert_eq!(a.name(), "/a");
208+
assert_eq!(a.file().unwrap().id(), file.id());
209+
assert_eq!(a.refcount(), 1);
210+
let b = a.clone();
211+
assert_eq!(b.name(), "/a");
212+
assert_eq!(b.file().unwrap().id(), file.id());
213+
assert_eq!(b.refcount(), 2);
214+
assert_eq!(a.refcount(), 2);
215+
drop(a);
216+
assert_eq!(b.refcount(), 1);
217+
assert!(b.is_valid());
218+
})
219+
}
220+
201221
#[test]
202222
pub fn test_len() {
203223
with_tmp_file(|file| {

hdf5-rs/src/hl/location.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ use crate::internal_prelude::*;
1212

1313
/// Named location (file, group, dataset, named datatype).
1414
#[repr(transparent)]
15+
#[derive(Clone)]
1516
pub struct Location(Handle);
1617

1718
impl ObjectClass for Location {

hdf5-rs/src/hl/object.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ use crate::internal_prelude::*;
66

77
/// Any HDF5 object that can be referenced through an identifier.
88
#[repr(transparent)]
9+
#[derive(Clone)]
910
pub struct Object(Handle);
1011

1112
impl ObjectClass for Object {

hdf5-rs/src/hl/plist.rs

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ pub mod file_create;
1313

1414
/// Represents the HDF5 property list.
1515
#[repr(transparent)]
16+
#[derive(Clone)]
1617
pub struct PropertyList(Handle);
1718

1819
impl ObjectClass for PropertyList {
@@ -46,13 +47,6 @@ impl Deref for PropertyList {
4647
}
4748
}
4849

49-
impl Clone for PropertyList {
50-
fn clone(&self) -> Self {
51-
let id = h5call!(H5Pcopy(self.id())).unwrap_or(H5I_INVALID_HID);
52-
Self::from_id(id).ok().unwrap_or_else(Self::invalid)
53-
}
54-
}
55-
5650
impl PartialEq for PropertyList {
5751
fn eq(&self, other: &Self) -> bool {
5852
h5call!(H5Pequal(self.id(), other.id())).unwrap_or(0) == 1
@@ -156,6 +150,11 @@ impl FromStr for PropertyListClass {
156150
}
157151

158152
impl PropertyList {
153+
/// Copies the property list.
154+
pub fn copy(&self) -> Self {
155+
Self::from_id(h5lock!(H5Pcopy(self.id()))).unwrap_or_else(|_| Self::invalid())
156+
}
157+
159158
/// Queries whether a property name exists in the property list.
160159
pub fn has(&self, property: &str) -> bool {
161160
to_cstring(property)
@@ -244,7 +243,7 @@ pub mod tests {
244243
pub fn test_clone() {
245244
let (fapl, _) = make_plists();
246245
assert!(fapl.is_valid());
247-
let fapl_c = fapl.clone();
246+
let fapl_c = fapl.copy();
248247
assert!(fapl.is_valid());
249248
assert!(fapl_c.is_valid());
250249
assert_eq!(fapl.refcount(), 1);

hdf5-rs/src/hl/plist/file_create.rs

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ use crate::internal_prelude::*;
2828

2929
/// File creation properties.
3030
#[repr(transparent)]
31+
#[derive(Clone)]
3132
pub struct FileCreate(Handle);
3233

3334
impl ObjectClass for FileCreate {
@@ -88,12 +89,6 @@ impl PartialEq for FileCreate {
8889

8990
impl Eq for FileCreate {}
9091

91-
impl Clone for FileCreate {
92-
fn clone(&self) -> Self {
93-
unsafe { self.deref().clone().cast() }
94-
}
95-
}
96-
9792
/// Size of the offsets and lengths used in a file.
9893
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
9994
pub struct SizeofInfo {
@@ -400,6 +395,10 @@ impl FileCreate {
400395
Self::from_id(h5try!(H5Pcreate(*H5P_FILE_CREATE)))
401396
}
402397

398+
pub fn copy(&self) -> Self {
399+
unsafe { self.deref().copy().cast() }
400+
}
401+
403402
pub fn build() -> FileCreateBuilder {
404403
FileCreateBuilder::new()
405404
}

hdf5-rs/src/hl/space.rs

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ use std::fmt::{self, Debug};
33
use std::ops::Deref;
44
use std::ptr;
55

6-
use ndarray::{SliceInfo, SliceOrIndex};
6+
use ndarray::SliceOrIndex;
77

88
use libhdf5_sys::h5s::{
99
H5Scopy, H5Screate_simple, H5Sget_simple_extent_dims, H5Sget_simple_extent_ndims,
@@ -14,6 +14,7 @@ use crate::internal_prelude::*;
1414

1515
/// Represents the HDF5 dataspace object.
1616
#[repr(transparent)]
17+
#[derive(Clone)]
1718
pub struct Dataspace(Handle);
1819

1920
impl ObjectClass for Dataspace {
@@ -53,6 +54,11 @@ impl Deref for Dataspace {
5354
}
5455

5556
impl Dataspace {
57+
/// Copies the dataspace.
58+
pub fn copy(&self) -> Self {
59+
Self::from_id(h5lock!(H5Scopy(self.id()))).unwrap_or_else(|_| Self::invalid())
60+
}
61+
5662
/// Select a slice (known as a 'hyperslab' in HDF5 terminology) of the Dataspace.
5763
/// Returns the shape of array that is capable of holding the resulting slice.
5864
/// Useful when you want to read a subset of a dataset.
@@ -160,13 +166,6 @@ impl Dimension for Dataspace {
160166
}
161167
}
162168

163-
impl Clone for Dataspace {
164-
fn clone(&self) -> Self {
165-
let id = h5call!(H5Scopy(self.id())).unwrap_or(H5I_INVALID_HID);
166-
Self::from_id(id).ok().unwrap_or_else(Self::invalid)
167-
}
168-
}
169-
170169
#[cfg(test)]
171170
pub mod tests {
172171
use crate::internal_prelude::*;
@@ -214,7 +213,7 @@ pub mod tests {
214213

215214
assert_err!(Dataspace::from_id(H5I_INVALID_HID), "Invalid dataspace id");
216215

217-
let dc = d.clone();
216+
let dc = d.copy();
218217
assert!(dc.is_valid());
219218
assert_ne!(dc.id(), d.id());
220219
assert_eq!((d.ndim(), d.dims(), d.size()), (dc.ndim(), dc.dims(), dc.size()));

0 commit comments

Comments
 (0)