From caf7224e283ed726a1a0cc6b49fa351091662f0c Mon Sep 17 00:00:00 2001 From: Norman Rzepka Date: Thu, 17 Sep 2020 13:20:22 +0200 Subject: [PATCH] Rust errors (#53) * adds better error messages to rust part * adds better error messages to rust part * verbose testing * consume less memory in test_big_read * better err messages * Propagate change of error type to MATLAB API * formatting --- .github/workflows/python-module.yml | 2 +- c/Cargo.toml | 2 +- c/src/lib.rs | 14 +++++----- matlab/rust/wkw_compress/src/lib.rs | 2 +- matlab/rust/wkw_init/src/lib.rs | 8 +++--- matlab/rust/wkw_load/src/lib.rs | 4 +-- matlab/rust/wkw_mex/src/macros.rs | 2 +- matlab/rust/wkw_mex/src/util.rs | 34 ++++++++++++------------ matlab/rust/wkw_mex/src/wkw.rs | 18 ++++++------- matlab/rust/wkw_save/src/lib.rs | 2 +- python/tests/test_wkw.py | 40 +++++++++++++++++++++-------- rust/src/dataset.rs | 22 ++++++++-------- rust/src/file.rs | 30 +++++++++++----------- rust/src/header.rs | 20 +++++++-------- rust/src/lz4.rs | 4 +-- rust/src/mat.rs | 24 ++++++++--------- rust/src/result.rs | 2 +- rust/src/vec.rs | 2 +- 18 files changed, 126 insertions(+), 106 deletions(-) diff --git a/.github/workflows/python-module.yml b/.github/workflows/python-module.yml index 5b24e24..56f556e 100644 --- a/.github/workflows/python-module.yml +++ b/.github/workflows/python-module.yml @@ -38,7 +38,7 @@ jobs: -v$(pwd):/app \ -w/app/python \ testing \ - bash -c "\$PYBIN/pytest tests" + bash -c "\$PYBIN/pytest tests -v" - name: Check formatting run: | docker run \ diff --git a/c/Cargo.toml b/c/Cargo.toml index 356de1c..e0650d3 100644 --- a/c/Cargo.toml +++ b/c/Cargo.toml @@ -4,7 +4,7 @@ version = "0.1.1" authors = ["Alessandro Motta "] [dependencies] -lazy_static = "0.2" +lazy_static = "1.4" [dependencies.wkwrap] path = "../rust" diff --git a/c/src/lib.rs b/c/src/lib.rs index 9bf2e1d..8caa3cb 100644 --- a/c/src/lib.rs +++ b/c/src/lib.rs @@ -29,7 +29,7 @@ fn as_log2(i: u8) -> Result { } } -fn from_header(header_ptr: *const Header) -> Result { +fn from_header(header_ptr: *const Header) -> Result { assert!(!header_ptr.is_null()); let c_header = unsafe { &*header_ptr }; @@ -38,7 +38,7 @@ fn from_header(header_ptr: *const Header) -> Result { 1 => wkw::BlockType::Raw, 2 => wkw::BlockType::LZ4, 3 => wkw::BlockType::LZ4HC, - _ => return Err("Block type is invalid"), + other => return Err(format!("Block type '{}' is invalid", other)), }; let voxel_type = match c_header.voxel_type { @@ -52,7 +52,7 @@ fn from_header(header_ptr: *const Header) -> Result { 8 => wkw::VoxelType::I16, 9 => wkw::VoxelType::I32, 10 => wkw::VoxelType::I64, - _ => return Err("Voxel type is invalid"), + other => return Err(format!("Voxel type '{}' is invalid", other)), }; let block_len_log2 = as_log2(c_header.block_len)?; @@ -70,11 +70,11 @@ fn from_header(header_ptr: *const Header) -> Result { }) } -fn check_return(ret: Result) -> c_int { +fn check_return(ret: Result) -> c_int { match ret { Ok(_) => 0, Err(msg) => { - set_last_error_msg(msg); + set_last_error_msg(&msg); 1 } } @@ -107,7 +107,7 @@ pub extern "C" fn dataset_open(root_ptr: *const c_char) -> *const Dataset { unsafe { std::mem::transmute(dataset_ptr) } } Err(msg) => { - set_last_error_msg(msg); + set_last_error_msg(&msg); std::ptr::null::() } } @@ -161,7 +161,7 @@ pub extern "C" fn dataset_create( unsafe { std::mem::transmute(dataset_ptr) } } Err(msg) => { - set_last_error_msg(msg); + set_last_error_msg(&msg); std::ptr::null::() } } diff --git a/matlab/rust/wkw_compress/src/lib.rs b/matlab/rust/wkw_compress/src/lib.rs index cee590e..cfa72a0 100644 --- a/matlab/rust/wkw_compress/src/lib.rs +++ b/matlab/rust/wkw_compress/src/lib.rs @@ -10,7 +10,7 @@ use std::path::Path; mex_function!(_nlhs, _lhs, nrhs, rhs, { let rhs = match nrhs == 2 { true => slice::from_raw_parts(rhs, nrhs as usize), - false => return Err("Invalid number of input arguments") + false => return Err("Invalid number of input arguments".to_string()) }; let src_path = Path::new(mx_array_to_str(rhs[0])?); diff --git a/matlab/rust/wkw_init/src/lib.rs b/matlab/rust/wkw_init/src/lib.rs index d34c617..0f3b531 100644 --- a/matlab/rust/wkw_init/src/lib.rs +++ b/matlab/rust/wkw_init/src/lib.rs @@ -9,7 +9,7 @@ use std::path::Path; unsafe fn new(nrhs: c_int, rhs: *const MxArray) -> Result<()> { let rhs = match nrhs == 5 { true => slice::from_raw_parts(rhs, nrhs as usize), - false => return Err("Invalid number of input arguments") + false => return Err("Invalid number of input arguments".to_string()) }; let wkw_path = Path::new(mx_array_to_str(rhs[0])?); @@ -46,7 +46,7 @@ unsafe fn new(nrhs: c_int, rhs: *const MxArray) -> Result<()> { unsafe fn compress(nrhs: c_int, rhs: *const MxArray) -> Result<()> { let rhs = match nrhs == 2 { true => slice::from_raw_parts(rhs, nrhs as usize), - false => return Err("Invalid number of input arguments") + false => return Err("Invalid number of input arguments".to_string()) }; let src_path = Path::new(mx_array_to_str(rhs[0])?); @@ -60,13 +60,13 @@ unsafe fn compress(nrhs: c_int, rhs: *const MxArray) -> Result<()> { mex_function!(_nlhs, _lhs, nrhs, rhs, { let command = match nrhs < 1 { - true => Err("Not enough input arguments"), + true => Err("Not enough input arguments".to_string()), false => mx_array_to_str(*rhs) }?; match command { "new" => new(nrhs - 1, rhs.offset(1)), "compress" => compress(nrhs - 1, rhs.offset(1)), - _ => Err("Unknown command") + _ => Err("Unknown command".to_string()) } }); diff --git a/matlab/rust/wkw_load/src/lib.rs b/matlab/rust/wkw_load/src/lib.rs index d2847cb..4385078 100644 --- a/matlab/rust/wkw_load/src/lib.rs +++ b/matlab/rust/wkw_load/src/lib.rs @@ -10,12 +10,12 @@ use std::path::Path; mex_function!(nlhs, lhs, nrhs, rhs, { let rhs = match nrhs == 2 { true => slice::from_raw_parts(rhs, nrhs as usize), - false => return Err("Invalid number of input arguments") + false => return Err("Invalid number of input arguments".to_string()) }; let lhs = match nlhs == 1 { true => slice::from_raw_parts_mut(lhs, nlhs as usize), - false => return Err("Invalid number of output arguments") + false => return Err("Invalid number of output arguments".to_string()) }; let wkw_path = mx_array_to_str(rhs[0])?; diff --git a/matlab/rust/wkw_mex/src/macros.rs b/matlab/rust/wkw_mex/src/macros.rs index f133b07..94363d6 100644 --- a/matlab/rust/wkw_mex/src/macros.rs +++ b/matlab/rust/wkw_mex/src/macros.rs @@ -51,7 +51,7 @@ pub extern fn mexFunction( match unsafe { body(nlhs, plhs, nrhs, prhs) } { Ok(_) => (), - Err(msg) => die(msg) + Err(msg) => die(&msg) } } } diff --git a/matlab/rust/wkw_mex/src/util.rs b/matlab/rust/wkw_mex/src/util.rs index 8bd9118..27028b3 100644 --- a/matlab/rust/wkw_mex/src/util.rs +++ b/matlab/rust/wkw_mex/src/util.rs @@ -4,16 +4,16 @@ use std; use std::slice; use std::ffi::CStr; -pub type Result = std::result::Result; +pub type Result = std::result::Result; pub fn as_nat(f: f64) -> Result { if f <= 0.0 { - return Err("Input must be positive"); + return Err("Input must be positive".to_string()) } match f % 1.0 == 0.0 { true => Ok(f as u64), - false => Err("Input must be an integer") + false => Err("Input must be an integer".to_string()) } } @@ -22,7 +22,7 @@ pub fn as_log2(f: f64) -> Result { match i & (i - 1) == 0 { true => Ok(i.trailing_zeros() as u8), - false => Err("Input must be a power of two") + false => Err("Input must be a power of two".to_string()) } } @@ -38,7 +38,7 @@ pub fn str_slice_to_mx_class_id(class_id: &str) -> Result { "int16" => Ok(MxClassId::Int16), "int32" => Ok(MxClassId::Int32), "int64" => Ok(MxClassId::Int64), - _ => Err("Unknown MxClassId name") + _ => Err("Unknown MxClassId name".to_string()) } } @@ -46,28 +46,28 @@ pub fn mx_array_to_str<'a>(pm: MxArray) -> Result<&'a str> { let pm_ptr = unsafe { mxArrayToUTF8String(pm) }; if pm_ptr.is_null() { - return Err("mxArrayToUTF8String returned null") + return Err("mxArrayToUTF8String returned null".to_string()) } let pm_cstr = unsafe { CStr::from_ptr(pm_ptr) }; match pm_cstr.to_str() { Ok(pm_str) => Ok(pm_str), - Err(_) => Err("mxArray contains invalid UTF-8 data") + Err(_) => Err("mxArray contains invalid UTF-8 data".to_string()) } } pub fn mx_array_to_f64_slice<'a>(pm: MxArray) -> Result<&'a [f64]> { unsafe { - if !mxIsDouble(pm) { return Err("MxArray is not of class \"double\"") }; - if mxIsComplex(pm) { return Err("MxArray is complex") }; + if !mxIsDouble(pm) { return Err("MxArray is not of class \"double\"".to_string()) }; + if mxIsComplex(pm) { return Err("MxArray is complex".to_string()) }; } let pm_numel = unsafe { mxGetNumberOfElements(pm) }; let pm_ptr = unsafe { mxGetPr(pm) }; match pm_ptr.is_null() { - true => Err("MxArray does not contain real values"), + true => Err("MxArray does not contain real values".to_string()), false => Ok(unsafe { slice::from_raw_parts(pm_ptr, pm_numel) }) } } @@ -77,7 +77,7 @@ pub fn mx_array_to_f64(pm: MxArray) -> Result { match pm_slice.len() { 1 => Ok(pm_slice[0]), - _ => Err("MxArray contains an invalid number of doubles") + _ => Err("MxArray contains an invalid number of doubles".to_string()) } } @@ -87,9 +87,9 @@ pub fn mx_array_to_u8_slice<'a>(pm: MxArray) -> Result<&'a [u8]> { let data = unsafe { mxGetData(pm) } as *const u8; if elem_size == 0 { - Err("Failed to determine element size") + Err("Failed to determine element size".to_string()) } else if data.is_null() { - Err("Data pointer is null") + Err("Data pointer is null".to_string()) } else { Ok(unsafe { slice::from_raw_parts(data, numel * elem_size) }) } @@ -101,9 +101,9 @@ pub fn mx_array_mut_to_u8_slice_mut<'a>(pm: MxArrayMut) -> Result<&'a mut [u8]> let data = unsafe { mxGetData(pm) } as *mut u8; if elem_size == 0 { - Err("Failed to determine element size") + Err("Failed to determine element size".to_string()) } else if data.is_null() { - Err("Data pointer is null") + Err("Data pointer is null".to_string()) } else { Ok(unsafe { slice::from_raw_parts_mut(data, numel * elem_size) }) } @@ -130,7 +130,7 @@ pub fn create_numeric_array( }; match arr.is_null() { - true => Err("Failed to create uninitialized numeric array"), + true => Err("Failed to create uninitialized numeric array".to_string()), false => Ok(arr) } } @@ -139,7 +139,7 @@ pub fn malloc(n: usize) -> Result<&'static mut [u8]> { let ptr = unsafe { mxMalloc(n as MwSize) } as *mut u8; match ptr.is_null() { - true => Err("Failed to allocate memory"), + true => Err("Failed to allocate memory".to_string()), false => Ok(unsafe { slice::from_raw_parts_mut(ptr, n) }) } } diff --git a/matlab/rust/wkw_mex/src/wkw.rs b/matlab/rust/wkw_mex/src/wkw.rs index 060f95c..844321a 100644 --- a/matlab/rust/wkw_mex/src/wkw.rs +++ b/matlab/rust/wkw_mex/src/wkw.rs @@ -5,11 +5,11 @@ use ::wkwrap; fn f64_slice_to_wkwrap_vec(buf: &[f64]) -> Result { match buf.len() == 3 { true => Ok(wkwrap::Vec3 { - x: as_nat(buf[0]).or(Err("Invalid X value"))? as u32, - y: as_nat(buf[1]).or(Err("Invalid Y value"))? as u32, - z: as_nat(buf[2]).or(Err("Invalid Z value"))? as u32 + x: as_nat(buf[0]).or(Err("Invalid X value".to_string()))? as u32, + y: as_nat(buf[1]).or(Err("Invalid Y value".to_string()))? as u32, + z: as_nat(buf[2]).or(Err("Invalid Z value".to_string()))? as u32 }), - false => Err("Size mismatch") + false => Err("Size mismatch".to_string()) } } @@ -18,12 +18,12 @@ pub fn mx_array_to_wkwrap_box(pm: MxArray) -> Result { // verify shape of array if mx_array_size_to_usize_slice(pm) != &[3, 2] { - return Err("Bounding box has invalid shape"); + return Err("Bounding box has invalid shape".to_string()); } wkwrap::Box3::new( - f64_slice_to_wkwrap_vec(&buf[0..3]).or(Err("Invalid lower bound"))? - 1, - f64_slice_to_wkwrap_vec(&buf[3..6]).or(Err("Invalid upper bound"))? + f64_slice_to_wkwrap_vec(&buf[0..3]).or(Err("Invalid lower bound".to_string()))? - 1, + f64_slice_to_wkwrap_vec(&buf[3..6]).or(Err("Invalid upper bound".to_string()))? ) } @@ -49,7 +49,7 @@ pub fn mx_class_id_to_voxel_type(class_id: MxClassId) -> Result Ok(wkwrap::VoxelType::I16), MxClassId::Int32 => Ok(wkwrap::VoxelType::I32), MxClassId::Int64 => Ok(wkwrap::VoxelType::I64), - _ => Err("Unknown MxClassId") + _ => Err("Unknown MxClassId".to_string()) } } @@ -81,7 +81,7 @@ pub fn mx_array_mut_to_wkwrap_mat<'a>( // check number of input dimensions if mx_size_len > if is_multi_channel { 4 } else { 3 } { - return Err("Data array has too many dimensions"); + return Err("Data array has too many dimensions".to_string()); } let mut size = [1usize; 4]; diff --git a/matlab/rust/wkw_save/src/lib.rs b/matlab/rust/wkw_save/src/lib.rs index a8b5eb5..69d32b9 100644 --- a/matlab/rust/wkw_save/src/lib.rs +++ b/matlab/rust/wkw_save/src/lib.rs @@ -10,7 +10,7 @@ use std::path::Path; mex_function!(_nlhs, _lhs, nrhs, rhs, { let rhs = match nrhs == 3 { true => slice::from_raw_parts(rhs, nrhs as usize), - false => return Err("Invalid number of input arguments") + false => return Err("Invalid number of input arguments".to_string()) }; // path to root diff --git a/python/tests/test_wkw.py b/python/tests/test_wkw.py index 65896c0..94874da 100644 --- a/python/tests/test_wkw.py +++ b/python/tests/test_wkw.py @@ -1,7 +1,7 @@ import wkw import numpy as np import shutil -from os import path +from os import path, makedirs import pytest POSITION = (0, 0, 0) @@ -291,18 +291,38 @@ def test_multiple_writes_and_reads(): def test_big_read(): data = np.ones((10, 10, 764), order="C", dtype=np.uint8) offset = np.array([0, 0, 640]) - bottom = (2000, 2000, 2000) - mem_buffer = np.zeros(bottom, dtype=np.uint8, order="F") + bottom = (1200, 2000, 2000) with wkw.Dataset.create("tests/tmp", wkw.Header(np.uint8)) as dataset: dataset.write(offset, data) - mem_buffer[ - offset[0] : offset[0] + data.shape[0], - offset[1] : offset[1] + data.shape[1], - offset[2] : offset[2] + data.shape[2], - ] = data - read_data = dataset.read((0, 0, 0), bottom) - assert np.all(read_data == mem_buffer) + read_data = dataset.read((0, 0, 0), bottom)[0] + assert np.all( + read_data[ + offset[0] : (offset[0] + data.shape[0]), + offset[1] : (offset[1] + data.shape[1]), + offset[2] : (offset[2] + data.shape[2]), + ] + == 1 + ) + assert np.count_nonzero(read_data[: offset[0], :, :]) == 0 + assert np.count_nonzero(read_data[offset[0] + data.shape[0] :, :, :]) == 0 + assert np.count_nonzero(read_data[:, : offset[1], :]) == 0 + assert np.count_nonzero(read_data[:, offset[1] + data.shape[1] :, :]) == 0 + assert np.count_nonzero(read_data[:, :, : offset[2]]) == 0 + assert np.count_nonzero(read_data[:, :, offset[2] + data.shape[2] :]) == 0 + + +def test_invalid_dataset(): + with pytest.raises(wkw.wkw.WKWException) as excinfo: + with wkw.Dataset.open("/path/does/not/exist") as dataset: + pass + print(excinfo.value) + + with pytest.raises(wkw.wkw.WKWException) as excinfo: + makedirs("tests/tmp/exists", exist_ok=True) + with wkw.Dataset.open("tests/tmp/exists") as dataset: + pass + print(excinfo.value) def generate_test_data(dtype, size=SIZE, order="C"): diff --git a/rust/src/dataset.rs b/rust/src/dataset.rs index aa30c3f..373ace1 100644 --- a/rust/src/dataset.rs +++ b/rust/src/dataset.rs @@ -13,7 +13,7 @@ static HEADER_FILE_NAME: &'static str = "header.wkw"; impl Dataset { pub fn new(root: &Path) -> Result { if !root.is_dir() { - return Err("Dataset root is not a directory"); + return Err(format!("Dataset root {:?} is not a directory", &root)); } // read required header file @@ -27,7 +27,7 @@ impl Dataset { pub fn create(root: &Path, mut header: Header) -> Result { // create directory hierarchy - fs::create_dir_all(root).or(Err("Could not create dataset directory"))?; + fs::create_dir_all(root).or(Err(format!("Could not create dataset directory {:?}", &root)))?; // create header file Self::create_header_file(root, &mut header)?; @@ -48,11 +48,11 @@ impl Dataset { header_path.push(HEADER_FILE_NAME); if header_path.exists() { - return Err("Header file already exists"); + return Err(format!("Header {:?} file already exists", &header_path)); } // create header file - let mut file = fs::File::create(header_path).or(Err("Could not create header file"))?; + let mut file = fs::File::create(&header_path).or(Err(format!("Could not create header file {:?}", &header_path)))?; header.write(&mut file) } @@ -110,16 +110,16 @@ impl Dataset { pub fn write_mat(&self, dst_pos: Vec3, mat: &Mat) -> Result { // validate input matrix if mat.voxel_type != self.header.voxel_type { - return Err("Input matrix has invalid voxel type"); + return Err(format!("Input matrix has invalid voxel type {:?} != {:?}", mat.voxel_type, self.header.voxel_type)); } if mat.voxel_size != self.header.voxel_size as usize { - return Err("Input matrix has invalid voxel size"); + return Err(format!("Input matrix has invalid voxel size {} != {}", mat.voxel_size, self.header.voxel_size as usize)); } let num_channels = self.header.voxel_type.size() / self.header.voxel_size as usize; if num_channels > 1 && mat.data_in_c_order { - return Err("Cannot write multichannel data if data is in row-major order."); + return Err(String::from("Cannot write multichannel data if data is in row-major order.")); } let file_len_vx_log2 = self.header.file_len_vx_log2() as u32; @@ -128,9 +128,9 @@ impl Dataset { let is_dst_aligned = dst_pos % file_len_vec == Vec3::from(0); let is_shape_aligned = mat.shape % file_len_vec == Vec3::from(0); if !is_dst_aligned || !is_shape_aligned { - return Err("When writing compressed files, each file has to be \ + return Err(String::from("When writing compressed files, each file has to be \ written as a whole. Please pad your data so that all cubes \ - are complete and the write position is block-aligned."); + are complete and the write position is block-aligned.")); } }; @@ -180,10 +180,10 @@ impl Dataset { let mut header_path = PathBuf::from(root); header_path.push(HEADER_FILE_NAME); - let mut header_file_opt = fs::File::open(header_path); + let mut header_file_opt = fs::File::open(&header_path); let header_file = match header_file_opt.as_mut() { Ok(header_file) => header_file, - Err(_) => return Err("Could not open header file"), + Err(_) => return Err(format!("Could not open header file {:?}", header_path)), }; Header::read(header_file) diff --git a/rust/src/file.rs b/rust/src/file.rs index f693996..7dfe138 100644 --- a/rust/src/file.rs +++ b/rust/src/file.rs @@ -31,7 +31,7 @@ impl File { } pub fn open(path: &path::Path) -> Result { - let mut file = fs::File::open(path).or(Err("Could not open WKW file"))?; + let mut file = fs::File::open(path).or(Err(format!("Could not open WKW file {:?}", path)))?; let header = Header::read(&mut file)?; Ok(Self::new(file, header)) } @@ -39,13 +39,13 @@ impl File { pub(crate) fn open_or_create(path: &path::Path, header: &Header) -> Result { // create parent directory, if needed if let Some(parent) = path.parent() { - fs::create_dir_all(parent).or(Err("Could not create parent directory"))?; + fs::create_dir_all(parent).or(Err(format!("Could not create parent directory {:?}", parent)))?; } let mut open_opts = fs::OpenOptions::new(); open_opts.read(true).write(true).create(true); - let mut file = open_opts.open(path).or(Err("Could not open file"))?; + let mut file = open_opts.open(path).or(Err(format!("Could not open file {:?}", path)))?; // check if file was created let (header, created) = match Header::read(&mut file) { @@ -212,7 +212,7 @@ impl File { // make sure that output path does not exist yet let mut file = match path.exists() { - true => return Err("Output file already exists"), + true => return Err(format!("Output file {:?} already exists", path)), false => Self::open_or_create(path, &header)?, }; @@ -251,13 +251,13 @@ impl File { self.file .set_len(truncated_size) - .map_err(|_| "Could not truncate file") + .map_err(|_| String::from("Could not truncate file")) } fn seek_header(&mut self) -> Result<()> { match self.file.seek(SeekFrom::Start(0)) { Ok(0) => Ok(()), - _ => Err("Could not seek header"), + _ => Err(String::from("Could not seek header")), } } @@ -268,12 +268,12 @@ impl File { fn read_block(&mut self, buf: &mut [u8]) -> Result { if buf.len() != self.header.block_size() { - return Err("Buffer has invalid size"); + return Err(String::from("Buffer has invalid size")); } let block_idx = match self.block_idx { Some(block_idx) => block_idx, - None => return Err("File is not block aligned"), + None => return Err(String::from("File is not block aligned")), }; let result = match self.header.block_type { @@ -292,7 +292,7 @@ impl File { fn write_block(&mut self, buf: &[u8]) -> Result { let block_idx = match self.block_idx { Some(block_idx) => block_idx, - None => return Err("File is not block aligned"), + None => return Err(String::from("File is not block aligned")), }; let result = match self.header.block_type { @@ -312,14 +312,14 @@ impl File { fn read_block_raw(&mut self, buf: &mut [u8]) -> Result { match self.file.read_exact(buf) { Ok(_) => Ok(buf.len()), - Err(_) => Err("Could not read raw block"), + Err(_) => Err(String::from("Could not read raw block")), } } fn write_block_raw(&mut self, buf: &[u8]) -> Result { match self.file.write_all(buf) { Ok(_) => Ok(buf.len()), - Err(_) => Err("Could not write raw block"), + Err(_) => Err(String::from("Could not write raw block")), } } @@ -331,7 +331,7 @@ impl File { // write data self.file .write_all(&buf_lz4[..len_lz4]) - .or(Err("Could not write LZ4 block"))?; + .or(Err(String::from("Could not write LZ4 block")))?; // update jump table let jump_entry = self @@ -357,14 +357,14 @@ impl File { // read compressed block self.file .read_exact(buf_lz4) - .or(Err("Error while reading LZ4 block"))?; + .or(Err(String::from("Error while reading LZ4 block")))?; // decompress block let byte_written = lz4::decompress_safe(buf_lz4, buf)?; match byte_written == block_size_raw { true => Ok(byte_written), - false => Err("Unexpected length after decompression"), + false => Err(String::from("Unexpected length after decompression")), } } @@ -378,7 +378,7 @@ impl File { // seek to byte offset match self.file.seek(SeekFrom::Start(offset)) { - Err(_) => Err("Could not seek block"), + Err(_) => Err(String::from("Could not seek block")), Ok(_) => { self.block_idx = Some(block_idx); Ok(block_idx) diff --git a/rust/src/header.rs b/rust/src/header.rs index ea3f1c1..720d300 100644 --- a/rust/src/header.rs +++ b/rust/src/header.rs @@ -107,7 +107,7 @@ impl Header { let mut buf = [0u8; 16]; let mut header = match file.read_exact(&mut buf) { - Err(_) => return Err("Could not read raw header"), + Err(_) => return Err(String::from("Could not read raw header")), Ok(_) => Self::from_bytes(buf)?, }; @@ -127,7 +127,7 @@ impl Header { pub fn write(&self, file: &mut fs::File) -> Result<()> { if file.write_all(&self.to_bytes()).is_err() { - return Err("Could not write header"); + return Err(String::from("Could not write header")); } match self.jump_table { @@ -156,7 +156,7 @@ impl Header { match result { Ok(_) => Ok(jump_table.into_boxed_slice()), - Err(_) => Err("Could not read jump table"), + Err(_) => Err(String::from("Could not read jump table")), } } @@ -174,13 +174,13 @@ impl Header { match result { Ok(_) => Ok(()), - Err(_) => Err("Could not write jump table"), + Err(_) => Err(String::from("Could not write jump table")), } } pub fn block_offset(&self, block_idx: u64) -> Result { if block_idx >= self.file_vol() { - return Err("Block index out of bounds"); + return Err(String::from("Block index out of bounds")); } let offset = match self.block_type { @@ -215,7 +215,7 @@ impl Header { let block_size = jump_table[block_idx] - jump_table[block_idx - 1]; Ok(block_size as usize) } else { - Err("Block index out of bounds") + Err(String::from("Block index out of bounds")) } } } @@ -248,11 +248,11 @@ impl Header { let raw: HeaderRaw = unsafe { mem::transmute(buf) }; if &raw.magic != "WKW".as_bytes() { - return Err("Sequence of magic bytes is invalid"); + return Err(format!("Sequence of magic bytes {:?} is invalid", &raw.magic)); } if raw.version != 1 { - return Err("Version number is invalid"); + return Err(format!("Version number '{}' is invalid", raw.version)); } let block_len_log2 = raw.per_dim_log2 & 0x0f; @@ -262,7 +262,7 @@ impl Header { 1 => BlockType::Raw, 2 => BlockType::LZ4, 3 => BlockType::LZ4HC, - _ => return Err("Block type is invalid"), + other => return Err(format!("Block type '{}' is invalid", other)), }; let voxel_type = match raw.voxel_type { @@ -276,7 +276,7 @@ impl Header { 8 => VoxelType::I16, 9 => VoxelType::I32, 10 => VoxelType::I64, - _ => return Err("Voxel type is invalid"), + other => return Err(format!("Voxel type '{}' is invalid", other)), }; Ok(Header { diff --git a/rust/src/lz4.rs b/rust/src/lz4.rs index 7fee1e6..008de3c 100644 --- a/rust/src/lz4.rs +++ b/rust/src/lz4.rs @@ -47,7 +47,7 @@ pub fn compress_hc(src_buf: &[u8], dst_buf: &mut [u8]) -> Result { }; match dst_len == 0 { - true => Err("Error in LZ4_compress_HC"), + true => Err(String::from("Error in LZ4_compress_HC")), false => Ok(dst_len as usize), } } @@ -66,7 +66,7 @@ pub fn decompress_safe(src_buf: &[u8], dst_buf: &mut [u8]) -> Result { }; match dst_len < 0 { - true => Err("Error in LZ4_decompress_safe"), + true => Err(String::from("Error in LZ4_decompress_safe")), false => Ok(dst_len as usize), } } diff --git a/rust/src/mat.rs b/rust/src/mat.rs index 36a2ef7..0710149 100644 --- a/rust/src/mat.rs +++ b/rust/src/mat.rs @@ -23,11 +23,11 @@ impl<'a> Mat<'a> { let numel = shape.x as usize * shape.y as usize * shape.z as usize; let expected_len = numel * voxel_size; if data.len() != expected_len { - return Err("Length of slice does not match expected size"); + return Err(format!("Length of slice does not match expected size {} != {}", data.len(), expected_len)); } if voxel_size % voxel_type.size() != 0 { - return Err("Voxel size must be a multiple of voxel type size"); + return Err(format!("Voxel size must be a multiple of voxel type size {} % {} != 0", voxel_size, voxel_type.size())); } Ok(Mat { @@ -63,16 +63,16 @@ impl<'a> Mat<'a> { pub fn copy_as_fortran_order(&self, buffer: &mut Mat, src_bbox: Box3) -> Result<()> { if !self.data_in_c_order { - return Err("Mat is already in fortran order"); + return Err(String::from("Mat is already in fortran order")); } if self.voxel_size != buffer.voxel_size { - return Err("Matrices mismatch in voxel size"); + return Err(format!("Matrices mismatch in voxel size {} != {}", self.voxel_size, buffer.voxel_size)); } if self.voxel_type != buffer.voxel_type { - return Err("Matrices mismatch in voxel type"); + return Err(format!("Matrices mismatch in voxel type {:?} != {:?}", self.voxel_type, buffer.voxel_type)); } if self.shape != buffer.shape { - return Err("Matrices mismatch in shape"); + return Err(format!("Matrices mismatch in shape {:?} != {:?}", self.shape, buffer.shape)); } let buffer_data = buffer.as_mut_slice(); @@ -125,7 +125,7 @@ impl<'a> Mat<'a> { intermediate_buffer: &mut Mat, ) -> Result<()> { if self.data_in_c_order { - return Err("copy_from_order_agnostic has to be called on a fortran order buffer."); + return Err(String::from("copy_from_order_agnostic has to be called on a fortran order buffer.")); } if src.data_in_c_order { @@ -140,19 +140,19 @@ impl<'a> Mat<'a> { pub fn copy_from(&mut self, dst_pos: Vec3, src: &Mat, src_box: Box3) -> Result<()> { // make sure that matrices are matching if self.voxel_size != src.voxel_size { - return Err("Matrices mismatch in voxel size"); + return Err(format!("Matrices mismatch in voxel size {} != {}", self.voxel_size, src.voxel_size)); } if self.voxel_type != src.voxel_type { - return Err("Matrices mismatch in voxel type"); + return Err(format!("Matrices mismatch in voxel type {:?} != {:?}", self.voxel_type, src.voxel_type)); } if !(src_box.max() < (src.shape + 1)) { - return Err("Reading out of bounds"); + return Err(String::from("Reading out of bounds")); } if !(dst_pos + src_box.width() < (self.shape + 1)) { - return Err("Writing out of bounds"); + return Err(String::from("Writing out of bounds")); } if self.data_in_c_order != src.data_in_c_order { - return Err("Source and destination has to be the same order"); + return Err(String::from("Source and destination has to be the same order")); } let length = src_box.width(); diff --git a/rust/src/result.rs b/rust/src/result.rs index a7b1c24..2e84c4c 100644 --- a/rust/src/result.rs +++ b/rust/src/result.rs @@ -1,3 +1,3 @@ use std::result; -pub type Result = result::Result; +pub type Result = result::Result; diff --git a/rust/src/vec.rs b/rust/src/vec.rs index 3b574d1..f5007a2 100644 --- a/rust/src/vec.rs +++ b/rust/src/vec.rs @@ -18,7 +18,7 @@ impl Box3 { pub fn new(min: Vec3, max: Vec3) -> Result { match min < (max + 1) { true => Ok(Box3 { min: min, max: max }), - false => Err("Minimum and maximum are in conflict"), + false => Err(String::from("Minimum and maximum are in conflict")), } }