arch_pkg_text/srcinfo/query/
memo.rs1mod cache;
2
3use super::{
4 ChecksumType, ChecksumValue, ChecksumsMut, QueryChecksumItem, QueryMut, QueryRawTextItem,
5 Section,
6 utils::{parse_line, trimmed_line_is_blank},
7};
8use crate::{
9 parse::{ParseWithIssues, PartialParse, PartialParseResult},
10 srcinfo::{
11 field::FieldName,
12 misc::{ReuseAdvice, True},
13 },
14 value::{Architecture, Name},
15};
16use cache::Cache;
17use core::convert::Infallible;
18use core::str::Lines;
19use pipe_trait::Pipe;
20
21#[derive(Debug, Clone)]
23pub struct MemoQuerier<'a> {
24 remaining_lines: Lines<'a>,
25 current_section: Section<'a>,
26 cache: Cache<'a>,
27}
28
29impl<'a> MemoQuerier<'a> {
30 pub fn new(srcinfo: &'a str) -> Self {
32 MemoQuerier {
33 remaining_lines: srcinfo.lines(),
34 current_section: Section::Base,
35 cache: Cache::default(),
36 }
37 }
38
39 pub fn shrink_cache_to_fit(&mut self) {
41 self.cache.shrink_to_fit();
42 }
43
44 #[doc(hidden)]
46 pub fn __has_cache(&self, field_name: FieldName, index: usize) -> bool {
47 self.cache.get(field_name, index).is_some()
48 }
49
50 fn next_entry(&mut self) -> Option<(FieldName, QueryRawTextItem<'a>)> {
52 let line = self.remaining_lines.next()?.trim();
53 if trimmed_line_is_blank(line) {
54 return self.next_entry();
55 }
56 let (raw_field, value) = parse_line(line)?;
57 let Ok(field) = raw_field.to_parsed::<FieldName, &str>() else {
58 return self.next_entry();
59 };
60 if value.is_empty() {
61 return self.next_entry();
62 }
63 let architecture = field.architecture_str().map(Architecture);
64 if *field.name() == FieldName::Name && architecture.is_none() {
65 self.current_section = value.pipe(Name).pipe(Section::Derivative);
66 }
67 let item = QueryRawTextItem::from_tuple3((value, self.current_section, architecture));
68 self.cache.add(*field.name(), item);
69 Some((*field.name(), item))
70 }
71}
72
73struct QueryIter<'a, 'r> {
75 querier: &'r mut MemoQuerier<'a>,
76 field_name: FieldName,
77 index: usize,
78}
79
80impl<'a, 'r> QueryIter<'a, 'r> {
81 fn new(querier: &'r mut MemoQuerier<'a>, field_name: FieldName) -> Self {
83 QueryIter {
84 querier,
85 field_name,
86 index: 0,
87 }
88 }
89}
90
91impl<'a> Iterator for QueryIter<'a, '_> {
92 type Item = QueryRawTextItem<'a>;
93 fn next(&mut self) -> Option<Self::Item> {
94 let QueryIter {
95 querier,
96 field_name,
97 index,
98 } = self;
99 loop {
100 if let Some(item) = querier.cache.get(*field_name, *index) {
101 *index += 1;
102 return Some(item);
103 } else {
104 querier.next_entry()?;
105 continue;
106 }
107 }
108 }
109}
110
111impl<'a> QueryMut<'a> for MemoQuerier<'a> {
112 fn query_raw_text_mut(
113 &mut self,
114 field_name: FieldName,
115 ) -> impl Iterator<Item = QueryRawTextItem<'a>> {
116 QueryIter::new(self, field_name)
117 }
118}
119
120struct ChecksumIter<'a, 'r> {
122 querier: &'r mut MemoQuerier<'a>,
123 checksum_type_id: usize,
124 checksum_index: usize,
125}
126
127impl<'a, 'r> ChecksumIter<'a, 'r> {
128 fn new(querier: &'r mut MemoQuerier<'a>) -> Self {
130 ChecksumIter {
131 querier,
132 checksum_type_id: 0,
133 checksum_index: 0,
134 }
135 }
136}
137
138impl<'a> Iterator for ChecksumIter<'a, '_> {
139 type Item = QueryChecksumItem<'a>;
140 fn next(&mut self) -> Option<Self::Item> {
141 let ChecksumIter {
142 querier,
143 checksum_type_id,
144 checksum_index,
145 } = self;
146 loop {
147 let checksum_type = *ChecksumType::TYPES.get(*checksum_type_id)?;
148 let field_name = checksum_type.into_field_name();
149 if let Some(item) = querier.cache.get(field_name, *checksum_index) {
150 *checksum_index += 1;
151 return item
152 .map(move |value| ChecksumValue::new(checksum_type, value))
153 .pipe(Some);
154 } else if querier.next_entry().is_none() {
155 *checksum_type_id += 1;
156 *checksum_index = 0;
157 }
158 }
159 }
160}
161
162impl<'a> ChecksumsMut<'a> for MemoQuerier<'a> {
163 fn checksums_mut(&mut self) -> impl Iterator<Item = QueryChecksumItem<'a>> {
164 ChecksumIter::new(self)
165 }
166}
167
168impl ReuseAdvice for MemoQuerier<'_> {
169 type ShouldReuse = True;
174}
175
176impl<'a> From<&'a str> for MemoQuerier<'a> {
177 fn from(value: &'a str) -> Self {
178 MemoQuerier::new(value)
179 }
180}
181
182impl<'a> PartialParse<&'a str> for MemoQuerier<'a> {
183 type Error = Infallible;
184 fn partial_parse(text: &'a str) -> PartialParseResult<Self, Self::Error> {
185 MemoQuerier::parse_with_issues(text, ())
186 }
187}
188
189impl<'a, HandleIssue, Error> ParseWithIssues<&'a str, HandleIssue, Error> for MemoQuerier<'a> {
190 fn parse_with_issues(text: &'a str, _: HandleIssue) -> PartialParseResult<Self, Error> {
191 text.pipe(MemoQuerier::new)
192 .pipe(PartialParseResult::new_complete)
193 }
194}