arch_pkg_text/srcinfo/query/
forgetful.rs

1use super::{
2    utils::{non_blank_trimmed_lines, parse_line},
3    ChecksumValue, Checksums, ChecksumsMut, EncourageReuse, Query, QueryChecksumItem, QueryMut,
4    QueryRawTextItem, Section,
5};
6use crate::{
7    srcinfo::field::{FieldName, ParsedField, RawField},
8    value::{Architecture, Name},
9};
10use iter_scan::IterScan;
11use pipe_trait::Pipe;
12
13/// [Query] without a cache.
14#[derive(Debug, Clone, Copy)]
15pub struct ForgetfulQuerier<'a>(&'a str);
16
17impl<'a> ForgetfulQuerier<'a> {
18    /// Query the `text` without cache.
19    pub const fn new(text: &'a str) -> Self {
20        ForgetfulQuerier(text)
21    }
22
23    /// List all items of known fields.
24    fn all_known_items(
25        &self,
26    ) -> impl Iterator<Item = (Section<'a>, (ParsedField<&'a str>, &'a str))> {
27        self.0
28            .pipe(non_blank_trimmed_lines)
29            .map_while(parse_line)
30            .filter_map(known_field)
31            .filter(|(_, value)| !value.is_empty())
32            .scan_state_copy(Section::Base, scan_section)
33    }
34}
35
36impl<'a> Query<'a> for ForgetfulQuerier<'a> {
37    fn query_raw_text(&self, field_name: FieldName) -> impl Iterator<Item = QueryRawTextItem<'a>> {
38        self.all_known_items()
39            .filter(move |(_, (field, _))| *field.name() == field_name)
40            .map(|(section, (field, value))| {
41                QueryRawTextItem::from_tuple3((
42                    value,
43                    section,
44                    field.architecture_str().map(Architecture::new),
45                ))
46            })
47    }
48}
49
50impl<'a> QueryMut<'a> for ForgetfulQuerier<'a> {
51    fn query_raw_text_mut(
52        &mut self,
53        field_name: FieldName,
54    ) -> impl Iterator<Item = QueryRawTextItem<'a>> {
55        self.query_raw_text(field_name)
56    }
57}
58
59impl<'a> Checksums<'a> for ForgetfulQuerier<'a> {
60    fn checksums(&self) -> impl Iterator<Item = QueryChecksumItem<'a>> {
61        self.all_known_items()
62            .filter_map(|(section, (field, value))| {
63                ChecksumValue::try_from_field_name(*field.name(), value)
64                    .map(|value| (value, section, field.architecture_str().map(Architecture)))
65            })
66            .map(QueryChecksumItem::from_tuple3)
67    }
68}
69
70impl<'a> ChecksumsMut<'a> for ForgetfulQuerier<'a> {
71    fn checksums_mut(&mut self) -> impl Iterator<Item = QueryChecksumItem<'a>> {
72        self.checksums()
73    }
74}
75
76/// Callback function to pass to `.filter_map` to filter out unknown fields.
77fn known_field<'a, Architecture, Acquaintance>(
78    (field, acquaintance): (RawField<'a>, Acquaintance),
79) -> Option<(ParsedField<Architecture>, Acquaintance)>
80where
81    &'a str: TryInto<Architecture>,
82{
83    field
84        .to_parsed::<FieldName, Architecture>()
85        .map(|field| (field, acquaintance))
86        .ok()
87}
88
89/// Callback function to pass to `.scan_state_*` to attach sections to items.
90fn scan_section<'a>(
91    section: Section<'a>,
92    (field, value): (ParsedField<&'a str>, &'a str),
93) -> (Section<'a>, (ParsedField<&'a str>, &'a str)) {
94    match field.name() {
95        FieldName::Name => (Section::Derivative(Name(value)), (field, value)),
96        _ => (section, (field, value)),
97    }
98}
99
100impl EncourageReuse for ForgetfulQuerier<'_> {
101    /// Whilst [`ForgetfulQuerier`] costs nothing to construct, performing a
102    /// lookup on it costs O(n) time complexity (n being text length).
103    ///
104    /// This struct is best used to lookup once.
105    const ENCOURAGE_REUSE: bool = false;
106}