gix_config/file/section/
body.rs1use std::{borrow::Cow, iter::FusedIterator, ops::Range};
2
3use bstr::{BStr, BString, ByteVec};
4
5use crate::{
6 parse::{section::ValueName, Event},
7 value::{normalize, normalize_bstr, normalize_bstring},
8};
9
10#[derive(PartialEq, Eq, Hash, PartialOrd, Ord, Clone, Debug, Default)]
12pub struct Body<'event>(pub(crate) Vec<Event<'event>>);
13
14impl<'event> Body<'event> {
16 #[must_use]
21 pub fn value(&self, value_name: impl AsRef<str>) -> Option<Cow<'_, BStr>> {
22 self.value_implicit(value_name.as_ref()).flatten()
23 }
24
25 #[must_use]
28 pub fn value_implicit(&self, value_name: &str) -> Option<Option<Cow<'_, BStr>>> {
29 let key = ValueName::from_str_unchecked(value_name);
30 let (_key_range, range) = self.key_and_value_range_by(&key)?;
31 let range = match range {
32 None => return Some(None),
33 Some(range) => range,
34 };
35 let mut concatenated = BString::default();
36
37 for event in &self.0[range] {
38 match event {
39 Event::Value(v) => {
40 return Some(Some(normalize_bstr(v.as_ref())));
41 }
42 Event::ValueNotDone(v) => {
43 concatenated.push_str(v.as_ref());
44 }
45 Event::ValueDone(v) => {
46 concatenated.push_str(v.as_ref());
47 return Some(Some(normalize_bstring(concatenated)));
48 }
49 _ => (),
50 }
51 }
52 None
53 }
54
55 #[must_use]
58 pub fn values(&self, value_name: &str) -> Vec<Cow<'_, BStr>> {
59 let key = &ValueName::from_str_unchecked(value_name);
60 let mut values = Vec::new();
61 let mut expect_value = false;
62 let mut concatenated_value = BString::default();
63
64 for event in &self.0 {
65 match event {
66 Event::SectionValueName(event_key) if event_key == key => expect_value = true,
67 Event::Value(v) if expect_value => {
68 expect_value = false;
69 values.push(normalize_bstr(v.as_ref()));
70 }
71 Event::ValueNotDone(v) if expect_value => {
72 concatenated_value.push_str(v.as_ref());
73 }
74 Event::ValueDone(v) if expect_value => {
75 expect_value = false;
76 concatenated_value.push_str(v.as_ref());
77 values.push(normalize_bstring(std::mem::take(&mut concatenated_value)));
78 }
79 _ => (),
80 }
81 }
82
83 values
84 }
85
86 pub fn value_names(&self) -> impl Iterator<Item = &ValueName<'event>> {
88 self.0.iter().filter_map(|e| match e {
89 Event::SectionValueName(k) => Some(k),
90 _ => None,
91 })
92 }
93
94 #[must_use]
96 pub fn contains_value_name(&self, value_name: &str) -> bool {
97 let key = &ValueName::from_str_unchecked(value_name);
98 self.0.iter().any(|e| {
99 matches!(e,
100 Event::SectionValueName(k) if k == key
101 )
102 })
103 }
104
105 #[must_use]
107 pub fn num_values(&self) -> usize {
108 self.0
109 .iter()
110 .filter(|e| matches!(e, Event::SectionValueName(_)))
111 .count()
112 }
113
114 #[must_use]
118 pub fn is_void(&self) -> bool {
119 self.0.is_empty()
120 }
121}
122
123impl Body<'_> {
124 pub(crate) fn as_ref(&self) -> &[Event<'_>] {
125 &self.0
126 }
127
128 pub(crate) fn key_and_value_range_by(
132 &self,
133 value_name: &ValueName<'_>,
134 ) -> Option<(Range<usize>, Option<Range<usize>>)> {
135 let mut value_range = Range::default();
136 let mut key_start = None;
137 for (i, e) in self.0.iter().enumerate().rev() {
138 match e {
139 Event::SectionValueName(k) => {
140 if k == value_name {
141 key_start = Some(i);
142 break;
143 }
144 value_range = Range::default();
145 }
146 Event::Value(_) => {
147 (value_range.start, value_range.end) = (i, i);
148 }
149 Event::ValueNotDone(_) | Event::ValueDone(_) => {
150 if value_range.end == 0 {
151 value_range.end = i;
152 } else {
153 value_range.start = i;
154 }
155 }
156 _ => (),
157 }
158 }
159 key_start.map(|key_start| {
160 #[allow(clippy::range_plus_one)]
163 let value_range = value_range.start..value_range.end + 1;
164 let key_range = key_start..value_range.end;
165 (key_range, (value_range.start != key_start + 1).then_some(value_range))
166 })
167 }
168}
169
170pub struct BodyIter<'event>(std::vec::IntoIter<Event<'event>>);
174
175impl<'event> IntoIterator for Body<'event> {
176 type Item = (ValueName<'event>, Cow<'event, BStr>);
177
178 type IntoIter = BodyIter<'event>;
179
180 fn into_iter(self) -> Self::IntoIter {
181 BodyIter(self.0.into_iter())
182 }
183}
184
185impl<'event> Iterator for BodyIter<'event> {
186 type Item = (ValueName<'event>, Cow<'event, BStr>);
187
188 fn next(&mut self) -> Option<Self::Item> {
189 let mut key = None;
190 let mut partial_value = BString::default();
191 let mut value = None;
192
193 for event in self.0.by_ref() {
194 match event {
195 Event::SectionValueName(k) => key = Some(k),
196 Event::Value(v) => {
197 value = Some(v);
198 break;
199 }
200 Event::ValueNotDone(v) => partial_value.push_str(v.as_ref()),
201 Event::ValueDone(v) => {
202 partial_value.push_str(v.as_ref());
203 value = Some(partial_value.into());
204 break;
205 }
206 _ => (),
207 }
208 }
209
210 key.zip(value.map(normalize))
211 }
212}
213
214impl FusedIterator for BodyIter<'_> {}