arch_pkg_text/desc/query/
forgetful.rs

1use core::convert::Infallible;
2
3use super::{Query, QueryMut};
4use crate::{
5    desc::{
6        field::{ParsedField, RawField},
7        misc::{False, ReuseAdvice},
8    },
9    parse::{ParseWithIssues, PartialParse, PartialParseResult},
10};
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
24impl<'a> Query<'a> for ForgetfulQuerier<'a> {
25    fn query_raw_text(&self, field: ParsedField) -> Option<&'a str> {
26        let mut lines_with_end_offset = self.0.lines().map(|line| {
27            (
28                line,
29                line.as_ptr() as usize + line.len() - self.0.as_ptr() as usize,
30            )
31        });
32
33        let (_, value_start_offset) = lines_with_end_offset.find(|(line, _)| {
34            line.trim()
35                .pipe(RawField::try_from)
36                .ok()
37                .map(|x| x.name_str() == field.name_str())
38                .unwrap_or(false)
39        })?;
40
41        let (_, value_end_offset) = lines_with_end_offset
42            .take_while(|(line, _)| RawField::try_from(line.trim()).is_err())
43            .last()?; // no last means empty iterator, which means no content
44
45        let value = self.0[value_start_offset..value_end_offset].trim_matches(['\n', '\r']);
46
47        if value.is_empty() { None } else { Some(value) }
48    }
49}
50
51impl<'a> QueryMut<'a> for ForgetfulQuerier<'a> {
52    fn query_raw_text_mut(&mut self, field: ParsedField) -> Option<&'a str> {
53        self.query_raw_text(field)
54    }
55}
56
57impl ReuseAdvice for ForgetfulQuerier<'_> {
58    /// Whilst [`ForgetfulQuerier`] costs nothing to construct, performing a
59    /// lookup on it costs O(n) time complexity (n being text length).
60    ///
61    /// This struct is best used to lookup once.
62    type ShouldReuse = False;
63}
64
65impl<'a> From<&'a str> for ForgetfulQuerier<'a> {
66    fn from(value: &'a str) -> Self {
67        ForgetfulQuerier::new(value)
68    }
69}
70
71impl<'a> PartialParse<&'a str> for ForgetfulQuerier<'a> {
72    type Error = Infallible;
73    fn partial_parse(text: &'a str) -> PartialParseResult<Self, Self::Error> {
74        ForgetfulQuerier::parse_with_issues(text, ())
75    }
76}
77
78impl<'a, HandleIssue, Error> ParseWithIssues<&'a str, HandleIssue, Error> for ForgetfulQuerier<'a> {
79    fn parse_with_issues(text: &'a str, _: HandleIssue) -> PartialParseResult<Self, Error> {
80        text.pipe(ForgetfulQuerier::new)
81            .pipe(PartialParseResult::new_complete)
82    }
83}