arch_pkg_text/srcinfo/query/
forgetful.rs

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