1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
|
use ogmarkup::generator::Output;
use ogmarkup::typography::{Typography, ENGLISH, FRENCH};
use serde_derive::{Deserialize, Serialize};
use crate::error::{Error, Raise};
#[derive(Debug, Serialize, Deserialize)]
pub enum Language {
Fr,
En,
}
impl Language {
pub fn typography(&self) -> &dyn Typography {
match self {
Language::Fr => &FRENCH,
Language::En => &ENGLISH,
}
}
}
#[derive(Debug, Serialize, Deserialize)]
pub struct Cover {
pub extension : String,
pub content : Vec<u8>,
}
pub trait Loader {
type CovId;
type DocId;
type ProjId;
fn load_cover(&self, id : &Self::CovId) -> Result<Cover, Error>;
fn load_document(&self, id : &Self::DocId) -> Result<String, Error>;
fn load_project(&self, id : &Self::ProjId) -> Result<Project<Self::CovId, Self::DocId>, Error>;
}
#[derive(Debug, Serialize, Deserialize)]
pub struct Chapter<I> {
pub title : Option<String>,
pub content : Vec<I>,
}
impl<I> Chapter<I> {
fn load_and_render<T, L, O>(&self, loader : &L, typo : &T) -> Result<Chapter<O>, Error>
where
T : Typography + ?Sized,
L : Loader<DocId = I>,
O : Output,
{
let title = &self.title;
let content = &self.content;
let doc = content
.iter()
.map(|ref x| {
let input = loader.load_document(x)?;
ogmarkup::compile(&input, typo)
.or_raise("Cannot parse an ogmarkup document for some reason")
})
.collect::<Result<Vec<O>, Error>>()?;
Ok(Chapter {
title : title.clone(),
content : doc,
})
}
}
#[derive(Debug, Serialize, Deserialize)]
pub struct Project<C, I> {
pub author : String,
pub title : String,
pub description : Option<String>,
pub chapters : Vec<Chapter<I>>,
pub cover : Option<C>,
pub numbering : Option<bool>,
pub language : Language,
}
impl<O> Project<Cover, O> {
pub fn load_and_render<'input, L>(
id : &L::ProjId,
loader : &L,
) -> Result<Project<Cover, O>, Error>
where
L : Loader,
O : Output,
{
let project = loader.load_project(id)?;
let lang = project.language;
let typo = lang.typography();
let numbering = project.numbering;
let descr = project.description;
let author = project.author;
let title = project.title;
let cover = project
.cover
.map(|x| loader.load_cover(&x).or_raise("cannot load the cover"))
.map_or(Ok(None), |r| r.map(Some))?;
project
.chapters
.into_iter()
.map(|chapter| chapter.load_and_render(loader, typo))
.collect::<Result<Vec<Chapter<O>>, Error>>()
.map(|x| Project {
author : author,
title : title,
description : descr,
chapters : x,
cover : cover,
numbering : numbering,
language : lang,
})
}
}
|