use crate::util::{DctSample, try_vec};
use crate::{PxdctError, PxdctExecutor};
use num_traits::AsPrimitive;
use std::sync::Arc;
pub(crate) struct ScalingInterceptor<T> {
pub(crate) interceptor: Arc<dyn PxdctExecutor<T> + Send + Sync>,
}
impl<T: DctSample> PxdctExecutor<T> for ScalingInterceptor<T>
where
f64: AsPrimitive<T>,
{
fn execute(&self, data: &mut [T]) -> Result<(), PxdctError> {
let mut scratch = try_vec![T::default(); self.scratch_size()];
self.execute_with_scratch(data, &mut scratch)
}
fn execute_with_scratch(&self, data: &mut [T], scratch: &mut [T]) -> Result<(), PxdctError> {
self.interceptor.execute_with_scratch(data, scratch)?;
let scale = (2f64 / self.length() as f64).sqrt().as_();
for x in data.iter_mut() {
*x *= scale;
}
Ok(())
}
fn execute_into(&self, input: &[T], output: &mut [T]) -> Result<(), PxdctError> {
let mut scratch = try_vec![T::default(); self.scratch_size()];
self.execute_into_with_scratch(input, output, &mut scratch)
}
fn execute_into_with_scratch(
&self,
input: &[T],
output: &mut [T],
scratch: &mut [T],
) -> Result<(), PxdctError> {
use crate::util::validate_oof_sizes;
validate_oof_sizes!(input, output, self.interceptor.length());
self.interceptor
.execute_into_with_scratch(input, output, scratch)?;
let scale = (2f64 / self.length() as f64).sqrt().as_();
for x in output.iter_mut() {
*x *= scale;
}
Ok(())
}
fn length(&self) -> usize {
self.interceptor.length()
}
fn scratch_size(&self) -> usize {
self.interceptor.scratch_size()
}
}