arch_pkg_text/desc/query/
memo.rs1use super::QueryMut;
2use crate::desc::field::{FieldName, ParsedField, RawField};
3
4#[derive(Debug, Clone)]
6pub struct MemoQuerier<'a> {
7 text: &'a str,
8 cache: Cache<'a>,
9 last: Option<(&'a str, RawField<'a>)>,
10}
11
12impl<'a> MemoQuerier<'a> {
13 pub fn new(text: &'a str) -> Self {
15 MemoQuerier {
16 text,
17 cache: Cache::default(),
18 last: None,
19 }
20 }
21
22 fn next_entry(&mut self) -> Option<(RawField<'a>, &'a str)> {
24 let mut lines = self.text.lines();
25
26 let (field_str, raw_field) = if let Some((field_str, raw_field)) = self.last {
27 lines.next()?;
28 (field_str, raw_field)
29 } else {
30 let field_str = lines.next()?.trim();
31 let raw_field = RawField::parse_raw(field_str).ok()?;
32 (field_str, raw_field)
33 };
34
35 let value_start_offset =
36 field_str.as_ptr() as usize + field_str.len() - self.text.as_ptr() as usize;
37 let next = lines.find_map(|line| -> Option<(&'a str, RawField<'a>)> {
38 let field_str = line.trim();
39 let raw_field = RawField::parse_raw(field_str).ok()?;
40 Some((field_str, raw_field))
41 });
42
43 let Some((next_field_str, next_raw_field)) = next else {
44 let value = self.text[value_start_offset..].trim_matches(['\n', '\r']);
45 self.text = "";
46 self.last = None;
47 return Some((raw_field, value));
48 };
49
50 let value_end_offset = next_field_str.as_ptr() as usize - self.text.as_ptr() as usize;
51 let value = self.text[value_start_offset..value_end_offset].trim_matches(['\n', '\r']);
52
53 self.last = Some((next_field_str, next_raw_field));
55 self.text = &self.text[value_end_offset..];
56
57 Some((raw_field, value))
58 }
59
60 #[doc(hidden)]
62 pub fn __has_cache(&self, field: FieldName) -> bool {
63 self.cache.get(&field).is_some()
64 }
65}
66
67impl<'a> QueryMut<'a> for MemoQuerier<'a> {
68 fn query_raw_text_mut(&mut self, field: ParsedField) -> Option<&'a str> {
69 if let Some(value) = self.cache.get(field.name()) {
70 return value;
71 }
72
73 while let Some((raw_field, value)) = self.next_entry() {
74 let Ok(parsed_field) = raw_field.to_parsed::<FieldName>() else {
75 continue;
76 };
77 let value = if value.is_empty() { None } else { Some(value) };
78 self.cache.add(&parsed_field, value);
79 if parsed_field == field {
80 return value;
81 }
82 }
83
84 None
85 }
86}
87
88macro_rules! def_cache {
89 ($(
90 $(#[$attrs:meta])*
91 $field:ident $(,)? $(;)?
92 )*) => {
93 #[derive(Debug, Clone, Copy)]
94 enum CacheErr {
95 OccupiedWithNone,
96 Unoccupied,
97 }
98
99 #[derive(Debug, Clone)]
100 #[allow(non_snake_case, reason = "We don't access the field names directly, keep it simple.")]
101 struct Cache<'a> {$(
102 $(#[$attrs])*
103 $field: Result<&'a str, CacheErr>, )*}
105
106 impl<'a> Cache<'a> {
107 fn get(&self, field: &FieldName) -> Option<Option<&'a str>> {
108 match field {$(
109 FieldName::$field => match self.$field {
110 Ok(value) => Some(Some(value)),
111 Err(CacheErr::OccupiedWithNone) => Some(None),
112 Err(CacheErr::Unoccupied) => None,
113 },
114 )*}
115 }
116
117 fn add(&mut self, field: &FieldName, value: Option<&'a str>) {
118 match (field, value) {$(
119 (FieldName::$field, Some(value)) => self.$field = Ok(value),
120 (FieldName::$field, None) => self.$field = Err(CacheErr::OccupiedWithNone),
121 )*}
122 }
123 }
124
125 impl<'a> Default for Cache<'a> {
126 fn default() -> Self {
127 Cache {$(
128 $field: Err(CacheErr::Unoccupied),
129 )*}
130 }
131 }
132
133 #[test]
134 fn test_cache_fields() {$({
135 use pretty_assertions::assert_eq;
136 let field = &FieldName::$field;
137 let mut cache = Cache::default();
138 assert_eq!(cache.get(field), None);
139 cache.add(field, None);
140 assert_eq!(cache.get(field), Some(None));
141 cache.add(field, Some("foo"));
142 assert_eq!(cache.get(field), Some(Some("foo")));
143 })*}
144 };
145}
146
147def_cache!(
148 FileName Name Base Version Description Groups
149 CompressedSize InstalledSize Md5Checksum Sha256Checksum
150 PgpSignature Url License Architecture BuildDate Packager
151 Dependencies CheckDependencies MakeDependencies OptionalDependencies
152 Provides Conflicts Replaces
153);