Skip to main content

bookforge_core/
ir.rs

1use std::path::PathBuf;
2
3use serde::{Deserialize, Serialize};
4
5#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
6pub struct BookId(pub String);
7
8#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
9pub struct SectionId(pub String);
10
11#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
12pub struct BlockId(pub String);
13
14#[derive(Debug, Clone, Serialize, Deserialize)]
15pub struct Book {
16    pub source_path: Option<PathBuf>,
17    pub id: BookId,
18    pub format: BookFormat,
19    pub metadata: Metadata,
20    pub manifest: Vec<Resource>,
21    pub spine: Vec<SpineItem>,
22    pub sections: Vec<Section>,
23    pub blocks: Vec<Block>,
24}
25
26#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
27pub enum BookFormat {
28    Epub,
29}
30
31#[derive(Debug, Clone, Default, Serialize, Deserialize)]
32pub struct Metadata {
33    pub title: Option<String>,
34    pub creators: Vec<String>,
35    pub language: Option<String>,
36}
37
38#[derive(Debug, Clone, Serialize, Deserialize)]
39pub struct Resource {
40    pub id: String,
41    pub href: String,
42    pub media_type: String,
43    pub properties: Vec<String>,
44}
45
46#[derive(Debug, Clone, Serialize, Deserialize)]
47pub struct SpineItem {
48    pub idref: String,
49    pub href: Option<String>,
50    pub linear: bool,
51}
52
53#[derive(Debug, Clone, Serialize, Deserialize)]
54pub struct Section {
55    pub id: SectionId,
56    pub href: String,
57    pub spine_index: usize,
58    pub title: Option<String>,
59    pub heading_level: Option<u8>,
60    pub block_ids: Vec<BlockId>,
61    pub prev: Option<SectionId>,
62    pub next: Option<SectionId>,
63}
64
65#[derive(Debug, Clone, Serialize, Deserialize)]
66pub struct Block {
67    pub id: BlockId,
68    pub section_id: SectionId,
69    pub kind: BlockKind,
70    pub dom_path: DomPath,
71    pub text_runs: Vec<TextRun>,
72    pub inline_marks: Vec<InlineMark>,
73    pub protected_spans: Vec<ProtectedSpan>,
74    pub token_estimate: usize,
75}
76
77#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
78pub enum BlockKind {
79    Heading(u8),
80    Paragraph,
81    ListItem,
82    Quote,
83    TableCell,
84    TableRow,
85    Footnote,
86    Caption,
87    Code,
88    Unknown,
89}
90
91#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
92pub struct DomPath(pub Vec<usize>);
93
94/// Path component base for addressing text nodes. Element children are
95/// indexed 0, 1, 2, ...; the N-th non-whitespace text node inside an
96/// element is addressed as `TEXT_NODE_PATH_BASE + N` in the final path
97/// component. The offset keeps text-node addresses from ever colliding
98/// with element indices. Reader and writer must count the same set of
99/// text nodes (non-whitespace after entity decoding) for paths to align.
100pub const TEXT_NODE_PATH_BASE: usize = usize::MAX / 2;
101
102#[derive(Debug, Clone, Serialize, Deserialize)]
103pub struct TextRun {
104    pub id: String,
105    pub text: String,
106}
107
108#[derive(Debug, Clone, Serialize, Deserialize)]
109pub struct InlineMark {
110    pub id: String,
111    pub kind: String,
112}
113
114#[derive(Debug, Clone, Serialize, Deserialize)]
115pub struct ProtectedSpan {
116    pub kind: ProtectedSpanKind,
117    pub text: String,
118}
119
120#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
121pub enum ProtectedSpanKind {
122    Url,
123    Email,
124    Code,
125    Math,
126    Number,
127    Filename,
128    InternalAnchor,
129    Citation,
130    FootnoteReference,
131}