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