singe-npp 0.1.0-alpha.8

Safe Rust wrappers for NVIDIA Performance Primitives library (NPP).
Documentation
use singe_cuda::memory::DeviceMemory;

use crate::error::{Error, Result};

use super::{ImageHistograms, ImageStatistic};

pub(crate) fn histogram_buffers<const C: usize>(
    levels: [i32; C],
) -> Result<[DeviceMemory<i32>; C]> {
    let lengths = levels.map(histogram_bins);
    let lengths = transpose_result(lengths)?;
    let mut buffers = Vec::with_capacity(C);
    for length in lengths {
        buffers.push(DeviceMemory::<i32>::create(length)?);
    }
    match buffers.try_into() {
        Ok(buffers) => Ok(buffers),
        Err(buffers) => Err(Error::LengthMismatch {
            name: "array length".into(),
            expected: C,
            actual: buffers.len(),
        }),
    }
}

pub(crate) fn histogram_range_buffers<Level, const C: usize>(
    levels: [&[Level]; C],
) -> Result<[DeviceMemory<i32>; C]> {
    let lengths = levels.map(histogram_range_bins);
    let lengths = transpose_result(lengths)?;
    let mut buffers = Vec::with_capacity(C);
    for length in lengths {
        buffers.push(DeviceMemory::<i32>::create(length)?);
    }
    match buffers.try_into() {
        Ok(buffers) => Ok(buffers),
        Err(buffers) => Err(Error::LengthMismatch {
            name: "array length".into(),
            expected: C,
            actual: buffers.len(),
        }),
    }
}

fn histogram_bins(levels: i32) -> Result<usize> {
    if levels < 2 {
        return Err(Error::OutOfRange {
            name: "levels".into(),
        });
    }
    usize::try_from(levels - 1).map_err(|_| Error::OutOfRange {
        name: "levels".into(),
    })
}

fn histogram_range_bins<Level>(levels: &[Level]) -> Result<usize> {
    if levels.len() < 2 {
        return Err(Error::OutOfRange {
            name: "levels".into(),
        });
    }
    Ok(levels.len() - 1)
}

fn transpose_result<T, const C: usize>(results: [Result<T>; C]) -> Result<[T; C]> {
    let mut values = Vec::with_capacity(C);
    for result in results {
        values.push(result?);
    }
    match values.try_into() {
        Ok(values) => Ok(values),
        Err(values) => Err(Error::LengthMismatch {
            name: "array length".into(),
            expected: C,
            actual: values.len(),
        }),
    }
}

pub(crate) fn image_histograms(histograms: Vec<DeviceMemory<i32>>) -> ImageHistograms {
    ImageHistograms {
        channels: histograms
            .into_iter()
            .map(ImageStatistic::from_values)
            .collect(),
    }
}