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