arch_pkg_db/single/
insert.rs

1use super::QueryDatabase;
2use arch_pkg_text::{
3    desc::{Query, QueryMut},
4    misc::desc::ShouldReuse,
5    value::{Name, ParseVersionError, Version},
6};
7use core::mem::replace;
8use derive_more::{Display, Error};
9use pipe_trait::Pipe;
10
11/// Error type of [`QueryDatabase::insert`] and [`QueryDatabase::insert_mut`].
12#[derive(Debug, Display, Clone, Copy, Error)]
13pub enum InsertError {
14    #[display("Querier could not provide a name")]
15    NoName,
16}
17
18impl<'a, Querier: ShouldReuse> QueryDatabase<'a, Querier> {
19    /// Add a querier of a `desc` file to the database.
20    ///
21    /// If an older querier already occupied the same [name](arch_pkg_text::value::Name), it will be returned inside `Ok(Some(_))`.
22    fn insert_with<GetName>(
23        &mut self,
24        mut querier: Querier,
25        get_name: GetName,
26    ) -> Result<Option<Querier>, InsertError>
27    where
28        GetName: FnOnce(&mut Querier) -> Option<Name<'a>>,
29    {
30        let name = get_name(&mut querier).ok_or(InsertError::NoName)?;
31        self.internal.insert(&name, querier).pipe(Ok)
32    }
33
34    /// Add an [immutable querier](Query) of a `desc` file to the database.
35    ///
36    /// If an older querier already occupied the same [name](arch_pkg_text::value::Name), it will be returned inside `Ok(Some(_))`.
37    pub fn insert(&mut self, querier: Querier) -> Result<Option<Querier>, InsertError>
38    where
39        Querier: Query<'a>,
40    {
41        self.insert_with(querier, |querier| querier.name())
42    }
43
44    /// Add a [mutable querier](QueryMut) of a `desc` file to the database.
45    ///
46    /// If an older querier already occupied the same [name](arch_pkg_text::value::Name), it will be returned inside `Ok(Some(_))`.
47    pub fn insert_mut(&mut self, querier: Querier) -> Result<Option<Querier>, InsertError>
48    where
49        Querier: QueryMut<'a>,
50    {
51        self.insert_with(querier, Querier::name_mut)
52    }
53}
54
55/// Return type of [`QueryDatabase::insert_newer`] and [`QueryDatabase::insert_newer_mut`] upon success.
56#[derive(Debug, Clone, Copy)]
57pub enum InsertNewerReturn<Querier> {
58    /// The entry was unoccupied, the querier was successfully inserted.
59    Unoccupied,
60    /// The entry was occupied by a querier whose package version is older than the provided querier.
61    /// The provided querier thus replaced the old one.
62    Replaced(Querier),
63    /// The entry was occupied by a querier whose package version is not older than the provided querier.
64    /// The occupied querier was kept, the provided querier was rejected.
65    Rejected(Querier),
66}
67
68/// Error type of [`QueryDatabase::insert_newer`] and [`QueryDatabase::insert_newer_mut`].
69#[derive(Debug, Display, Error)]
70pub enum InsertNewerError<'a> {
71    #[display("Querier could not provide a name")]
72    NoName,
73    #[display("Querier could not provide a version")]
74    NoVersion,
75    #[display("Version provided by the querier has invalid syntax: {_0}")]
76    InvalidVersion(#[error(not(source))] ParseVersionError<'a>),
77}
78
79impl<'a, Querier: ShouldReuse> QueryDatabase<'a, Querier> {
80    /// Add a querier of a `desc` file to the database unless the entry was already occupied by a querier whose
81    /// [package version](arch_pkg_text::value::Version) is not older than the provided querier.
82    fn insert_newer_with<GetName, GetVersion>(
83        &mut self,
84        mut querier: Querier,
85        get_name: GetName,
86        mut get_version: GetVersion,
87    ) -> Result<InsertNewerReturn<Querier>, InsertNewerError<'a>>
88    where
89        GetName: FnOnce(&mut Querier) -> Option<Name<'a>>,
90        GetVersion: FnMut(&mut Querier) -> Option<Version<'a>>,
91    {
92        let name = get_name(&mut querier).ok_or(InsertNewerError::NoName)?;
93        let Some(existing) = self.internal.get_mut(name.as_str()) else {
94            self.internal.insert(&name, querier);
95            return Ok(InsertNewerReturn::Unoccupied);
96        };
97
98        let existing_version = existing
99            .pipe_mut(&mut get_version)
100            .ok_or(InsertNewerError::NoVersion)?
101            .parse()
102            .map_err(InsertNewerError::InvalidVersion)?;
103        let inserted_version = querier
104            .pipe_mut(&mut get_version)
105            .ok_or(InsertNewerError::NoVersion)?
106            .parse()
107            .map_err(InsertNewerError::InvalidVersion)?;
108
109        Ok(if existing_version < inserted_version {
110            InsertNewerReturn::Replaced(replace(existing, querier))
111        } else {
112            InsertNewerReturn::Rejected(querier)
113        })
114    }
115
116    /// Add an [immutable querier](Query) of a `desc` file to the database unless the entry was already occupied by a querier whose
117    /// [package version](arch_pkg_text::value::Version) is not older than the provided querier.
118    pub fn insert_newer(
119        &mut self,
120        querier: Querier,
121    ) -> Result<InsertNewerReturn<Querier>, InsertNewerError<'a>>
122    where
123        Querier: Query<'a>,
124    {
125        self.insert_newer_with(
126            querier,
127            |querier| querier.name(),
128            |querier| querier.version(),
129        )
130    }
131
132    /// Add a [mutable querier](QueryMut) of a `desc` file to the database unless the entry was already occupied by a querier whose
133    /// [package version](arch_pkg_text::value::Version) is not older than the provided querier.
134    pub fn insert_newer_mut(
135        &mut self,
136        querier: Querier,
137    ) -> Result<InsertNewerReturn<Querier>, InsertNewerError<'a>>
138    where
139        Querier: QueryMut<'a>,
140    {
141        self.insert_newer_with(querier, Querier::name_mut, Querier::version_mut)
142    }
143}