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