use std::{collections::HashMap, borrow::Cow, fs};
use crate::{Locale, Sources, LocaleError};
#[derive(Debug, Default)]
pub(crate) struct LocaleCache<'a>(
HashMap<
&'a str, Locale
>,
pub(crate) Option<&'static str>
);
impl<'a> LocaleCache<'a> {
pub fn new() -> Self {
Default::default()
}
#[allow(unused)]
pub fn look_up(&self, tag: &str) -> crate::Result<&Locale> {
if let Some(locale) = self.0.get(tag) {
return Ok(locale);
} else {
if let Some(default_tag) = self.1 {
return self.0.get(default_tag).ok_or(LocaleError::CacheExhaustion);
}
}
Err(LocaleError::CacheExhaustion)
}
#[allow(unused)]
pub fn look_up_or_fetch(&self, tag: &str, sources: &Sources) -> crate::Result<Cow<Locale>> {
if let Some(locale) = self.0.get(tag) {
log::trace!("Locale `{}` was found in cache.", tag);
Ok(Cow::Borrowed(locale))
} else if let Some(path) = sources.get(tag) {
log::trace!("Locale `{}` is missing in cache, fetching sources.", tag);
let locale = json::from_reader(fs::File::open(path)?)?;
log::trace!("Loaded locale `{}` from disk.", tag);
Ok(Cow::Owned(locale))
} else {
if let Some(default_tag) = self.1 {
log::trace!("Locale `{}` is missing in cache. Falling back to default locale `{}`.", tag, default_tag);
if let Some(default) = self.0.get(default_tag) {
log::trace!("Fetched default locale `{}` from cache.", default_tag);
Ok(Cow::Borrowed(default))
} else if let Some(path) = sources.get(default_tag) {
let default = json::from_reader(fs::File::open(path)?)?;
log::trace!("Fetched default locale `{}` from disk.", default_tag);
Ok(Cow::Owned(default))
} else {
log::error!("Fallback to default locale failed. Was not found in cache nor on disk.");
Err(LocaleError::FallbackToDefaultFailed)
}
} else {
log::error!("Locale `{}` wasn't found in sources, and default was `None`. Aborted.", tag);
Err(LocaleError::LocaleNotFound)
}
}
}
#[allow(unused, clippy::cast_ref_to_mut)]
pub fn look_up_or_cache<'w>(&mut self, tag: &'w str, sources: &Sources) -> crate::Result<&Locale>
where
'w: 'a
{
if let Some(locale) = self.0.get(tag) {
log::trace!("Locale `{}` was found in cache.", tag);
Ok(locale)
} else if let Some(path) = sources.get(tag) {
log::trace!("Locale `{}` is missing in cache, fetching sources.", tag);
let locale = json::from_reader(fs::File::open(path)?)?;
log::trace!("Loaded locale `{}` from disk.", tag);
unsafe { &mut *(self as *const Self as *mut Self) }.0.insert(tag, locale);
log::trace!("Overwritten locale `{}` in cache.", tag);
Ok(self.0.get(tag).unwrap())
} else {
if let Some(default_tag) = self.1 {
log::trace!("Locale `{}` is missing in cache. Falling back to default locale `{}`.", tag, default_tag);
if let Some(default) = self.0.get(default_tag) {
Ok(default)
} else if let Some(path) = sources.get(default_tag) {
let default = json::from_reader(fs::File::open(path)?)?;
unsafe { &mut *(self as *const Self as *mut Self) }.0.insert(default_tag, default);
log::trace!("Cached default locale `{}`.", default_tag);
Ok(self.0.get(default_tag).unwrap())
} else {
log::error!("Fallback to default locale failed. Was not found in cache nor on disk.");
Err(LocaleError::FallbackToDefaultFailed)
}
} else {
log::error!("Locale `{}` wasn't found in sources, and default was `None`. Aborted.", tag);
Err(LocaleError::LocaleNotFound)
}
}
}
#[allow(unused)]
pub fn prefer_recache<'w>(&mut self, tag: &'w str, sources: &Sources) -> crate::Result<&Locale>
where
'w: 'a
{
if let Some(path) = sources.get(tag) {
log::trace!("Locale `{}` was found in cache.", tag);
let locale = json::from_reader(fs::File::open(path)?)?;
self.0.insert(tag, locale);
Ok(self.0.get(tag).unwrap())
} else if let Some(default_tag) = self.1 {
log::trace!("Locale `{}` is missing in cache. Falling back to default locale `{}`", tag, default_tag);
let locale = json::from_reader(
fs::File::open(
sources.get(default_tag).ok_or(LocaleError::SourceLookupFailed)?
)?
)?;
self.0.insert(tag, locale);
Ok(self.0.get(tag).unwrap())
} else {
self.look_up(tag)
}
}
}