1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
//! Compact detections and caller-owned detection batches.
use crate::{ClassId, CoreError, Rect, TrackId};
/// A validated object detection with optional typed metadata.
#[derive(Clone, Copy, Debug, Default, PartialEq)]
pub struct Detection {
bbox: Rect,
score: f32,
class_id: Option<ClassId>,
track_id: Option<TrackId>,
}
impl Detection {
/// Creates a detection when its score is finite.
///
/// Finite scores are preserved without clamping.
///
/// # Errors
///
/// Returns [`CoreError::NonFinite`] when `score` is NaN or infinite.
pub fn new(
bbox: Rect,
score: f32,
class_id: Option<ClassId>,
track_id: Option<TrackId>,
) -> Result<Self, CoreError> {
if !score.is_finite() {
return Err(CoreError::NonFinite);
}
Ok(Self {
bbox,
score,
class_id,
track_id,
})
}
/// Returns the detection bounding box.
#[must_use]
pub const fn bbox(self) -> Rect {
self.bbox
}
/// Returns the model confidence score.
#[must_use]
pub const fn score(self) -> f32 {
self.score
}
/// Returns the optional class identifier.
#[must_use]
pub const fn class_id(self) -> Option<ClassId> {
self.class_id
}
/// Returns the optional external track identifier.
#[must_use]
pub const fn track_id(self) -> Option<TrackId> {
self.track_id
}
}
/// A detection batch backed by mutable storage owned by the caller.
#[derive(Debug)]
pub struct DetectionBatch<'a> {
storage: &'a mut [Detection],
len: usize,
}
impl<'a> DetectionBatch<'a> {
/// Creates an empty batch over caller-owned storage.
#[must_use]
pub fn new(storage: &'a mut [Detection]) -> Self {
Self { storage, len: 0 }
}
/// Creates a batch whose complete caller-owned slice contains valid data.
#[must_use]
pub fn from_filled(storage: &'a mut [Detection]) -> Self {
let len = storage.len();
Self { storage, len }
}
/// Appends a detection without reallocating or truncating existing data.
///
/// # Errors
///
/// Returns [`CoreError::InsufficientCapacity`] without modifying the batch
/// when the caller-owned storage is full.
pub fn push(&mut self, detection: Detection) -> Result<(), CoreError> {
let slot = self
.storage
.get_mut(self.len)
.ok_or(CoreError::InsufficientCapacity)?;
*slot = detection;
self.len += 1;
Ok(())
}
/// Returns the valid prefix of the caller-owned storage.
#[must_use]
pub fn as_slice(&self) -> &[Detection] {
&self.storage[..self.len]
}
}