1use std::collections::HashMap;
2
3use crate::{
4 ROOT_KEY, Value,
5 block::Block,
6 comment::{Comment, CommentType},
7 error::Error,
8 schema::Meta,
9 util,
10};
11
12#[derive(Debug, Clone)]
13pub struct Section {
14 pub key: String,
15 pub meta: Meta,
16 pub array_index: Option<usize>,
17 pub blocks: Vec<Block>,
18}
19
20impl Default for Section {
21 fn default() -> Self {
22 Section {
23 key: ROOT_KEY.to_string(),
24 meta: Meta::default(),
25 array_index: None,
26 blocks: Vec::new(),
27 }
28 }
29}
30
31impl Section {
32 pub fn is_root(&self) -> bool {
33 self.key == ROOT_KEY && !self.blocks.is_empty()
34 }
35 pub fn is_value(&self) -> bool {
36 self.key == ROOT_KEY && self.blocks.len() == 1 && self.blocks[0].is_value()
37 }
38
39 pub fn assigned_to(&mut self, ident: impl AsRef<str>) {
40 if self.is_value() {
41 for block in &mut self.blocks {
42 block.key = ident.as_ref().to_string();
43 block.ident = ident.as_ref().to_string();
44 }
45 } else {
46 util::increase_key(&mut self.key, &ident);
47 for block in &mut self.blocks {
48 util::increase_key(&mut block.key, &ident);
49 }
50 }
51 }
52
53 pub fn reduce(sections: &mut Vec<Section>) {
54 let mut map: HashMap<String, &mut Section> = HashMap::new();
55 let mut dup = Vec::new();
56 for (i, section) in sections.iter_mut().enumerate() {
57 if let Some(s) = map.get_mut(§ion.key) {
58 s.blocks.append(&mut section.blocks);
59 dup.push(i);
60 } else {
61 map.insert(section.key.clone(), section);
62 }
63 }
64 for (i, index) in dup.iter().enumerate() {
65 sections.remove(index - i);
66 }
67 }
68
69 pub fn render(&self) -> Result<String, Error> {
70 let comment = self.comment();
71 let text = comment.render()?;
72 let mut lines = Vec::new();
73 if !text.is_empty() {
74 lines.push(text);
75 }
76 let (left, right) = if self.is_root() {
77 ("".to_string(), "".to_string())
78 } else if self.meta.is_array {
79 ("[[".to_string(), "]]".to_string())
80 } else {
81 ("[".to_string(), "]".to_string())
82 };
83 lines.push(format!("{}{}{}", left, self.key, right));
84 for block in &self.blocks {
85 lines.push(block.render()?)
86 }
87 Ok(lines.join("\n"))
88 }
89
90 pub fn comment(&self) -> Comment {
91 let mut comment = self.meta.comment();
92 comment.comment_type = if self.is_root() {
93 CommentType::Root
94 } else {
95 CommentType::Section
96 };
97 comment
98 }
99}
100
101#[derive(Debug, Clone)]
102pub struct TomlContent {
103 pub sections: Vec<Section>,
104}
105
106impl TomlContent {
107 pub fn merge_value(&mut self, value: Value) {
108 let values = value.flatten();
109 for value in &values {
110 if value.array_index.is_some() {
111 let section_key = util::key_parent(&value.key);
112 let mut new_section = None;
113 for section in &mut self.sections {
114 if section.key != section_key {
115 continue;
116 }
117 if section.array_index == value.array_index {
118 new_section = None;
119 break;
120 }
121 if new_section.is_none() {
122 let mut section = section.clone();
123 section.array_index = value.array_index;
124 new_section = Some(section)
125 }
126 }
127 if let Some(section) = new_section {
128 self.sections.push(section);
129 }
130 }
131 }
132 for value in values {
133 'f0: for section in &mut self.sections {
134 if section.array_index != value.array_index {
135 continue;
136 }
137 for block in &mut section.blocks {
138 if block.key == value.key && value.value.is_some() {
139 block.value = Some(value);
140 break 'f0;
141 }
142 }
143 }
144 }
145 }
146
147 pub fn config_block_comment(&mut self, commented: bool) {
148 for section in &mut self.sections {
149 for block in &mut section.blocks {
150 block.meta.config.block_comment = commented;
151 }
152 }
153 }
154
155 pub fn render(&self) -> Result<String, Error> {
156 let mut lines = Vec::new();
157 for section in &self.sections {
158 lines.push(section.render()?);
159 }
160 Ok(lines.join("\n\n"))
161 }
162}