pub mod tier_a;
#[cfg(feature = "tier-b")]
pub mod tier_b;
pub use tier_a::TierA;
#[cfg(feature = "tier-b")]
pub use tier_b::TierB;
use crate::types::{Entity, WordBox};
pub fn attach_bboxes(entities: &mut [Entity], word_boxes: &[WordBox]) {
for entity in entities.iter_mut() {
if entity.bbox.is_none() {
entity.bbox = tier_a::union_bbox(word_boxes, entity.span.start, entity.span.end);
}
}
}
pub fn unplaceable_types(entities: &[Entity]) -> Vec<String> {
let mut types: Vec<String> = entities
.iter()
.filter(|e| e.bbox.is_none())
.map(|e| e.entity_type.clone())
.collect();
types.sort();
types.dedup();
types
}
#[cfg(test)]
mod routing_tests {
use super::*;
use crate::types::{BoundingBox, DetectionSource, Span};
fn word(start: usize, end: usize, x: f32, page: u32) -> WordBox {
WordBox {
span: Span { start, end },
bbox: BoundingBox {
page,
x,
y: 10.0,
width: 20.0,
height: 10.0,
},
}
}
fn span_entity(start: usize, end: usize) -> Entity {
Entity {
entity_type: "PERSON".into(),
span: Span { start, end },
score: 0.85,
bbox: None,
source: DetectionSource::TierB,
}
}
#[test]
fn a_multi_word_span_gets_the_union_of_its_words() {
let words = [word(0, 5, 0.0, 1), word(6, 11, 30.0, 1)];
let mut entities = [span_entity(0, 11)];
attach_bboxes(&mut entities, &words);
let bbox = entities[0].bbox.expect("span overlaps both words");
assert_eq!(bbox.x, 0.0);
assert_eq!(bbox.width, 50.0);
}
#[test]
fn a_span_no_word_covers_stays_unplaced_and_is_reported() {
let words = [word(0, 5, 0.0, 1)];
let mut entities = [span_entity(40, 50)];
attach_bboxes(&mut entities, &words);
assert!(entities[0].bbox.is_none());
assert_eq!(unplaceable_types(&entities), vec!["PERSON".to_string()]);
}
#[test]
fn an_existing_bbox_is_never_overwritten() {
let words = [word(0, 5, 99.0, 2)];
let mut entities = [span_entity(0, 5)];
entities[0].bbox = Some(BoundingBox {
page: 1,
x: 1.0,
y: 1.0,
width: 1.0,
height: 1.0,
});
attach_bboxes(&mut entities, &words);
assert_eq!(entities[0].bbox.unwrap().x, 1.0);
}
#[test]
fn placed_entities_are_not_reported_unplaceable() {
let words = [word(0, 5, 0.0, 1)];
let mut entities = [span_entity(0, 5)];
attach_bboxes(&mut entities, &words);
assert!(unplaceable_types(&entities).is_empty());
}
}