1use std::path::Path;
2
3use serde::{Deserialize, Serialize};
4
5use crate::{BookyardError, Result, load_config, save_config};
6
7#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
8pub struct BookyardConfig {
9 pub workspace: WorkspaceConfig,
10 #[serde(default)]
11 pub build: BuildConfig,
12 #[serde(default)]
13 pub books: Vec<BookConfig>,
14}
15
16impl BookyardConfig {
17 pub fn new(title: impl Into<String>) -> Self {
18 Self {
19 workspace: WorkspaceConfig {
20 title: title.into(),
21 output: "bookyard".into(),
22 },
23 build: BuildConfig::default(),
24 books: Vec::new(),
25 }
26 }
27
28 pub fn load_from(path: impl AsRef<Path>) -> Result<Self> {
29 load_config(path.as_ref())
30 }
31
32 pub fn save_to(&self, path: impl AsRef<Path>) -> Result<()> {
33 save_config(path.as_ref(), self)
34 }
35
36 pub fn validate(&self) -> Result<()> {
37 for book in &self.books {
38 if book.engine != BookEngine::MdBook {
39 return Err(BookyardError::UnsupportedBookEngine(
40 book.engine.to_string(),
41 ));
42 }
43 }
44 Ok(())
45 }
46}
47
48#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
49pub struct WorkspaceConfig {
50 pub title: String,
51 #[serde(default = "default_output")]
52 pub output: String,
53}
54
55#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
56pub struct BuildConfig {
57 #[serde(default = "default_jobs")]
58 pub jobs: usize,
59 #[serde(default)]
60 pub fail_fast: bool,
61}
62
63impl Default for BuildConfig {
64 fn default() -> Self {
65 Self {
66 jobs: default_jobs(),
67 fail_fast: false,
68 }
69 }
70}
71
72#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
73pub struct BookConfig {
74 pub id: String,
75 pub title: String,
76 pub source: String,
77 #[serde(default)]
78 pub engine: BookEngine,
79 #[serde(default)]
80 pub folders: Vec<String>,
81 #[serde(default)]
82 pub tags: Vec<String>,
83 #[serde(default)]
84 pub order: i32,
85}
86
87impl BookConfig {
88 pub fn new_mdbook(
89 id: impl Into<String>,
90 title: impl Into<String>,
91 source: impl Into<String>,
92 folders: Vec<impl Into<String>>,
93 ) -> Self {
94 Self {
95 id: id.into(),
96 title: title.into(),
97 source: source.into(),
98 engine: BookEngine::MdBook,
99 folders: folders.into_iter().map(Into::into).collect(),
100 tags: Vec::new(),
101 order: 0,
102 }
103 }
104}
105
106#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
107pub enum BookEngine {
108 #[serde(rename = "mdbook")]
109 MdBook,
110}
111
112impl Default for BookEngine {
113 fn default() -> Self {
114 Self::MdBook
115 }
116}
117
118impl std::fmt::Display for BookEngine {
119 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
120 match self {
121 BookEngine::MdBook => f.write_str("mdbook"),
122 }
123 }
124}
125
126fn default_output() -> String {
127 "bookyard".into()
128}
129
130fn default_jobs() -> usize {
131 4
132}