Range reads M0/M1 (indexed lookups, Storage trait), ZFP, in-place editing #17
@@ -0,0 +1,59 @@
|
||||
//! File address and length → in-memory index conversion.
|
||||
//!
|
||||
//! HDF5 addresses and lengths are 64-bit; the file is parsed through a
|
||||
//! `&[u8]` indexed by `usize`. On a 64-bit target every `u64` fits, but on a
|
||||
//! 32-bit one (`wasm32`, `i686`, `thumbv7em`) an address past `usize::MAX`
|
||||
//! used to be truncated by an `as usize` cast — silently pointing at another
|
||||
//! part of the file — or to panic. [`to_usize`] is the one conversion the
|
||||
//! parsers use instead: such an address is a clean
|
||||
//! [`FormatError::Overflow`]. It cannot be inside the data anyway: no slice
|
||||
//! is longer than `isize::MAX` bytes.
|
||||
|
||||
#[cfg(not(feature = "std"))]
|
||||
use alloc::format;
|
||||
|
||||
use crate::error::FormatError;
|
||||
|
||||
/// A file address, offset or length from the file as a `usize` index.
|
||||
///
|
||||
/// Fails with [`FormatError::Overflow`] when the value does not fit this
|
||||
/// platform's `usize` (only possible on targets narrower than 64 bits).
|
||||
#[inline]
|
||||
pub fn to_usize(value: u64) -> Result<usize, FormatError> {
|
||||
usize::try_from(value).map_err(|_| too_large(value))
|
||||
}
|
||||
|
||||
#[cold]
|
||||
#[inline(never)]
|
||||
fn too_large(value: u64) -> FormatError {
|
||||
FormatError::Overflow(format!(
|
||||
"file address or length {value:#x} exceeds this platform's address space"
|
||||
))
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn values_that_fit_convert_exactly() {
|
||||
assert_eq!(to_usize(0), Ok(0));
|
||||
assert_eq!(to_usize(0x1234), Ok(0x1234));
|
||||
assert_eq!(to_usize(usize::MAX as u64), Ok(usize::MAX));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn values_past_usize_max_are_an_error_not_truncated() {
|
||||
// Only reachable where usize is narrower than u64; on a 64-bit host
|
||||
// every u64 fits, which the first branch checks instead.
|
||||
if let Some(past) = (usize::MAX as u64).checked_add(1) {
|
||||
let err = to_usize(past).unwrap_err();
|
||||
assert!(matches!(err, FormatError::Overflow(_)), "{err:?}");
|
||||
// The value an `as usize` cast would have produced is not returned.
|
||||
assert!(to_usize(u64::MAX).is_err());
|
||||
assert!(to_usize(past + 0x10).is_err());
|
||||
} else {
|
||||
assert_eq!(to_usize(u64::MAX), Ok(u64::MAX as usize));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -57,6 +57,7 @@
|
||||
#[cfg(not(feature = "std"))]
|
||||
extern crate alloc;
|
||||
|
||||
pub mod addr;
|
||||
pub mod attribute;
|
||||
pub mod attribute_info;
|
||||
pub mod btree_v1;
|
||||
|
||||
Reference in New Issue
Block a user