toml_input/
section.rs

1use std::collections::HashMap;
2
3use crate::{
4    BANG_COMMENT, ROOT_KEY,
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 is_commented(&self) -> bool {
40        let mut commented = self.meta.config.commented;
41        for block in &self.blocks {
42            commented = commented && block.is_comented();
43        }
44        commented
45    }
46
47    pub fn is_none_skipped(&self) -> bool {
48        let mut skipped = self.meta.is_option_type() && self.meta.config.is_none_skipped();
49        for block in &self.blocks {
50            skipped = skipped && block.is_none_skipped();
51        }
52        skipped
53    }
54
55    pub fn assigned_to(&mut self, ident: impl AsRef<str>) {
56        if self.is_value() {
57            for block in &mut self.blocks {
58                block.key = ident.as_ref().to_string();
59                block.ident = ident.as_ref().to_string();
60            }
61        } else {
62            util::increase_key(&mut self.key, &ident);
63            for block in &mut self.blocks {
64                util::increase_key(&mut block.key, &ident);
65            }
66        }
67    }
68
69    pub fn reduce(sections: &mut Vec<Section>) {
70        let mut map: HashMap<String, &mut Section> = HashMap::new();
71        let mut dup = Vec::new();
72        for (i, section) in sections.iter_mut().enumerate() {
73            if let Some(s) = map.get_mut(&section.key) {
74                s.blocks.append(&mut section.blocks);
75                dup.push(i);
76            } else {
77                map.insert(section.key.clone(), section);
78            }
79        }
80        for (i, index) in dup.iter().enumerate() {
81            sections.remove(index - i);
82        }
83    }
84
85    pub fn render(&self) -> Result<String, Error> {
86        if self.is_none_skipped() {
87            return Ok(String::new());
88        }
89        let comment = self.comment();
90        let text = comment.render()?;
91        let mut lines = Vec::new();
92        if !self.meta.config.is_comment_hidden() {
93            lines.push(text);
94        }
95        let (left, right) = if self.is_root() {
96            ("".to_string(), "".to_string())
97        } else if self.meta.is_array {
98            ("[[".to_string(), "]]".to_string())
99        } else {
100            ("[".to_string(), "]".to_string())
101        };
102        let bang = if self.is_commented() && (self.key != ROOT_KEY) {
103            BANG_COMMENT
104        } else {
105            ""
106        };
107        lines.push(format!("{bang}{}{}{}", left, self.key, right));
108        for block in &self.blocks {
109            let line = block.render()?;
110            if !line.is_empty() {
111                lines.push(line);
112            }
113        }
114        Ok(lines.join("\n"))
115    }
116
117    pub fn comment(&self) -> Comment {
118        let mut comment = self.meta.comment();
119        comment.comment_type = if self.is_root() {
120            CommentType::Root
121        } else {
122            CommentType::Section
123        };
124        comment
125    }
126}