use j2k_core::{try_host_vec_filled, try_host_vec_with_capacity};
use super::{
budget::validate_dense_weight_budget,
error::allocation_error,
shared::{high_len, low_len, WaveletKind},
transform::try_linearized_from_sample_slice,
SparseWeightRowsError,
};
type DenseWeightTable = Vec<Vec<f32>>;
#[derive(Debug, Clone, PartialEq)]
pub struct Dwt97WeightRows {
pub low: Vec<Vec<f32>>,
pub high: Vec<Vec<f32>>,
}
impl Dwt97WeightRows {
pub fn for_len(sample_len: usize) -> Result<Self, SparseWeightRowsError> {
let (low, high) = dense_rows_for_len(sample_len, WaveletKind::Irreversible97)?;
Ok(Self { low, high })
}
}
#[derive(Debug, Clone, PartialEq)]
pub struct Dwt53WeightRows {
pub low: Vec<Vec<f32>>,
pub high: Vec<Vec<f32>>,
}
impl Dwt53WeightRows {
pub fn for_len(sample_len: usize) -> Result<Self, SparseWeightRowsError> {
let (low, high) = dense_rows_for_len(sample_len, WaveletKind::Reversible53)?;
Ok(Self { low, high })
}
}
#[expect(
clippy::cast_possible_truncation,
reason = "Metal projection tables intentionally store scalar f64 weights in the f32 shader ABI"
)]
fn dense_rows_for_len(
sample_len: usize,
wavelet: WaveletKind,
) -> Result<(DenseWeightTable, DenseWeightTable), SparseWeightRowsError> {
validate_dense_weight_budget(sample_len)?;
let mut low = try_dense_rows(low_len(sample_len), sample_len)?;
let mut high = try_dense_rows(high_len(sample_len), sample_len)?;
let mut basis = try_host_vec_filled(sample_len, 0.0).map_err(allocation_error)?;
for sample_idx in 0..sample_len {
basis[sample_idx] = 1.0;
let transformed = try_linearized_from_sample_slice(&basis, wavelet)?;
for (row, &weight) in low.iter_mut().zip(&transformed.low) {
row[sample_idx] = weight as f32;
}
for (row, &weight) in high.iter_mut().zip(&transformed.high) {
row[sample_idx] = weight as f32;
}
basis[sample_idx] = 0.0;
}
Ok((low, high))
}
fn try_dense_rows(
row_count: usize,
sample_len: usize,
) -> Result<DenseWeightTable, SparseWeightRowsError> {
let mut rows = try_host_vec_with_capacity(row_count).map_err(allocation_error)?;
for _ in 0..row_count {
rows.push(try_host_vec_filled(sample_len, 0.0).map_err(allocation_error)?);
}
Ok(rows)
}