use std::ffi::c_int;
#[repr(C)]
#[derive(Debug, Clone, Copy, PartialEq, Default)]
pub struct EfDetectBox {
pub xmin: f32,
pub ymin: f32,
pub xmax: f32,
pub ymax: f32,
pub score: f32,
pub label: u32,
}
#[repr(C)]
#[derive(Debug, Clone, Copy)]
pub struct EfSegmentation {
pub xmin: f32,
pub ymin: f32,
pub xmax: f32,
pub ymax: f32,
pub mask: *const u8,
pub width: u32,
pub height: u32,
}
#[repr(C)]
#[derive(Debug, Clone, Copy)]
pub struct EfMergeConfig {
pub metric: u32,
pub threshold: f32,
pub class_agnostic: c_int,
pub max_det: usize,
pub score_threshold: f32,
pub mode: u32,
}
#[derive(Debug, Clone, Copy, PartialEq)]
pub struct TilePlacement {
pub index: usize,
pub count: usize,
pub origin: (f32, f32),
pub crop_size: (f32, f32),
pub letterbox: Option<[f32; 4]>,
pub frame_dims: (f32, f32),
}
#[repr(C)]
#[derive(Debug, Clone, Copy)]
pub struct EfTilePlacement {
pub index: usize,
pub count: usize,
pub origin_x: f32,
pub origin_y: f32,
pub crop_width: f32,
pub crop_height: f32,
pub has_letterbox: c_int,
pub letterbox: [f32; 4],
pub frame_width: f32,
pub frame_height: f32,
}
impl From<&TilePlacement> for EfTilePlacement {
fn from(p: &TilePlacement) -> Self {
let (has_letterbox, letterbox) = match p.letterbox {
Some(lb) => (1, lb),
None => (0, [0.0; 4]),
};
Self {
index: p.index,
count: p.count,
origin_x: p.origin.0,
origin_y: p.origin.1,
crop_width: p.crop_size.0,
crop_height: p.crop_size.1,
has_letterbox,
letterbox,
frame_width: p.frame_dims.0,
frame_height: p.frame_dims.1,
}
}
}
impl From<&EfTilePlacement> for TilePlacement {
fn from(p: &EfTilePlacement) -> Self {
Self {
index: p.index,
count: p.count,
origin: (p.origin_x, p.origin_y),
crop_size: (p.crop_width, p.crop_height),
letterbox: if p.has_letterbox != 0 {
Some(p.letterbox)
} else {
None
},
frame_dims: (p.frame_width, p.frame_height),
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn this_crate_has_no_dependencies_and_never_may() {
let manifest = include_str!("../Cargo.toml");
assert!(
!manifest.contains("[dependencies."),
"dependency sub-tables are dependencies too"
);
let deps = manifest
.split("[dependencies]")
.nth(1)
.expect("manifest has a [dependencies] table");
let body = deps.split("\n[").next().unwrap_or(deps);
let lines: Vec<&str> = body
.lines()
.map(str::trim)
.filter(|l| !l.is_empty() && !l.starts_with('#'))
.collect();
assert!(
lines.is_empty(),
"edgefirst-decoder-abi grew dependencies: {lines:?}"
);
}
#[test]
fn detect_box_is_six_packed_32_bit_fields() {
assert_eq!(std::mem::size_of::<EfDetectBox>(), 24);
assert_eq!(std::mem::align_of::<EfDetectBox>(), 4);
}
#[test]
fn segmentation_layout_is_pinned() {
assert_eq!(std::mem::size_of::<EfSegmentation>(), 32);
assert_eq!(std::mem::align_of::<EfSegmentation>(), 8);
}
#[test]
fn merge_config_layout_is_pinned() {
assert_eq!(std::mem::size_of::<EfMergeConfig>(), 32);
assert_eq!(std::mem::align_of::<EfMergeConfig>(), 8);
assert_eq!(std::mem::offset_of!(EfMergeConfig, metric), 0);
assert_eq!(std::mem::offset_of!(EfMergeConfig, threshold), 4);
assert_eq!(std::mem::offset_of!(EfMergeConfig, class_agnostic), 8);
assert_eq!(std::mem::offset_of!(EfMergeConfig, max_det), 16);
assert_eq!(std::mem::offset_of!(EfMergeConfig, score_threshold), 24);
assert_eq!(std::mem::offset_of!(EfMergeConfig, mode), 28);
}
#[test]
fn tile_placement_layout_is_pinned() {
assert_eq!(std::mem::size_of::<EfTilePlacement>(), 64);
assert_eq!(std::mem::align_of::<EfTilePlacement>(), 8);
}
}