cdx_core/presentation/
toc.rs1use serde::{Deserialize, Serialize};
4
5#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
7#[serde(rename_all = "camelCase")]
8pub struct TocConfig {
9 #[serde(default, skip_serializing_if = "Option::is_none")]
11 pub title: Option<String>,
12
13 #[serde(default, skip_serializing_if = "Option::is_none")]
15 pub levels: Option<Vec<u32>>,
16
17 #[serde(default, skip_serializing_if = "Option::is_none")]
19 pub page_numbers: Option<bool>,
20
21 #[serde(default, skip_serializing_if = "Option::is_none")]
23 pub leaders: Option<TocLeaders>,
24}
25
26impl TocConfig {
27 #[must_use]
29 pub fn new() -> Self {
30 Self {
31 title: None,
32 levels: None,
33 page_numbers: None,
34 leaders: None,
35 }
36 }
37
38 #[must_use]
40 pub fn with_title(mut self, title: impl Into<String>) -> Self {
41 self.title = Some(title.into());
42 self
43 }
44
45 #[must_use]
47 pub fn with_levels(mut self, levels: Vec<u32>) -> Self {
48 self.levels = Some(levels);
49 self
50 }
51
52 #[must_use]
54 pub const fn with_page_numbers(mut self) -> Self {
55 self.page_numbers = Some(true);
56 self
57 }
58
59 #[must_use]
61 pub const fn with_leaders(mut self, leaders: TocLeaders) -> Self {
62 self.leaders = Some(leaders);
63 self
64 }
65}
66
67impl Default for TocConfig {
68 fn default() -> Self {
69 Self::new()
70 }
71}
72
73#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
75#[serde(rename_all = "lowercase")]
76pub enum TocLeaders {
77 Dots,
79 Dashes,
81 #[serde(rename = "none")]
83 NoLeaders,
84 Solid,
86}
87
88#[cfg(test)]
89mod tests {
90 use super::*;
91
92 #[test]
93 fn test_toc_config_serde() {
94 let config = TocConfig::new()
95 .with_title("Table of Contents")
96 .with_levels(vec![1, 2, 3])
97 .with_page_numbers()
98 .with_leaders(TocLeaders::Dots);
99
100 let json = serde_json::to_string_pretty(&config).unwrap();
101 assert!(json.contains("\"title\": \"Table of Contents\""));
102 assert!(json.contains("\"pageNumbers\": true"));
103 assert!(json.contains("\"leaders\": \"dots\""));
104
105 let parsed: TocConfig = serde_json::from_str(&json).unwrap();
106 assert_eq!(parsed, config);
107 }
108
109 #[test]
110 fn test_toc_leaders_serde() {
111 assert_eq!(
112 serde_json::to_string(&TocLeaders::Dots).unwrap(),
113 "\"dots\""
114 );
115 assert_eq!(
116 serde_json::to_string(&TocLeaders::Dashes).unwrap(),
117 "\"dashes\""
118 );
119 assert_eq!(
120 serde_json::to_string(&TocLeaders::NoLeaders).unwrap(),
121 "\"none\""
122 );
123 assert_eq!(
124 serde_json::to_string(&TocLeaders::Solid).unwrap(),
125 "\"solid\""
126 );
127 }
128
129 #[test]
130 fn test_toc_defaults() {
131 let json = "{}";
132 let config: TocConfig = serde_json::from_str(json).unwrap();
133 assert!(config.title.is_none());
134 assert!(config.levels.is_none());
135 assert!(config.page_numbers.is_none());
136 assert!(config.leaders.is_none());
137 }
138}