localize 0.2.0

Localization library
Documentation
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);
            // let key: &'a str = unsafe { transmute(sources.keys().find(|&key| key == tag).unwrap().as_str()) };

            // Mm should be fine because it's other branch, at least I hope so.
            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)
        }
    }
}