Skip to main content

fission_shell_winit/
barcode.rs

1use fission_core::{
2    BarcodeFormat, BarcodeImageDecodeRequest, BarcodePoint, BarcodeScanRequest, BarcodeScanResult,
3    BarcodeScanResults, BarcodeScannerError, CANCEL_BARCODE_SCAN, DECODE_BARCODE_IMAGE,
4    SCAN_BARCODE,
5};
6use fission_shell::async_host::AsyncRegistry;
7use std::sync::Arc;
8
9/// Host-side barcode scanner provider.
10pub trait BarcodeScannerHost: Send + Sync + 'static {
11    /// Runs a live barcode scanning session and returns decoded results.
12    fn scan(&self, request: BarcodeScanRequest) -> Result<BarcodeScanResults, BarcodeScannerError>;
13    /// Decodes barcode results from image bytes supplied by the app.
14    fn decode_image(
15        &self,
16        request: BarcodeImageDecodeRequest,
17    ) -> Result<BarcodeScanResults, BarcodeScannerError>;
18    /// Cancels the active live barcode scanning session.
19    fn cancel_scan(&self) -> Result<(), BarcodeScannerError>;
20}
21
22#[derive(Debug, Default)]
23pub struct UnsupportedBarcodeScannerHost;
24
25impl BarcodeScannerHost for UnsupportedBarcodeScannerHost {
26    fn scan(
27        &self,
28        _request: BarcodeScanRequest,
29    ) -> Result<BarcodeScanResults, BarcodeScannerError> {
30        Err(BarcodeScannerError::unsupported("scan"))
31    }
32
33    fn decode_image(
34        &self,
35        _request: BarcodeImageDecodeRequest,
36    ) -> Result<BarcodeScanResults, BarcodeScannerError> {
37        Err(BarcodeScannerError::unsupported("decode_image"))
38    }
39
40    fn cancel_scan(&self) -> Result<(), BarcodeScannerError> {
41        Err(BarcodeScannerError::unsupported("cancel_scan"))
42    }
43}
44
45#[derive(Debug, Clone)]
46pub struct MemoryBarcodeScannerHost {
47    results: BarcodeScanResults,
48}
49
50impl MemoryBarcodeScannerHost {
51    pub fn new(results: BarcodeScanResults) -> Self {
52        Self { results }
53    }
54}
55
56impl Default for MemoryBarcodeScannerHost {
57    fn default() -> Self {
58        Self {
59            results: BarcodeScanResults {
60                items: vec![BarcodeScanResult {
61                    value: "fission://barcode/memory".into(),
62                    format: BarcodeFormat::QrCode,
63                    raw_bytes: b"fission://barcode/memory".to_vec(),
64                    bounds: vec![
65                        BarcodePoint { x: 0, y: 0 },
66                        BarcodePoint { x: 64, y: 0 },
67                        BarcodePoint { x: 64, y: 64 },
68                        BarcodePoint { x: 0, y: 64 },
69                    ],
70                    symbology_identifier: None,
71                }],
72            },
73        }
74    }
75}
76
77impl BarcodeScannerHost for MemoryBarcodeScannerHost {
78    fn scan(
79        &self,
80        _request: BarcodeScanRequest,
81    ) -> Result<BarcodeScanResults, BarcodeScannerError> {
82        Ok(self.results.clone())
83    }
84
85    fn decode_image(
86        &self,
87        _request: BarcodeImageDecodeRequest,
88    ) -> Result<BarcodeScanResults, BarcodeScannerError> {
89        Ok(self.results.clone())
90    }
91
92    fn cancel_scan(&self) -> Result<(), BarcodeScannerError> {
93        Ok(())
94    }
95}
96
97pub(crate) fn register_barcode_scanner_capabilities(
98    async_registry: &mut AsyncRegistry,
99    host: Arc<dyn BarcodeScannerHost>,
100) {
101    let scan_host = host.clone();
102    async_registry.register_operation_capability(SCAN_BARCODE, move |request, _| {
103        let host = scan_host.clone();
104        async move { host.scan(request) }
105    });
106
107    let decode_host = host.clone();
108    async_registry.register_operation_capability(DECODE_BARCODE_IMAGE, move |request, _| {
109        let host = decode_host.clone();
110        async move { host.decode_image(request) }
111    });
112
113    async_registry.register_operation_capability(CANCEL_BARCODE_SCAN, move |(), _| {
114        let host = host.clone();
115        async move { host.cancel_scan() }
116    });
117}
118
119#[cfg(test)]
120mod tests {
121    use super::*;
122
123    #[test]
124    fn unsupported_host_reports_errors() {
125        let host = UnsupportedBarcodeScannerHost;
126        assert!(host.scan(BarcodeScanRequest::default()).is_err());
127        assert!(host
128            .decode_image(BarcodeImageDecodeRequest::default())
129            .is_err());
130    }
131
132    #[test]
133    fn memory_host_scans_and_decodes() {
134        let host = MemoryBarcodeScannerHost::default();
135        let scan = host.scan(BarcodeScanRequest::default()).unwrap();
136        let decode = host
137            .decode_image(BarcodeImageDecodeRequest::default())
138            .unwrap();
139        assert_eq!(scan, decode);
140        assert_eq!(scan.items[0].format, BarcodeFormat::QrCode);
141    }
142}