toml_input/
section.rs

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(&section.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}