singe-npp 0.1.0-alpha.8

Safe Rust wrappers for NVIDIA Performance Primitives library (NPP).
Documentation
use singe_npp_sys as sys;

use crate::{
    context::StreamContext,
    error::{Error, Result},
    signal::view::{SignalView, SignalViewMut},
    try_ffi,
    types::DataTypeLike,
    utility::{to_u64, to_usize},
    workspace::ScratchBuffer,
};

pub(crate) fn integral_i32_buffer_size(source: &SignalView<'_, i32>) -> Result<usize> {
    let mut bytes = 0;
    let len = source
        .len()
        .checked_add(1)
        .ok_or_else(|| Error::OutOfRange { name: "len".into() })?;
    let raw_len = to_u64(len, "len")?;
    unsafe {
        try_ffi!(sys::nppsIntegralGetBufferSize_32s(raw_len, &raw mut bytes,))?;
    }
    to_usize(bytes, "scratch bytes")
}

pub(crate) fn integral_i32_with_scratch(
    stream_context: &StreamContext,
    source: &SignalView<'_, i32>,
    destination: &mut SignalViewMut<'_, i32>,
    scratch: &mut ScratchBuffer,
) -> Result<()> {
    validate_integral_destination_len(source, destination)?;
    let required_bytes = integral_i32_buffer_size(source)?;
    scratch.require(required_bytes)?;

    unsafe {
        try_ffi!(sys::nppsIntegral_32s_Ctx(
            source.as_ptr(),
            destination.as_mut_ptr(),
            to_u64(destination.len(), "destination length")?,
            scratch.as_mut_ptr(),
            stream_context.as_raw(),
        ))?;
    }
    Ok(())
}

pub trait Integral: DataTypeLike {
    fn integral_buffer_size(source: &SignalView<'_, Self>) -> Result<usize>;

    fn integral_with_scratch(
        stream_context: &StreamContext,
        source: &SignalView<'_, Self>,
        destination: &mut SignalViewMut<'_, Self>,
        scratch: &mut ScratchBuffer,
    ) -> Result<()>;
}

impl Integral for i32 {
    fn integral_buffer_size(source: &SignalView<'_, Self>) -> Result<usize> {
        integral_i32_buffer_size(source)
    }

    fn integral_with_scratch(
        stream_context: &StreamContext,
        source: &SignalView<'_, Self>,
        destination: &mut SignalViewMut<'_, Self>,
        scratch: &mut ScratchBuffer,
    ) -> Result<()> {
        integral_i32_with_scratch(stream_context, source, destination, scratch)
    }
}

pub fn integral_buffer_size<T: Integral>(source: &SignalView<'_, T>) -> Result<usize> {
    T::integral_buffer_size(source)
}

pub fn integral_with_scratch<T: Integral>(
    stream_context: &StreamContext,
    source: &SignalView<'_, T>,
    destination: &mut SignalViewMut<'_, T>,
    scratch: &mut ScratchBuffer,
) -> Result<()> {
    T::integral_with_scratch(stream_context, source, destination, scratch)
}

pub fn integral<T: Integral>(
    stream_context: &StreamContext,
    source: &SignalView<'_, T>,
    destination: &mut SignalViewMut<'_, T>,
) -> Result<()> {
    let required_bytes = integral_buffer_size(source)?;
    let mut scratch = ScratchBuffer::create(required_bytes)?;
    integral_with_scratch(stream_context, source, destination, &mut scratch)
}

fn validate_integral_destination_len<T>(
    source: &SignalView<'_, T>,
    destination: &SignalViewMut<'_, T>,
) -> Result<()> {
    let expected = source
        .len()
        .checked_add(1)
        .ok_or_else(|| Error::OutOfRange { name: "len".into() })?;
    if destination.len() != expected {
        return Err(Error::LengthMismatch {
            name: "destination".into(),
            expected,
            actual: destination.len(),
        });
    }

    Ok(())
}