arch-pkg-text 0.10.0

Pure Rust library to parse Arch Linux packages' structured text formats
Documentation
use core::convert::Infallible;

use super::{Query, QueryMut};
use crate::{
    desc::{
        field::{ParsedField, RawField},
        misc::{False, ReuseAdvice},
    },
    parse::{ParseWithIssues, PartialParse, PartialParseResult},
};
use pipe_trait::Pipe;

/// [Query] without a cache.
#[derive(Debug, Clone, Copy)]
pub struct ForgetfulQuerier<'a>(&'a str);

impl<'a> ForgetfulQuerier<'a> {
    /// Query the `text` without cache.
    pub const fn new(text: &'a str) -> Self {
        ForgetfulQuerier(text)
    }
}

impl<'a> Query<'a> for ForgetfulQuerier<'a> {
    fn query_raw_text(&self, field: ParsedField) -> Option<&'a str> {
        let mut lines_with_end_offset = self.0.lines().map(|line| {
            (
                line,
                line.as_ptr() as usize + line.len() - self.0.as_ptr() as usize,
            )
        });

        let (_, value_start_offset) = lines_with_end_offset.find(|(line, _)| {
            line.trim()
                .pipe(RawField::try_from)
                .ok()
                .map(|x| x.name_str() == field.name_str())
                .unwrap_or(false)
        })?;

        let (_, value_end_offset) = lines_with_end_offset
            .take_while(|(line, _)| RawField::try_from(line.trim()).is_err())
            .last()?; // no last means empty iterator, which means no content

        let value = self.0[value_start_offset..value_end_offset].trim();

        if value.is_empty() { None } else { Some(value) }
    }
}

impl<'a> QueryMut<'a> for ForgetfulQuerier<'a> {
    fn query_raw_text_mut(&mut self, field: ParsedField) -> Option<&'a str> {
        self.query_raw_text(field)
    }
}

impl ReuseAdvice for ForgetfulQuerier<'_> {
    /// Whilst [`ForgetfulQuerier`] costs nothing to construct, performing a
    /// lookup on it costs O(n) time complexity (n being text length).
    ///
    /// This struct is best used to lookup once.
    type ShouldReuse = False;
}

impl<'a> From<&'a str> for ForgetfulQuerier<'a> {
    fn from(value: &'a str) -> Self {
        ForgetfulQuerier::new(value)
    }
}

impl<'a> PartialParse<&'a str> for ForgetfulQuerier<'a> {
    type Error = Infallible;
    fn partial_parse(text: &'a str) -> PartialParseResult<Self, Self::Error> {
        ForgetfulQuerier::parse_with_issues(text, ())
    }
}

impl<'a, HandleIssue, Error> ParseWithIssues<&'a str, HandleIssue, Error> for ForgetfulQuerier<'a> {
    fn parse_with_issues(text: &'a str, _: HandleIssue) -> PartialParseResult<Self, Error> {
        text.pipe(ForgetfulQuerier::new)
            .pipe(PartialParseResult::new_complete)
    }
}