| 
1 | 1 | use std::convert::TryFrom;  | 
2 | 2 | use std::fmt;  | 
 | 3 | +use std::io::{Read, Seek, SeekFrom};  | 
3 | 4 | 
 
  | 
4 | 5 | use ndarray::{s, Array1, Array2, ArrayD, IxDyn, SliceInfo};  | 
5 | 6 | use rand::prelude::{Rng, SeedableRng, SmallRng};  | 
6 | 7 | 
 
  | 
7 |  | -use hdf5_types::TypeDescriptor;  | 
 | 8 | +use hdf5_types::{H5Type, TypeDescriptor};  | 
8 | 9 | 
 
  | 
9 | 10 | mod common;  | 
10 | 11 | 
 
  | 
@@ -171,6 +172,85 @@ where  | 
171 | 172 |     Ok(())  | 
172 | 173 | }  | 
173 | 174 | 
 
  | 
 | 175 | +fn test_byte_read_seek_impl(ds: &hdf5::Dataset, arr: &ArrayD<u8>, ndim: usize) -> hdf5::Result<()> {  | 
 | 176 | +    let mut rng = SmallRng::seed_from_u64(42);  | 
 | 177 | +    ds.write(arr)?;  | 
 | 178 | + | 
 | 179 | +    // Read whole  | 
 | 180 | +    let reader = ds.as_byte_reader();  | 
 | 181 | +    let mut reader = if ndim != 1 {  | 
 | 182 | +        assert!(reader.is_err());  | 
 | 183 | +        return Ok(());  | 
 | 184 | +    } else {  | 
 | 185 | +        reader.unwrap()  | 
 | 186 | +    };  | 
 | 187 | +    let mut out_bytes = vec![0u8; arr.len()];  | 
 | 188 | +    reader.read(&mut out_bytes.as_mut_slice()).expect("io::Read failed");  | 
 | 189 | +    assert_eq!(out_bytes.as_slice(), arr.as_slice().unwrap());  | 
 | 190 | + | 
 | 191 | +    // Read in chunks  | 
 | 192 | +    let mut reader = reader.clone();  | 
 | 193 | +    reader.seek(std::io::SeekFrom::Start(0)).expect("io::Seek failed");  | 
 | 194 | +    let mut pos = 0;  | 
 | 195 | +    while pos < arr.len() {  | 
 | 196 | +        let chunk_len: usize = rng.gen_range(1..arr.len() + 1);  | 
 | 197 | +        let mut chunk = vec![0u8; chunk_len];  | 
 | 198 | +        let n_read = reader.read(&mut chunk).expect("io::Read failed");  | 
 | 199 | +        if pos + chunk_len < arr.len() {  | 
 | 200 | +            // We did not read until end. Thus, the chunk should be fully filled.  | 
 | 201 | +            assert_eq!(chunk_len, n_read);  | 
 | 202 | +        }  | 
 | 203 | +        assert_eq!(&chunk[..n_read], arr.slice(s![pos..pos + n_read]).as_slice().unwrap());  | 
 | 204 | +        pos += chunk_len;  | 
 | 205 | +    }  | 
 | 206 | + | 
 | 207 | +    // Seek to the begining and read again  | 
 | 208 | +    reader.seek(SeekFrom::Start(0)).expect("io::Seek failed");  | 
 | 209 | +    let mut out_bytes = vec![0u8; arr.len()];  | 
 | 210 | +    reader.read(&mut out_bytes.as_mut_slice()).expect("io::Read failed");  | 
 | 211 | +    assert_eq!(out_bytes.as_slice(), arr.as_slice().unwrap());  | 
 | 212 | + | 
 | 213 | +    // Seek to a random position from start  | 
 | 214 | +    let pos = rng.gen_range(0..arr.len() + 1) as u64;  | 
 | 215 | +    let seeked_pos = reader.seek(SeekFrom::Start(pos)).expect("io::Seek failed") as usize;  | 
 | 216 | +    let mut out_bytes = vec![0u8; arr.len() - seeked_pos];  | 
 | 217 | +    reader.read(&mut out_bytes.as_mut_slice()).expect("io::Read failed");  | 
 | 218 | +    assert_eq!(out_bytes.as_slice(), arr.slice(s![seeked_pos..]).as_slice().unwrap());  | 
 | 219 | + | 
 | 220 | +    // Seek from current position  | 
 | 221 | +    let orig_pos = reader.seek(SeekFrom::Start(pos)).expect("io::Seek failed") as i64;  | 
 | 222 | +    let rel_pos = rng.gen_range(-(arr.len() as i64)..arr.len() as i64 + 1);  | 
 | 223 | +    let pos_res = reader.seek(SeekFrom::Current(rel_pos));  | 
 | 224 | +    if (rel_pos + orig_pos) < 0 {  | 
 | 225 | +        assert!(pos_res.is_err()) // We cannot seek before start  | 
 | 226 | +    } else {  | 
 | 227 | +        let seeked_pos = pos_res.unwrap() as usize;  | 
 | 228 | +        assert_eq!(rel_pos + orig_pos, seeked_pos as i64);  | 
 | 229 | +        let mut out_bytes = vec![0u8; arr.len() - seeked_pos];  | 
 | 230 | +        reader.read(&mut out_bytes.as_mut_slice()).expect("io::Read failed");  | 
 | 231 | +        assert_eq!(out_bytes.as_slice(), arr.slice(s![seeked_pos..]).as_slice().unwrap());  | 
 | 232 | +    }  | 
 | 233 | + | 
 | 234 | +    // Seek to a random position from end  | 
 | 235 | +    let pos = -(rng.gen_range(0..arr.len() + 1) as i64);  | 
 | 236 | +    let seeked_pos = reader.seek(SeekFrom::End(pos)).expect("io::Seek failed") as usize;  | 
 | 237 | +    assert_eq!(pos, seeked_pos as i64 - arr.len() as i64);  | 
 | 238 | +    let mut out_bytes = vec![0u8; arr.len() - seeked_pos];  | 
 | 239 | +    reader.read(&mut out_bytes.as_mut_slice()).expect("io::Read failed");  | 
 | 240 | +    assert_eq!(out_bytes.as_slice(), arr.slice(s![seeked_pos..]).as_slice().unwrap());  | 
 | 241 | + | 
 | 242 | +    // Seek before start  | 
 | 243 | +    assert!(reader.seek(SeekFrom::End(-(arr.len() as i64) - 1)).is_err());  | 
 | 244 | + | 
 | 245 | +    // Test stream position start  | 
 | 246 | +    // Requires Rust 1.55.0: reader.rewind().expect("io::Seek::rewind failed");  | 
 | 247 | +    assert_eq!(0, reader.seek(SeekFrom::Start(0)).unwrap());  | 
 | 248 | +    assert_eq!(0, reader.stream_position().unwrap());  | 
 | 249 | +    assert_eq!(0, reader.seek(SeekFrom::End(-(arr.len() as i64))).unwrap());  | 
 | 250 | +    assert_eq!(0, reader.stream_position().unwrap());  | 
 | 251 | +    Ok(())  | 
 | 252 | +}  | 
 | 253 | + | 
