1mod checksums;
2mod data;
3
4use super::{ParseWithIssues, PartialParse, PartialParseResult};
5use crate::{
6 srcinfo::{
7 Field, FieldName, ParsedField, RawField, Section,
8 misc::{ReuseAdvice, True},
9 utils::{non_blank_trimmed_lines, parse_line},
10 },
11 value,
12};
13use derive_more::{Display, Error};
14use indexmap::IndexMap;
15use pipe_trait::Pipe;
16
17pub use data::{
18 ParsedSrcinfoBaseSection, ParsedSrcinfoBaseUniqueFieldDuplicationError,
19 ParsedSrcinfoDerivativeSection, ParsedSrcinfoDerivativeUniqueFieldDuplicationError,
20};
21
22#[derive(Debug, Default, Clone)]
24pub struct ParsedSrcinfo<'a> {
25 pub base: ParsedSrcinfoBaseSection<'a>,
27 pub derivatives: IndexMap<value::Name<'a>, ParsedSrcinfoDerivativeSection<'a>>,
29}
30
31enum ParsedSrcinfoSectionMut<'a, 'r> {
33 Base(&'r mut ParsedSrcinfoBaseSection<'a>),
35 Derivative(ParsedSrcinfoDerivativeSectionEntryMut<'a, 'r>),
37}
38
39impl<'a> ParsedSrcinfo<'a> {
40 fn get_or_insert(&mut self, section: Section<'a>) -> ParsedSrcinfoSectionMut<'a, '_> {
42 match section {
43 Section::Base => self.base.pipe_mut(ParsedSrcinfoSectionMut::Base),
44 Section::Derivative(name) => self
45 .derivatives
46 .entry(name)
47 .or_default()
48 .pipe(|data| ParsedSrcinfoDerivativeSectionEntryMut::new(name, data))
49 .pipe(ParsedSrcinfoSectionMut::Derivative),
50 }
51 }
52}
53
54enum AddFailure<'a> {
56 MeetHeader(value::Name<'a>),
58 Issue(SrcinfoParseIssue<'a>),
60}
61
62fn unknown_field_from_parsed(field: ParsedField<&str>) -> Result<(), AddFailure<'_>> {
64 Field::blank()
65 .with_name(field.name_str())
66 .with_architecture(field.architecture_str())
67 .pipe(SrcinfoParseIssue::UnknownField)
68 .pipe(AddFailure::Issue)
69 .pipe(Err)
70}
71
72impl<'a> ParsedSrcinfoSectionMut<'a, '_> {
73 fn add(&mut self, field: ParsedField<&'a str>, value: &'a str) -> Result<(), AddFailure<'a>> {
75 match self {
76 ParsedSrcinfoSectionMut::Base(section) => section.add(field, value),
77 ParsedSrcinfoSectionMut::Derivative(section) => section.add(field, value),
78 }
79 }
80
81 fn shrink_to_fit(&mut self) {
83 match self {
84 ParsedSrcinfoSectionMut::Base(section) => section.shrink_to_fit(),
85 ParsedSrcinfoSectionMut::Derivative(section) => section.shrink_to_fit(),
86 }
87 }
88}
89
90impl<'a> ParsedSrcinfoBaseSection<'a> {
91 fn add_value_to_option<Value: Copy>(
93 target: &mut Option<Value>,
94 value: &'a str,
95 make_value: impl FnOnce(&'a str) -> Value,
96 make_error: impl FnOnce(Value) -> ParsedSrcinfoBaseUniqueFieldDuplicationError<'a>,
97 ) -> Result<(), AddFailure<'a>> {
98 let Some(old_value) = target else {
99 *target = Some(make_value(value));
100 return Ok(());
101 };
102 (*old_value)
103 .pipe(make_error)
104 .pipe(SrcinfoParseIssue::BaseUniqueFieldDuplication)
105 .pipe(AddFailure::Issue)
106 .pipe(Err)
107 }
108}
109
110struct ParsedSrcinfoDerivativeSectionEntryMut<'a, 'r> {
112 name: value::Name<'a>,
113 data: &'r mut ParsedSrcinfoDerivativeSection<'a>,
114}
115
116impl<'a, 'r> ParsedSrcinfoDerivativeSectionEntryMut<'a, 'r> {
117 fn new(name: value::Name<'a>, data: &'r mut ParsedSrcinfoDerivativeSection<'a>) -> Self {
119 ParsedSrcinfoDerivativeSectionEntryMut { name, data }
120 }
121
122 fn add_value_to_option<Value: Copy>(
124 name: value::Name<'a>,
125 target: &mut Option<Value>,
126 value: &'a str,
127 make_value: impl FnOnce(&'a str) -> Value,
128 make_error: impl FnOnce(Value) -> ParsedSrcinfoDerivativeUniqueFieldDuplicationError<'a>,
129 ) -> Result<(), AddFailure<'a>> {
130 let Some(old_value) = target else {
131 *target = Some(make_value(value));
132 return Ok(());
133 };
134 (*old_value)
135 .pipe(make_error)
136 .pipe(move |error| SrcinfoParseIssue::DerivativeUniqueFieldDuplication(name, error))
137 .pipe(AddFailure::Issue)
138 .pipe(Err)
139 }
140
141 fn shrink_to_fit(&mut self) {
143 self.data.shrink_to_fit()
144 }
145}
146
147#[derive(Debug, Display, Error, Clone, Copy)]
149pub enum SrcinfoParseError<'a> {
150 #[display("Failed to insert value to the pkgbase section: {_0}")]
151 BaseUniqueFieldDuplication(
152 #[error(not(source))] ParsedSrcinfoBaseUniqueFieldDuplicationError<'a>,
153 ),
154 #[display("Failed to insert value to the pkgname section named {_0}: {_1}")]
155 DerivativeUniqueFieldDuplication(
156 value::Name<'a>,
157 ParsedSrcinfoDerivativeUniqueFieldDuplicationError<'a>,
158 ),
159 #[display("Invalid line: {_0:?}")]
160 InvalidLine(#[error(not(source))] &'a str),
161}
162
163pub type SrcinfoParseReturn<'a> = PartialParseResult<ParsedSrcinfo<'a>, SrcinfoParseError<'a>>;
165
166#[derive(Debug, Clone, Copy)]
168pub enum SrcinfoParseIssue<'a> {
169 UnknownField(RawField<'a>),
170 BaseUniqueFieldDuplication(ParsedSrcinfoBaseUniqueFieldDuplicationError<'a>),
171 DerivativeUniqueFieldDuplication(
172 value::Name<'a>,
173 ParsedSrcinfoDerivativeUniqueFieldDuplicationError<'a>,
174 ),
175 InvalidLine(&'a str),
176}
177
178impl<'a> SrcinfoParseIssue<'a> {
179 pub fn ignore_unknown_field(self) -> Result<(), SrcinfoParseError<'a>> {
184 Err(match self {
185 SrcinfoParseIssue::UnknownField(_) => return Ok(()),
186 SrcinfoParseIssue::BaseUniqueFieldDuplication(error) => {
187 SrcinfoParseError::BaseUniqueFieldDuplication(error)
188 }
189 SrcinfoParseIssue::DerivativeUniqueFieldDuplication(name, error) => {
190 SrcinfoParseError::DerivativeUniqueFieldDuplication(name, error)
191 }
192 SrcinfoParseIssue::InvalidLine(line) => SrcinfoParseError::InvalidLine(line),
193 })
194 }
195}
196
197impl<'a> ParsedSrcinfo<'a> {
198 pub fn parse(text: &'a str) -> SrcinfoParseReturn<'a> {
200 ParsedSrcinfo::parse_with_issues(text, SrcinfoParseIssue::ignore_unknown_field)
201 }
202
203 pub fn parse_with_issues<HandleIssue, Error>(
205 text: &'a str,
206 mut handle_issue: HandleIssue,
207 ) -> PartialParseResult<ParsedSrcinfo<'a>, Error>
208 where
209 HandleIssue: FnMut(SrcinfoParseIssue<'a>) -> Result<(), Error>,
210 {
211 let mut parsed = ParsedSrcinfo::default();
212 let lines = non_blank_trimmed_lines(text);
213 let mut section_mut = parsed.get_or_insert(Section::Base);
214
215 macro_rules! return_or_continue {
216 ($issue:expr) => {
217 match handle_issue($issue) {
218 Err(error) => return PartialParseResult::new_partial(parsed, error),
219 Ok(()) => continue,
220 }
221 };
222 }
223
224 for line in lines {
225 let Some((field, value)) = parse_line(line) else {
226 return_or_continue!(SrcinfoParseIssue::InvalidLine(line));
227 };
228 let Ok(field) = field.to_parsed::<FieldName, &str>() else {
229 return_or_continue!(SrcinfoParseIssue::UnknownField(field));
230 };
231 if value.is_empty() {
232 continue;
233 }
234 match section_mut.add(field, value) {
235 Ok(()) => {}
236 Err(AddFailure::MeetHeader(name)) => {
237 section_mut.shrink_to_fit();
238 section_mut = parsed.get_or_insert(Section::Derivative(name));
239 }
240 Err(AddFailure::Issue(issue)) => {
241 return_or_continue!(issue);
242 }
243 }
244 }
245
246 PartialParseResult::new_complete(parsed)
247 }
248}
249
250impl<'a> PartialParse<&'a str> for ParsedSrcinfo<'a> {
251 type Error = SrcinfoParseError<'a>;
252 fn partial_parse(input: &'a str) -> PartialParseResult<Self, Self::Error> {
253 ParsedSrcinfo::parse(input)
254 }
255}
256
257impl<'a, HandleIssue, Error> ParseWithIssues<&'a str, HandleIssue, Error> for ParsedSrcinfo<'a>
258where
259 HandleIssue: FnMut(SrcinfoParseIssue<'a>) -> Result<(), Error>,
260{
261 fn parse_with_issues(
262 input: &'a str,
263 handle_issue: HandleIssue,
264 ) -> PartialParseResult<Self, Error> {
265 ParsedSrcinfo::parse_with_issues(input, handle_issue)
266 }
267}
268
269impl<'a> TryFrom<&'a str> for ParsedSrcinfo<'a> {
271 type Error = SrcinfoParseError<'a>;
273 fn try_from(text: &'a str) -> Result<Self, Self::Error> {
275 ParsedSrcinfo::parse(text).try_into_complete()
276 }
277}
278
279impl ReuseAdvice for ParsedSrcinfo<'_> {
280 type ShouldReuse = True;
285}