Skip to main content

apple_vision/
request_base.rs

1//! Shared request / observation building blocks for Vision base classes.
2
3use std::path::{Path, PathBuf};
4
5use crate::registration::{HomographicAlignment, TranslationalAlignment};
6
7/// Function-pointer shape used by [`RequestProgress`] /
8/// [`RequestProgressProviding`].
9pub type RequestProgressHandler = fn(f64);
10
11/// Mirrors the observable state carried by `VNRequestProgressProviding`.
12#[derive(Debug, Clone, Copy, Default)]
13pub struct RequestProgress {
14    progress_handler: Option<RequestProgressHandler>,
15    indeterminate: bool,
16}
17
18impl RequestProgress {
19    #[must_use]
20    pub const fn new() -> Self {
21        Self {
22            progress_handler: None,
23            indeterminate: false,
24        }
25    }
26
27    #[must_use]
28    pub const fn with_progress_handler(mut self, progress_handler: RequestProgressHandler) -> Self {
29        self.progress_handler = Some(progress_handler);
30        self
31    }
32
33    #[must_use]
34    pub const fn with_indeterminate(mut self, indeterminate: bool) -> Self {
35        self.indeterminate = indeterminate;
36        self
37    }
38
39    #[must_use]
40    pub const fn progress_handler(&self) -> Option<RequestProgressHandler> {
41        self.progress_handler
42    }
43
44    #[must_use]
45    pub const fn is_indeterminate(&self) -> bool {
46        self.indeterminate
47    }
48}
49
50/// Rust mirror of `VNRequestProgressProviding`.
51pub trait RequestProgressProviding {
52    fn progress_handler(&self) -> Option<RequestProgressHandler>;
53    fn is_indeterminate(&self) -> bool;
54}
55
56impl RequestProgressProviding for RequestProgress {
57    fn progress_handler(&self) -> Option<RequestProgressHandler> {
58        self.progress_handler()
59    }
60
61    fn is_indeterminate(&self) -> bool {
62        self.is_indeterminate()
63    }
64}
65
66/// Rust mirror of `VNRequestRevisionProviding`.
67pub trait RequestRevisionProviding {
68    fn request_revision(&self) -> Option<usize>;
69}
70
71/// A normalized rectangle in Vision image coordinates (`0.0..=1.0`, lower-left origin).
72#[derive(Debug, Clone, Copy, PartialEq)]
73pub struct NormalizedRect {
74    pub x: f64,
75    pub y: f64,
76    pub width: f64,
77    pub height: f64,
78}
79
80impl NormalizedRect {
81    #[must_use]
82    pub const fn new(x: f64, y: f64, width: f64, height: f64) -> Self {
83        Self {
84            x,
85            y,
86            width,
87            height,
88        }
89    }
90}
91
92/// Common configuration shared by `VNImageBasedRequest` subclasses.
93#[derive(Debug, Clone, PartialEq, Default)]
94pub struct ImageBasedRequest {
95    region_of_interest: Option<NormalizedRect>,
96    prefer_background_processing: bool,
97    uses_cpu_only: bool,
98    revision: Option<usize>,
99}
100
101impl ImageBasedRequest {
102    #[must_use]
103    pub const fn new() -> Self {
104        Self {
105            region_of_interest: None,
106            prefer_background_processing: false,
107            uses_cpu_only: false,
108            revision: None,
109        }
110    }
111
112    #[must_use]
113    pub const fn with_region_of_interest(mut self, region_of_interest: NormalizedRect) -> Self {
114        self.region_of_interest = Some(region_of_interest);
115        self
116    }
117
118    #[must_use]
119    pub const fn with_prefer_background_processing(mut self, enabled: bool) -> Self {
120        self.prefer_background_processing = enabled;
121        self
122    }
123
124    #[must_use]
125    pub const fn with_uses_cpu_only(mut self, enabled: bool) -> Self {
126        self.uses_cpu_only = enabled;
127        self
128    }
129
130    #[must_use]
131    pub const fn with_revision(mut self, revision: usize) -> Self {
132        self.revision = Some(revision);
133        self
134    }
135
136    #[must_use]
137    pub const fn region_of_interest(&self) -> Option<NormalizedRect> {
138        self.region_of_interest
139    }
140
141    #[must_use]
142    pub const fn prefer_background_processing(&self) -> bool {
143        self.prefer_background_processing
144    }
145
146    #[must_use]
147    pub const fn uses_cpu_only(&self) -> bool {
148        self.uses_cpu_only
149    }
150
151    #[must_use]
152    pub const fn revision(&self) -> Option<usize> {
153        self.revision
154    }
155}
156
157impl RequestRevisionProviding for ImageBasedRequest {
158    fn request_revision(&self) -> Option<usize> {
159        self.revision()
160    }
161}
162
163/// A Rust wrapper for the abstract `VNTargetedImageRequest` base class.
164#[derive(Debug, Clone, PartialEq, Eq)]
165pub struct TargetedImageRequest {
166    targeted_image_path: PathBuf,
167}
168
169impl TargetedImageRequest {
170    #[must_use]
171    pub fn new(targeted_image_path: impl AsRef<Path>) -> Self {
172        Self {
173            targeted_image_path: targeted_image_path.as_ref().to_path_buf(),
174        }
175    }
176
177    #[must_use]
178    pub fn targeted_image_path(&self) -> &Path {
179        &self.targeted_image_path
180    }
181}
182
183impl RequestRevisionProviding for TargetedImageRequest {
184    fn request_revision(&self) -> Option<usize> {
185        None
186    }
187}
188
189/// A Rust wrapper for the abstract `VNStatefulRequest` base class.
190#[derive(Debug, Clone, Copy, PartialEq)]
191pub struct StatefulRequest {
192    frame_analysis_spacing_seconds: Option<f64>,
193    minimum_latency_frame_count: usize,
194}
195
196impl Default for StatefulRequest {
197    fn default() -> Self {
198        Self::new()
199    }
200}
201
202impl StatefulRequest {
203    #[must_use]
204    pub const fn new() -> Self {
205        Self {
206            frame_analysis_spacing_seconds: None,
207            minimum_latency_frame_count: 0,
208        }
209    }
210
211    #[must_use]
212    pub const fn with_frame_analysis_spacing_seconds(mut self, seconds: f64) -> Self {
213        self.frame_analysis_spacing_seconds = Some(seconds);
214        self
215    }
216
217    #[must_use]
218    pub const fn with_minimum_latency_frame_count(mut self, frame_count: usize) -> Self {
219        self.minimum_latency_frame_count = frame_count;
220        self
221    }
222
223    #[must_use]
224    pub const fn frame_analysis_spacing_seconds(&self) -> Option<f64> {
225        self.frame_analysis_spacing_seconds
226    }
227
228    #[must_use]
229    pub const fn minimum_latency_frame_count(&self) -> usize {
230        self.minimum_latency_frame_count
231    }
232}
233
234impl RequestRevisionProviding for StatefulRequest {
235    fn request_revision(&self) -> Option<usize> {
236        None
237    }
238}
239
240/// Mirrors `VNRequestTrackingLevel` used by `VNTrackingRequest` subclasses.
241#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
242pub enum TrackingLevel {
243    Accurate,
244    Fast,
245}
246
247/// A Rust wrapper for the abstract `VNTrackingRequest` base class.
248#[derive(Debug, Clone, PartialEq)]
249pub struct TrackingRequest {
250    tracking_level: TrackingLevel,
251    last_frame: bool,
252    input_observation: Option<NormalizedRect>,
253}
254
255impl Default for TrackingRequest {
256    fn default() -> Self {
257        Self::new()
258    }
259}
260
261impl TrackingRequest {
262    #[must_use]
263    pub const fn new() -> Self {
264        Self {
265            tracking_level: TrackingLevel::Fast,
266            last_frame: false,
267            input_observation: None,
268        }
269    }
270
271    #[must_use]
272    pub const fn with_tracking_level(mut self, tracking_level: TrackingLevel) -> Self {
273        self.tracking_level = tracking_level;
274        self
275    }
276
277    #[must_use]
278    pub const fn with_last_frame(mut self, last_frame: bool) -> Self {
279        self.last_frame = last_frame;
280        self
281    }
282
283    #[must_use]
284    pub const fn with_input_observation(mut self, input_observation: NormalizedRect) -> Self {
285        self.input_observation = Some(input_observation);
286        self
287    }
288
289    #[must_use]
290    pub const fn tracking_level(&self) -> TrackingLevel {
291        self.tracking_level
292    }
293
294    #[must_use]
295    pub const fn is_last_frame(&self) -> bool {
296        self.last_frame
297    }
298
299    #[must_use]
300    pub const fn input_observation(&self) -> Option<NormalizedRect> {
301        self.input_observation
302    }
303}
304
305impl RequestRevisionProviding for TrackingRequest {
306    fn request_revision(&self) -> Option<usize> {
307        None
308    }
309}
310
311/// A Rust wrapper for the abstract `VNImageRegistrationRequest` base class.
312#[derive(Debug, Clone, PartialEq, Eq)]
313pub struct ImageRegistrationRequest {
314    targeted_image: TargetedImageRequest,
315}
316
317impl ImageRegistrationRequest {
318    #[must_use]
319    pub fn new(targeted_image_path: impl AsRef<Path>) -> Self {
320        Self {
321            targeted_image: TargetedImageRequest::new(targeted_image_path),
322        }
323    }
324
325    #[must_use]
326    pub const fn from_targeted_image_request(targeted_image: TargetedImageRequest) -> Self {
327        Self { targeted_image }
328    }
329
330    #[must_use]
331    pub const fn targeted_image_request(&self) -> &TargetedImageRequest {
332        &self.targeted_image
333    }
334}
335
336impl RequestRevisionProviding for ImageRegistrationRequest {
337    fn request_revision(&self) -> Option<usize> {
338        RequestRevisionProviding::request_revision(&self.targeted_image)
339    }
340}
341
342/// A Rust wrapper for the abstract `VNImageAlignmentObservation` base class.
343#[derive(Debug, Clone, Copy, PartialEq)]
344pub enum ImageAlignmentObservation {
345    Translational(TranslationalAlignment),
346    Homographic(HomographicAlignment),
347}
348
349impl ImageAlignmentObservation {
350    #[must_use]
351    pub const fn translational(alignment: TranslationalAlignment) -> Self {
352        Self::Translational(alignment)
353    }
354
355    #[must_use]
356    pub const fn homographic(alignment: HomographicAlignment) -> Self {
357        Self::Homographic(alignment)
358    }
359}
360
361/// A Rust wrapper for `VNPixelBufferObservation`.
362#[derive(Debug, Clone, PartialEq, Eq)]
363pub struct PixelBufferObservation {
364    pub width: usize,
365    pub height: usize,
366    pub bytes_per_row: usize,
367    pub bytes: Vec<u8>,
368    pub feature_name: Option<String>,
369}
370
371impl PixelBufferObservation {
372    #[must_use]
373    pub const fn new(width: usize, height: usize, bytes_per_row: usize, bytes: Vec<u8>) -> Self {
374        Self {
375            width,
376            height,
377            bytes_per_row,
378            bytes,
379            feature_name: None,
380        }
381    }
382
383    #[must_use]
384    pub fn with_feature_name(mut self, feature_name: impl Into<String>) -> Self {
385        self.feature_name = Some(feature_name.into());
386        self
387    }
388
389    #[must_use]
390    pub fn as_bytes(&self) -> &[u8] {
391        &self.bytes
392    }
393}