174 | 254 | fn test_read_write<T>() -> hdf5::Result<()>  | 
175 | 255 | where  | 
176 | 256 |     T: hdf5::H5Type + fmt::Debug + PartialEq + Gen + Clone,  | 
@@ -278,3 +358,24 @@ fn test_read_write_rename_fields() -> hdf5::Result<()> {  | 
278 | 358 |     test_read_write::<RenameEnum>()?;  | 
279 | 359 |     Ok(())  | 
280 | 360 | }  | 
 | 361 | + | 
 | 362 | +#[test]  | 
 | 363 | +fn test_byte_read_seek() -> hdf5::Result<()> {  | 
 | 364 | +    let mut rng = SmallRng::seed_from_u64(42);  | 
 | 365 | +    let file = new_in_memory_file()?;  | 
 | 366 | + | 
 | 367 | +    for ndim in 0..=2 {  | 
 | 368 | +        for _ in 0..=20 {  | 
 | 369 | +            let arr: ArrayD<u8> = gen_arr(&mut rng, ndim);  | 
 | 370 | + | 
 | 371 | +            let ds: hdf5::Dataset = file.new_dataset::<u8>().shape(arr.shape()).create("x")?;  | 
 | 372 | +            let ds = scopeguard::guard(ds, |ds| {  | 
 | 373 | +                drop(ds);  | 
 | 374 | +                drop(file.unlink("x"));  | 
 | 375 | +            });  | 
 | 376 | + | 
 | 377 | +            test_byte_read_seek_impl(&ds, &arr, ndim)?;  | 
 | 378 | +        }  | 
 | 379 | +    }  | 
 | 380 | +    Ok(())  | 
 | 381 | +}  | 
0 commit comments