use std::sync::Arc;
use crate::error::{OcrError, Result};
use crate::types::{Image, OcrResult};
use super::{OcrEngine, ReadOptions};
pub struct FallbackEngine {
engines: Vec<Arc<dyn OcrEngine>>,
}
impl FallbackEngine {
pub fn new(engines: Vec<Arc<dyn OcrEngine>>) -> Result<Self> {
if engines.is_empty() {
return Err(OcrError::config("FallbackEngine requires at least one engine"));
}
Ok(Self { engines })
}
pub fn push(mut self, engine: Arc<dyn OcrEngine>) -> Self {
self.engines.push(engine);
self
}
}
impl std::fmt::Debug for FallbackEngine {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("FallbackEngine")
.field("engines", &self.engines.len())
.finish()
}
}
impl OcrEngine for FallbackEngine {
fn recognize(&self, image: &Image, options: &ReadOptions) -> Result<OcrResult> {
let mut last_error: Option<OcrError> = None;
let mut last_empty: Option<OcrResult> = None;
for engine in &self.engines {
match engine.recognize(image, options) {
Ok(result) if !result.lines.is_empty() => return Ok(result),
Ok(empty) => last_empty = Some(empty),
Err(error) => last_error = Some(error),
}
}
if let Some(error) = last_error {
return Err(error);
}
last_empty.ok_or_else(|| OcrError::config("FallbackEngine had no engines to run"))
}
}