use crate::cache::{ensure_model, Cache, ModelFiles};
use crate::engine::{Engine, Translation};
use crate::fetch::Fetch;
use crate::remote::fetch_records;
use crate::route::{resolve_route, Route, PREFERRED_HUB};
pub fn ensure_files(
fetch: &dyn Fetch,
cache: &Cache,
src: &str,
trg: &str,
) -> Result<ModelFiles, String> {
let records = fetch_records(fetch)?;
ensure_model(fetch, cache, &records, src, trg)
}
pub fn ensure_route_files(
fetch: &dyn Fetch,
cache: &Cache,
src: &str,
trg: &str,
) -> Result<(Route, Vec<ModelFiles>), String> {
let records = fetch_records(fetch)?;
let route = resolve_route(&records, src, trg)?;
let files = match &route {
Route::Direct { src, trg } => vec![ensure_model(fetch, cache, &records, src, trg)?],
Route::Pivot { src, pivot, trg } => vec![
ensure_model(fetch, cache, &records, src, pivot)?,
ensure_model(fetch, cache, &records, pivot, trg)?,
],
};
Ok((route, files))
}
pub fn load_engine(
fetch: &dyn Fetch,
cache: &Cache,
src: &str,
trg: &str,
) -> Result<Engine, String> {
let files = ensure_files(fetch, cache, src, trg)?;
engine_from(&files)
}
fn engine_from(files: &ModelFiles) -> Result<Engine, String> {
Engine::load(&files.model, &files.src_vocab, &files.trg_vocab)
}
pub fn load_translation(
fetch: &dyn Fetch,
cache: &Cache,
src: &str,
trg: &str,
) -> Result<Translation, String> {
let records = match fetch_records(fetch) {
Ok(records) => records,
Err(net) => {
return load_cached_translation(cache, src, trg)
.map_err(|miss| format!("{miss}; and Remote Settings was unreachable: {net}"))
}
};
match resolve_route(&records, src, trg)? {
Route::Direct { src, trg } => {
let files = ensure_model(fetch, cache, &records, &src, &trg)?;
Ok(Translation::Direct(engine_from(&files)?))
}
Route::Pivot { src, pivot, trg } => {
let leg1 = ensure_model(fetch, cache, &records, &src, &pivot)?;
let leg2 = ensure_model(fetch, cache, &records, &pivot, &trg)?;
Ok(Translation::Pivot {
pivot,
first: engine_from(&leg1)?,
second: engine_from(&leg2)?,
})
}
}
}
fn load_cached_translation(cache: &Cache, src: &str, trg: &str) -> Result<Translation, String> {
if let Some(files) = cache.cached_model(src, trg) {
return Ok(Translation::Direct(engine_from(&files)?));
}
let hub = PREFERRED_HUB;
if src != hub && trg != hub {
if let (Some(leg1), Some(leg2)) =
(cache.cached_model(src, hub), cache.cached_model(hub, trg))
{
return Ok(Translation::Pivot {
pivot: hub.to_string(),
first: engine_from(&leg1)?,
second: engine_from(&leg2)?,
});
}
}
Err(format!("no cached model for {src}→{trg}"))
}