use std::iter::Product;
use super::algs::{AlgorithmError, Result};
pub trait IntoF32 {
fn into_f32(self) -> Result<f32>;
}
impl IntoF32 for u16 {
fn into_f32(self) -> Result<f32> {
self.try_into().map_err(|_| AlgorithmError::InvalidParameters("u16 转换为 f32 超出范围".to_string()))
}
}
pub(crate) fn dim_product<T>(uppers: &[T]) -> Result<usize>
where
T: Copy + Clone + Product<T> + TryInto<usize>,
{
uppers
.iter()
.copied()
.product::<T>()
.try_into()
.map_err(|_| AlgorithmError::InvalidParameters("乘积超出 usize".into()))
}
pub(crate) fn encode_mixed_radix<T>(value: &[T], uppers: &[T]) -> Result<usize>
where
T: Copy + TryInto<usize>,
{
if value.len() != uppers.len() {
return Err(AlgorithmError::InvalidParameters(
format!("维度不匹配 {} vs {}", value.len(), uppers.len()).into(),
));
}
let mut idx = 0;
let mut base = 1;
for (&v, &u) in value.iter().zip(uppers).rev() {
let v: usize = v.try_into().map_err(|_| AlgorithmError::InvalidParameters("v 越界".into()))?;
let u: usize = u.try_into().map_err(|_| AlgorithmError::InvalidParameters("u 越界".into()))?;
if v >= u {
return Err(AlgorithmError::InvalidParameters(
format!("v={} >= u={}", v, u).into(),
));
}
idx += v * base;
base *= u;
}
Ok(idx)
}
pub(crate) fn decode_mixed_radix<T>(mut index: usize, uppers: &[T]) -> Result<Vec<T>>
where
T: Copy + TryFrom<usize> + TryInto<usize>,
{
let mut vec = Vec::with_capacity(uppers.len());
for &u in uppers.iter().rev() {
let u: usize = u.try_into().map_err(|_| AlgorithmError::InvalidParameters("u 越界".into()))?;
let rem = index % u;
vec.push(T::try_from(rem).map_err(|_| AlgorithmError::InvalidParameters("rem 越界".into()))?);
index /= u;
}
vec.reverse(); Ok(vec)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_dim_product() {
assert_eq!(dim_product(&[2u16, 3, 4]), Ok(24));
assert_eq!(dim_product(&[5u8, 6, 7]), Ok(210));
}
#[test]
fn test_round_trip() {
let uppers = vec![2u8, 3, 4];
for idx in 0..24 {
let dec = decode_mixed_radix(idx, &uppers).unwrap();
let enc = encode_mixed_radix(&dec, &uppers).unwrap();
assert_eq!(enc, idx, "round trip failed at {}", idx);
}
}
#[test]
fn test_encode_edge() {
let uppers = vec![2u16, 3, 4];
assert_eq!(encode_mixed_radix(&[0, 0, 3], &uppers), Ok(3));
assert_eq!(encode_mixed_radix(&[1, 2, 3], &uppers), Ok(1*12 + 2*4 + 3));
}
#[test]
fn test_decode_edge() {
let uppers = vec![2u8, 3, 4];
assert_eq!(decode_mixed_radix(23, &uppers), Ok(vec![1, 2, 3]));
assert_eq!(decode_mixed_radix(0, &uppers), Ok(vec![0, 0, 0]));
}
}