der_die_das 0.5.0

der_die_das: Learn german genders like a true geek.
Documentation
pub mod nouns_attempts_repo;
pub mod nouns_repo;
pub mod sentence_attempts_repo;
pub mod sentence_repo;
use std::path::PathBuf;

use miette::{miette, Context as _, IntoDiagnostic as _, Report, Result};
use serde::{Deserialize, Serialize};
use tracing::{info, instrument};

use crate::nouns::Article;

#[derive(Debug, Clone)]
pub struct Storage(pub PathBuf);

impl Storage {
    fn nouns_attempts_path(&self) -> PathBuf {
        self.0.join("nouns_attempts")
    }
    fn nouns_path(&self) -> PathBuf {
        self.0.join("nouns")
    }
    fn sentence_path(&self) -> PathBuf {
        self.0.join("sentences")
    }
    #[allow(unused)]
    fn sentence_attempts_path(&self) -> PathBuf {
        self.0.join("sentence_attempts")
    }
}

impl TryFrom<PathBuf> for Storage {
    type Error = Report;
    #[instrument]
    fn try_from(at: PathBuf) -> Result<Self> {
        if !at
            .try_exists()
            .into_diagnostic()
            .wrap_err_with(|| "somethig good!")?
        {
            info!(
                directory = at.to_string_lossy().into_owned(),
                "storage directory does not exist yet. creating it right now."
            );
            fs_extra::dir::create_all(&at, false).into_diagnostic()?;
        };
        if at.is_file() {
            return Err(miette!(
                help = "The address should be directory where I can store a load of data files.",
                "The path at {} is not a directory.",
                at.to_string_lossy()
            ));
        };
        let storage = Storage(at);

        if !storage.nouns_path().try_exists().into_diagnostic()? {
            info!(
                directory = storage.nouns_path().to_string_lossy().into_owned(),
                "storage nouns directory does not exist yet. creating it right now."
            );
            fs_extra::dir::create_all(storage.nouns_path(), false).into_diagnostic()?;
        }

        if !storage
            .nouns_attempts_path()
            .try_exists()
            .into_diagnostic()?
        {
            info!(
                directory = storage.nouns_attempts_path().to_string_lossy().into_owned(),
                "storage nouns attempts directory does not exist yet. creating it right now."
            );
            fs_extra::dir::create_all(storage.nouns_attempts_path(), false).into_diagnostic()?;
        }

        Ok(storage)
    }
}

#[derive(Debug, Clone, Copy, clap::ValueEnum, PartialEq, Eq, Deserialize, Serialize)]
#[serde(rename_all = "lowercase")]
pub enum ArticleFileV1 {
    Der,
    Die,
    Das,
}

impl From<ArticleFileV1> for Article {
    fn from(value: ArticleFileV1) -> Self {
        match value {
            ArticleFileV1::Der => Article::Der,
            ArticleFileV1::Die => Article::Die,
            ArticleFileV1::Das => Article::Das,
        }
    }
}
impl From<Article> for ArticleFileV1 {
    fn from(value: Article) -> Self {
        match value {
            Article::Der => ArticleFileV1::Der,
            Article::Die => ArticleFileV1::Die,
            Article::Das => ArticleFileV1::Das,
        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    fn is_normal<T: Sized + Send + Sync + Unpin>() {}
    #[test]
    fn normal_types() {
        is_normal::<Storage>();
    }
}