use crate::registry::ServiceRegistry;
use std::sync::Arc;
#[derive(Clone)]
pub struct CameraFrame {
pub width: u32,
pub height: u32,
pub rgba: Vec<u8>,
}
#[derive(Clone)]
pub struct CameraStill {
pub jpeg: Vec<u8>,
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct CameraLens {
pub id: String,
pub name: String,
}
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
pub enum FlashMode {
#[default]
Off,
Auto,
On,
}
#[derive(Debug, thiserror::Error)]
pub enum CameraError {
#[error("live camera capture is not supported here")]
Unsupported,
#[error("camera permission denied")]
PermissionDenied,
#[error("{0}")]
Failed(String),
}
pub trait Camera: Send + Sync {
fn start(&self) -> Result<String, CameraError>;
fn latest_frame(&self) -> Option<CameraFrame>;
fn capture_still(&self) -> Option<CameraStill> {
None
}
fn set_torch(&self, _on: bool) -> bool {
false
}
fn lenses(&self) -> Vec<CameraLens> {
Vec::new()
}
fn lens(&self) -> Option<String> {
None
}
fn use_lens(&self, _id: &str) -> bool {
false
}
fn has_flash(&self) -> bool {
false
}
fn set_flash(&self, _mode: FlashMode) -> bool {
false
}
fn stop(&self);
}
pub type CameraRef = Arc<dyn Camera>;
static PLATFORM_CAMERA: ServiceRegistry<dyn Camera> = ServiceRegistry::new();
pub fn set_platform_camera(camera: CameraRef) {
PLATFORM_CAMERA.set(camera);
}
pub fn clear_platform_camera() {
PLATFORM_CAMERA.clear();
}
pub fn camera() -> Option<CameraRef> {
PLATFORM_CAMERA.get()
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn registration_round_trips() {
let _guard = crate::registry::test_service_guard();
clear_platform_camera();
assert!(camera().is_none());
struct Fake;
impl Camera for Fake {
fn start(&self) -> Result<String, CameraError> {
Ok("fake".into())
}
fn latest_frame(&self) -> Option<CameraFrame> {
Some(CameraFrame {
width: 1,
height: 1,
rgba: vec![0, 0, 0, 255],
})
}
fn stop(&self) {}
}
set_platform_camera(Arc::new(Fake));
let cam = camera().expect("registered");
assert_eq!(cam.start().unwrap(), "fake");
assert_eq!(cam.latest_frame().unwrap().width, 1);
clear_platform_camera();
}
#[test]
fn a_backend_that_lists_no_lens_and_no_flash_says_so() {
let _guard = crate::registry::test_service_guard();
clear_platform_camera();
struct Bare;
impl Camera for Bare {
fn start(&self) -> Result<String, CameraError> {
Ok("bare".into())
}
fn latest_frame(&self) -> Option<CameraFrame> {
None
}
fn stop(&self) {}
}
set_platform_camera(Arc::new(Bare));
let cam = camera().expect("registered");
assert!(cam.lenses().is_empty());
assert_eq!(cam.lens(), None);
assert!(!cam.use_lens("0"));
assert!(!cam.has_flash());
assert!(!cam.set_flash(FlashMode::On));
clear_platform_camera();
}
#[test]
fn a_backend_that_lists_two_lenses_hands_them_over_in_order() {
let _guard = crate::registry::test_service_guard();
clear_platform_camera();
struct Two;
impl Camera for Two {
fn start(&self) -> Result<String, CameraError> {
Ok("two".into())
}
fn latest_frame(&self) -> Option<CameraFrame> {
None
}
fn lenses(&self) -> Vec<CameraLens> {
vec![
CameraLens {
id: "u".into(),
name: "Ultra wide".into(),
},
CameraLens {
id: "w".into(),
name: "Wide".into(),
},
]
}
fn lens(&self) -> Option<String> {
Some("w".into())
}
fn use_lens(&self, id: &str) -> bool {
id == "u" || id == "w"
}
fn stop(&self) {}
}
set_platform_camera(Arc::new(Two));
let cam = camera().expect("registered");
let lenses = cam.lenses();
assert_eq!(lenses.len(), 2);
assert_eq!(lenses[0].name, "Ultra wide");
assert_eq!(cam.lens().as_deref(), Some("w"));
assert!(cam.use_lens("u"));
assert!(!cam.use_lens("tele"));
clear_platform_camera();
}
}