ldpc-toolbox 0.3.0

Utilities to aid in LDPC code design
Documentation
use super::{c_to_string, size_t_to_usize};
use crate::{
    cli::ber::parse_puncturing_pattern,
    decoder::{factory::DecoderImplementation, LdpcDecoder},
    simulation::puncturing::Puncturer,
    sparse::SparseMatrix,
};
use libc::size_t;
use std::{
    convert::TryFrom,
    error::Error,
    ffi::{c_char, c_void},
};

#[derive(Debug)]
struct Decoder {
    decoder: Box<dyn LdpcDecoder>,
    puncturer: Option<Puncturer>,
}

impl Decoder {
    fn new(alist: &str, implementation: &str, puncturing: &str) -> Result<Decoder, Box<dyn Error>> {
        let h = SparseMatrix::from_alist(&std::fs::read_to_string(alist)?)?;
        let implementation: DecoderImplementation = implementation.parse()?;
        let puncturing_pattern = if !puncturing.is_empty() {
            Some(parse_puncturing_pattern(puncturing)?)
        } else {
            None
        };
        let puncturer = puncturing_pattern.map(|v| Puncturer::new(&v));
        let decoder = implementation.build_decoder(h);
        Ok(Decoder { decoder, puncturer })
    }

    fn decode_f64(&mut self, output: &mut [u8], llrs: &[f64], max_iterations: u32) -> i32 {
        let depunctured = self.puncturer.as_ref().map(|p| p.depuncture(llrs).unwrap());
        let llrs = if let Some(d) = &depunctured { d } else { llrs };
        let res = self
            .decoder
            .decode(llrs, usize::try_from(max_iterations).unwrap());
        let success = res.is_ok();
        let decoded = match res {
            Ok(o) => o,
            Err(o) => o,
        };
        output.copy_from_slice(&decoded.codeword[..output.len()]);
        if success {
            i32::try_from(decoded.iterations).unwrap()
        } else {
            -1
        }
    }

    fn decode_f32(&mut self, output: &mut [u8], llrs: &[f32], max_iterations: u32) -> i32 {
        let llrs_f64 = llrs.iter().copied().map(f64::from).collect::<Vec<f64>>();
        self.decode_f64(output, &llrs_f64, max_iterations)
    }
}

#[no_mangle]
unsafe extern "C" fn ldpc_toolbox_decoder_ctor(
    alist: *const c_char,
    implementation: *const c_char,
    puncturing: *const c_char,
) -> *mut c_void {
    let alist = c_to_string(alist);
    let implementation = c_to_string(implementation);
    let puncturing = c_to_string(puncturing);
    if let Ok(decoder) = Decoder::new(&alist, &implementation, &puncturing) {
        Box::into_raw(Box::new(decoder)) as *mut c_void
    } else {
        std::ptr::null_mut()
    }
}

#[no_mangle]
unsafe extern "C" fn ldpc_toolbox_decoder_dtor(decoder: *mut c_void) {
    drop(Box::from_raw(decoder as *mut Decoder));
}

#[no_mangle]
unsafe extern "C" fn ldpc_toolbox_decoder_decode_f64(
    decoder: *mut c_void,
    output: *mut u8,
    output_len: size_t,
    llrs: *const f64,
    llrs_len: size_t,
    max_iterations: u32,
) -> i32 {
    let output = std::slice::from_raw_parts_mut(output, size_t_to_usize(output_len));
    let llrs = std::slice::from_raw_parts(llrs, size_t_to_usize(llrs_len));
    let decoder = &mut *(decoder as *mut Decoder);
    decoder.decode_f64(output, llrs, max_iterations)
}

#[no_mangle]
unsafe extern "C" fn ldpc_toolbox_decoder_decode_f32(
    decoder: *mut c_void,
    output: *mut u8,
    output_len: size_t,
    llrs: *const f32,
    llrs_len: size_t,
    max_iterations: u32,
) -> i32 {
    let output = std::slice::from_raw_parts_mut(output, size_t_to_usize(output_len));
    let llrs = std::slice::from_raw_parts(llrs, size_t_to_usize(llrs_len));
    let decoder = &mut *(decoder as *mut Decoder);
    decoder.decode_f32(output, llrs, max_iterations)
}