vmb_core/system.rs
1//! RAII owner for the Vimba X runtime lifecycle.
2//!
3//! [`VmbSystem`] is the composition root for a running Vimba session. It
4//! is generic over any [`VmbRuntime`]: use the production FFI adapter in
5//! release code, an in-memory fake in tests.
6//!
7//! Construction calls [`VmbRuntime::startup`]; `Drop` calls
8//! [`VmbRuntime::shutdown`]. The "singleton" invariant (the FFI SDK is
9//! process-global) is enforced by the runtime — dropping a live system
10//! while another `VmbSystem` exists for the same runtime is prevented
11//! inside the FFI adapter, not here.
12
13use std::sync::Arc;
14
15use crate::camera::Camera;
16use crate::discovery::{register_camera_discovery, DiscoveryRegistration};
17use crate::port::VmbRuntime;
18use crate::types::{CameraInfo, DiscoveryEvent};
19use crate::Result;
20
21/// Owns the Vimba X runtime lifecycle.
22///
23/// On construction, calls [`VmbRuntime::startup`]; on drop, calls
24/// [`VmbRuntime::shutdown`].
25pub struct VmbSystem<R: VmbRuntime> {
26 runtime: Arc<R>,
27}
28
29impl<R: VmbRuntime> VmbSystem<R> {
30 /// Start the Vimba runtime with the given backend.
31 ///
32 /// Returns [`crate::VmbError::AlreadyStarted`] if another
33 /// `VmbSystem` built on the same process-global runtime is still
34 /// alive (applies to [`VmbFfiRuntime`] — fakes are per-instance).
35 ///
36 /// [`VmbFfiRuntime`]: #production-adapter
37 pub fn startup(runtime: R) -> Result<Self> {
38 let runtime = Arc::new(runtime);
39 runtime.startup()?;
40 Ok(Self { runtime })
41 }
42
43 /// Borrow the underlying runtime. Rarely needed by user code — most
44 /// operations are exposed directly on [`VmbSystem`], [`Camera`], or
45 /// [`DiscoveryRegistration`].
46 pub fn runtime(&self) -> &R {
47 &self.runtime
48 }
49
50 /// Enumerate currently-visible cameras.
51 pub fn list_cameras(&self) -> Result<Vec<CameraInfo>> {
52 self.runtime.list_cameras()
53 }
54
55 /// Open a camera by its transport-layer ID.
56 pub fn open_camera(&self, id: &str) -> Result<Camera<R>> {
57 Camera::open(self.runtime.clone(), id)
58 }
59
60 /// Register a camera-discovery subscription; the callback is invoked
61 /// for every plug / unplug / reachability event the runtime
62 /// surfaces.
63 pub fn register_discovery<F>(&self, callback: F) -> Result<DiscoveryRegistration<R>>
64 where
65 F: Fn(DiscoveryEvent) + Send + Sync + 'static,
66 {
67 register_camera_discovery(self.runtime.clone(), callback)
68 }
69}
70
71impl<R: VmbRuntime> Drop for VmbSystem<R> {
72 fn drop(&mut self) {
73 self.runtime.shutdown();
74 }
75}
76
77impl<R: VmbRuntime> std::fmt::Debug for VmbSystem<R> {
78 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
79 f.debug_struct("VmbSystem").finish_non_exhaustive()
80 }
81}