#[cxx::bridge]
#[allow(clippy::ptr_arg)]
#[allow(clippy::too_many_arguments)]
pub mod ffi {
unsafe extern "C++" {
include!("aoflagger_sys/include/cxx_aoflagger.h");
pub type CxxImageSet;
pub type CxxFlagMask;
pub type CxxAOFlagger;
pub type CxxStrategy;
unsafe fn cxx_aoflagger_new() -> UniquePtr<CxxAOFlagger>;
fn Width(self: &CxxImageSet) -> usize;
fn Height(self: &CxxImageSet) -> usize;
fn ImageCount(self: &CxxImageSet) -> usize;
fn HorizontalStride(self: &CxxImageSet) -> usize;
fn ImageBuffer(self: &CxxImageSet, imgIndex: usize) -> &[f32];
fn ImageBufferMut(self: Pin<&mut CxxImageSet>, imgIndex: usize) -> &mut [f32];
#[allow(clippy::mut_from_ref)]
unsafe fn ImageBufferMutUnsafe(self: &CxxImageSet, imgIndex: usize) -> &mut [f32];
fn Width(self: &CxxFlagMask) -> usize;
fn Height(self: &CxxFlagMask) -> usize;
fn HorizontalStride(self: &CxxFlagMask) -> usize;
fn Buffer(self: &CxxFlagMask) -> &[bool];
fn BufferMut(self: Pin<&mut CxxFlagMask>) -> &mut [bool];
fn GetVersion(self: &CxxAOFlagger, major: &mut i16, minor: &mut i16, subMinor: &mut i16);
unsafe fn MakeImageSet(
self: &CxxAOFlagger,
width: usize,
height: usize,
count: usize,
initialValue: f32,
widthCapacity: usize,
) -> UniquePtr<CxxImageSet>;
unsafe fn MakeFlagMask(
self: &CxxAOFlagger,
width: usize,
height: usize,
initialValue: bool,
) -> UniquePtr<CxxFlagMask>;
fn FindStrategyFileGeneric(self: &CxxAOFlagger, scenario: &String) -> String;
fn FindStrategyFileMWA(self: &CxxAOFlagger) -> String;
fn LoadStrategyFile(self: &CxxAOFlagger, filename: &String) -> UniquePtr<CxxStrategy>;
fn Run(self: &CxxStrategy, input: &CxxImageSet) -> UniquePtr<CxxFlagMask>;
fn RunExisting(
self: &CxxStrategy,
input: &CxxImageSet,
existingFlags: &CxxFlagMask,
) -> UniquePtr<CxxFlagMask>;
}
}
unsafe impl Send for ffi::CxxImageSet {}
unsafe impl Sync for ffi::CxxImageSet {}
unsafe impl Send for ffi::CxxFlagMask {}
unsafe impl Sync for ffi::CxxFlagMask {}
unsafe impl Send for ffi::CxxAOFlagger {}
unsafe impl Sync for ffi::CxxAOFlagger {}
#[cfg(test)]
#[allow(clippy::float_cmp)]
mod tests_aoflagger {
use super::ffi::cxx_aoflagger_new;
use std::mem::size_of_val;
#[test]
fn test_mem_layout() {
let usize_test: usize = 0;
assert_eq!(size_of_val(&usize_test), 8);
}
#[test]
fn test_valid_img_set_init() {
let width = 2_usize;
let height = 3_usize;
let count = 4_usize;
let initial_val = 5_f32;
let width_cap = 6_usize;
let exp_stride = (((width_cap - 1) / 8) + 1) * 8;
let aoflagger = unsafe { cxx_aoflagger_new() };
let img_set =
unsafe { aoflagger.MakeImageSet(width, height, count, initial_val, width_cap) };
assert_eq!(img_set.Width(), width);
assert_eq!(img_set.Height(), height);
assert_eq!(img_set.ImageCount(), count);
assert_eq!(img_set.HorizontalStride(), exp_stride);
let fist_buffer = img_set.ImageBuffer(0);
assert_eq!(fist_buffer[0], initial_val);
}
#[test]
fn test_valid_img_set_rw() {
let width = 2_usize;
let height = 3_usize;
let count = 4_usize;
let initial_val = 5_f32;
let width_cap = 6_usize;
let aoflagger = unsafe { cxx_aoflagger_new() };
let mut img_set =
unsafe { aoflagger.MakeImageSet(width, height, count, initial_val, width_cap) };
let first_buffer_write = img_set.pin_mut().ImageBufferMut(0);
first_buffer_write[0] = 7_f32;
let first_buffer_read = img_set.ImageBuffer(0);
assert_eq!(first_buffer_read[0], 7_f32);
}
#[test]
fn test_valid_flag_mask_init() {
let width = 21_usize;
let height = 22_usize;
let initial_val = false;
let exp_stride = 8 * (width / 8 + 1);
let aoflagger = unsafe { cxx_aoflagger_new() };
let flag_mask = unsafe { aoflagger.MakeFlagMask(width, height, initial_val) };
assert_eq!(flag_mask.Width(), width);
assert_eq!(flag_mask.Height(), height);
assert_eq!(flag_mask.HorizontalStride(), exp_stride);
let buffer = flag_mask.Buffer();
assert_eq!(buffer[0], initial_val);
}
#[test]
fn test_valid_flag_mask_rw() {
let width = 21_usize;
let height = 22_usize;
let initial_val = false;
let aoflagger = unsafe { cxx_aoflagger_new() };
let mut flag_mask = unsafe { aoflagger.MakeFlagMask(width, height, initial_val) };
let buffer_write = flag_mask.pin_mut().BufferMut();
buffer_write[0] = !initial_val;
let buffer_read = flag_mask.Buffer();
assert_eq!(buffer_read[0], !initial_val);
}
#[test]
fn test_find_strategy_file_generic() {
let aoflagger = unsafe { cxx_aoflagger_new() };
let strategy_file_default = aoflagger.FindStrategyFileGeneric(&String::from(""));
assert!(str::ends_with(
&strategy_file_default,
"generic-default.lua"
));
let strategy_file_minimal = aoflagger.FindStrategyFileGeneric(&String::from("minimal"));
assert!(str::ends_with(
&strategy_file_minimal,
"generic-minimal.lua"
));
}
#[test]
fn test_find_strategy_file_mwa() {
let aoflagger = unsafe { cxx_aoflagger_new() };
let strategy_file = aoflagger.FindStrategyFileMWA();
assert!(str::ends_with(&strategy_file, "mwa-default.lua"));
}
#[test]
fn test_load_strategy_file() {
let aoflagger = unsafe { cxx_aoflagger_new() };
let strategy_file = aoflagger.FindStrategyFileMWA();
let strategy = aoflagger.LoadStrategyFile(&strategy_file);
assert_eq!(size_of_val(&strategy), 8);
}
#[test]
fn test_strategy_run() {
let width = 5_usize;
let height = 6_usize;
let count = 4_usize;
let initial_val = 5_f32;
let width_cap = width as usize;
let exp_stride = (((width - 1) / 4) + 1) * 4;
let mut exp_flag_chunks = vec![vec![false; exp_stride]; height];
let noise_x = 3;
let noise_y = 4;
let noise_z = 2;
exp_flag_chunks[noise_y][noise_x] = true;
let aoflagger = unsafe { cxx_aoflagger_new() };
let mut img_set =
unsafe { aoflagger.MakeImageSet(width, height, count, initial_val, width_cap) };
let strategy_file_name = aoflagger.FindStrategyFileGeneric(&String::from("minimal"));
let strategy = aoflagger.LoadStrategyFile(&strategy_file_name);
let img_buffer = img_set.pin_mut().ImageBufferMut(noise_z);
img_buffer[noise_y * exp_stride + noise_x] = 999_f32;
let flag_mask = strategy.Run(&img_set);
let flag_stride = flag_mask.HorizontalStride();
assert_eq!(flag_stride, exp_stride);
let flag_buffer = flag_mask.Buffer();
assert_eq!(
&flag_buffer.chunks(exp_stride).collect::<Vec<_>>(),
&exp_flag_chunks
);
}
#[test]
fn test_strategy_run_existing() {
let width = 5_usize;
let height = 6_usize;
let count = 4_usize;
let initial_val = 5_f32;
let width_cap = width as usize;
let exp_stride = (((width - 1) / 4) + 1) * 4;
let mut exp_flag_chunks = vec![vec![false; exp_stride]; height];
let existing_x = 1;
let existing_y = 2;
let noise_x = 3;
let noise_y = 4;
let noise_z = 2;
exp_flag_chunks[noise_y][noise_x] = true;
let aoflagger = unsafe { cxx_aoflagger_new() };
let strategy_file_name = aoflagger.FindStrategyFileGeneric(&String::from("minimal"));
let strategy = aoflagger.LoadStrategyFile(&strategy_file_name);
let mut img_set =
unsafe { aoflagger.MakeImageSet(width, height, count, initial_val, width_cap) };
let img_buffer = img_set.pin_mut().ImageBufferMut(noise_z);
img_buffer[noise_y * exp_stride + noise_x] = 999_f32;
let mut existing_flag_mask = unsafe { aoflagger.MakeFlagMask(width, height, false) };
let existing_flag_buf = existing_flag_mask.pin_mut().BufferMut();
existing_flag_buf[existing_y * exp_stride + existing_x] = true;
let flag_stride = existing_flag_mask.HorizontalStride();
let flag_mask = strategy.RunExisting(&img_set, &existing_flag_mask);
let flag_buffer = flag_mask.Buffer();
assert_eq!(size_of_val(&flag_buffer), 16);
assert_eq!(
&flag_buffer.chunks(flag_stride).collect::<Vec<_>>(),
&exp_flag_chunks
);
}
}