bookyard-core 0.1.0

Core configuration and catalog model for Bookyard.
Documentation
use std::path::Path;

use serde::{Deserialize, Serialize};

use crate::{BookyardError, Result, load_config, save_config};

#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct BookyardConfig {
    pub workspace: WorkspaceConfig,
    #[serde(default)]
    pub build: BuildConfig,
    #[serde(default)]
    pub books: Vec<BookConfig>,
}

impl BookyardConfig {
    pub fn new(title: impl Into<String>) -> Self {
        Self {
            workspace: WorkspaceConfig {
                title: title.into(),
                output: "bookyard".into(),
            },
            build: BuildConfig::default(),
            books: Vec::new(),
        }
    }

    pub fn load_from(path: impl AsRef<Path>) -> Result<Self> {
        load_config(path.as_ref())
    }

    pub fn save_to(&self, path: impl AsRef<Path>) -> Result<()> {
        save_config(path.as_ref(), self)
    }

    pub fn validate(&self) -> Result<()> {
        for book in &self.books {
            if book.engine != BookEngine::MdBook {
                return Err(BookyardError::UnsupportedBookEngine(
                    book.engine.to_string(),
                ));
            }
        }
        Ok(())
    }
}

#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct WorkspaceConfig {
    pub title: String,
    #[serde(default = "default_output")]
    pub output: String,
}

#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct BuildConfig {
    #[serde(default = "default_jobs")]
    pub jobs: usize,
    #[serde(default)]
    pub fail_fast: bool,
}

impl Default for BuildConfig {
    fn default() -> Self {
        Self {
            jobs: default_jobs(),
            fail_fast: false,
        }
    }
}

#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct BookConfig {
    pub id: String,
    pub title: String,
    pub source: String,
    #[serde(default)]
    pub engine: BookEngine,
    #[serde(default)]
    pub folders: Vec<String>,
    #[serde(default)]
    pub tags: Vec<String>,
    #[serde(default)]
    pub order: i32,
}

impl BookConfig {
    pub fn new_mdbook(
        id: impl Into<String>,
        title: impl Into<String>,
        source: impl Into<String>,
        folders: Vec<impl Into<String>>,
    ) -> Self {
        Self {
            id: id.into(),
            title: title.into(),
            source: source.into(),
            engine: BookEngine::MdBook,
            folders: folders.into_iter().map(Into::into).collect(),
            tags: Vec::new(),
            order: 0,
        }
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
pub enum BookEngine {
    #[serde(rename = "mdbook")]
    MdBook,
}

impl Default for BookEngine {
    fn default() -> Self {
        Self::MdBook
    }
}

impl std::fmt::Display for BookEngine {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        match self {
            BookEngine::MdBook => f.write_str("mdbook"),
        }
    }
}

fn default_output() -> String {
    "bookyard".into()
}

fn default_jobs() -> usize {
    4
}