#[cfg(not(feature = "std"))]
use core::ops::Range;
#[cfg(feature = "std")]
use std::ops::Range;
use crate::error::FormatError;
pub trait TryToUsize {
fn to_usize(self) -> Result<usize, FormatError>;
}
impl TryToUsize for u64 {
#[inline]
fn to_usize(self) -> Result<usize, FormatError> {
usize::try_from(self).map_err(|_| FormatError::ValueTooLargeForPlatform {
value: self,
target: "usize",
})
}
}
impl TryToUsize for u32 {
#[inline]
fn to_usize(self) -> Result<usize, FormatError> {
usize::try_from(self).map_err(|_| FormatError::ValueTooLargeForPlatform {
value: u64::from(self),
target: "usize",
})
}
}
#[inline]
pub fn usize_from(value: u64) -> Result<usize, FormatError> {
value.to_usize()
}
#[inline]
pub fn u32_from(value: u64) -> Result<u32, FormatError> {
u32::try_from(value).map_err(|_| FormatError::ValueTooLargeForPlatform {
value,
target: "u32",
})
}
#[inline]
pub fn slice_range(offset: u64, len: u64) -> Result<Range<usize>, FormatError> {
let end = offset.checked_add(len).ok_or(FormatError::OffsetOverflow {
offset,
length: len,
})?;
Ok(offset.to_usize()?..end.to_usize()?)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn small_values_round_trip() {
assert_eq!(0u64.to_usize().unwrap(), 0);
assert_eq!(1234u64.to_usize().unwrap(), 1234);
assert_eq!(42u32.to_usize().unwrap(), 42);
assert_eq!(u32_from(1000).unwrap(), 1000);
}
#[test]
fn slice_range_basic() {
let r = slice_range(10, 20).unwrap();
assert_eq!(r, 10..30);
}
#[test]
fn slice_range_addition_overflow_is_caught() {
let err = slice_range(u64::MAX, 1).unwrap_err();
assert!(matches!(err, FormatError::OffsetOverflow { .. }));
}
#[test]
fn large_u64_behaviour_matches_platform_width() {
let big: u64 = u64::from(u32::MAX) + 1; match big.to_usize() {
Ok(v) => assert_eq!(v as u64, big),
Err(e) => assert!(matches!(e, FormatError::ValueTooLargeForPlatform { .. })),
}
}
}