url_cleaner_engine/helpers/
profiles.rs

1//! [`Profiles`] allow for cheaply switching between common [`ParamsDiff`]s.
2
3use std::collections::HashMap;
4use std::borrow::Cow;
5
6use crate::types::*;
7use crate::util::*;
8
9use serde::{Serialize, Deserialize};
10
11impl<'a> Cleaner<'a> {
12    /// Convert the [`Cleaner`] into a [`ProfiledCleaner`] using the specified [`ProfilesConfig`].
13    pub fn with_profiles(self, profiles: ProfilesConfig) -> ProfiledCleaner<'a> {
14        ProfiledCleaner {
15            profiles: profiles.make(self.params),
16            cleaner: UnprofiledCleaner {
17                docs   : self.docs,
18                commons: self.commons,
19                actions: self.actions
20            }
21        }
22    }
23}
24
25/// A [`UnprofiledCleaner`] and [`Profiles`].
26#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
27pub struct ProfiledCleaner<'a> {
28    /// The [`UnprofiledCleaner`].
29    cleaner: UnprofiledCleaner<'a>,
30    /// The [`Profiles`].
31    profiles: Profiles<'a>
32}
33
34impl<'a> ProfiledCleaner<'a> {
35    /// Get the [`UnprofiledCleaner`].
36    pub fn cleaner(&self) -> &UnprofiledCleaner<'a> {
37        &self.cleaner
38    }
39
40    /// Get the [`Profiles`].
41    pub fn profiles(&self) -> &Profiles<'a> {
42        &self.profiles
43    }
44
45    /// Make a [`Cleaner`] borrowing each field of `self` and using the specified profile.
46    pub fn with_profile(&'a self, name: Option<&str>) -> Option<Cleaner<'a>> {
47        Some(Cleaner {
48            docs   : Cow::Borrowed(&*self.cleaner.docs),
49            params : self.profiles.get(name)?.params().borrowed(),
50            commons: Cow::Borrowed(&*self.cleaner.commons),
51            actions: Cow::Borrowed(&*self.cleaner.actions)
52        })
53    }
54}
55
56/// A [`Cleaner`] with no [`Params`], for use with [`Profiles`].
57#[derive(Debug, Clone, Default, PartialEq, Eq, Deserialize, Serialize, Suitability)]
58#[serde(deny_unknown_fields)]
59pub struct UnprofiledCleaner<'a> {
60    /// The documentation.
61    ///
62    /// Defaults to an empty [`CleanerDocs`].
63    #[serde(default, skip_serializing_if = "is_default")]
64    pub docs: Cow<'a, CleanerDocs>,
65    /// Basically functions.
66    ///
67    /// Defaults to an empty [`Commons`].
68    #[serde(default, skip_serializing_if = "is_default")]
69    pub commons: Cow<'a, Commons>,
70    /// The [`Action`]s to apply.
71    ///
72    /// Defaults to an empty [`Vec`].
73    #[serde(default, skip_serializing_if = "is_default")]
74    pub actions: Cow<'a, [Action]>
75}
76
77impl<'a> UnprofiledCleaner<'a> {
78    /// Create a new [`Self`] that [`Cow::Borrowed`]s all fields.
79    pub fn borrowed(&'a self) -> Self {
80        Self {
81            docs   : Cow::Borrowed(&*self.docs),
82            commons: Cow::Borrowed(&*self.commons),
83            actions: Cow::Borrowed(&*self.actions)
84        }
85    }
86
87    /// Make a [`Cleaner`] borrowing each field of `self` and using the specified [`Params`].
88    pub fn with_profile(&'a self, profile: &'a Profile) -> Cleaner<'a> {
89        Cleaner {
90            docs   : Cow::Borrowed(&*self.docs),
91            params : profile.params.borrowed(),
92            commons: Cow::Borrowed(&*self.commons),
93            actions: Cow::Borrowed(&*self.actions)
94        }
95    }
96}
97
98/// A default and named [`Profile`]s.
99#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
100pub struct Profiles<'a> {
101    /// The base [`Profile`].
102    base: Profile<'a>,
103    /// The [`Profile`]s.
104    profiles: HashMap<String, Profile<'a>>
105}
106
107impl<'a> Profiles<'a> {
108    /// Get an iterator over the names of the [`Profile`]s.
109    pub fn names(&self) -> impl Iterator<Item = &str> {
110        self.profiles.keys().map(String::as_str)
111    }
112
113    /// Get the specified [`Profile`].
114    pub fn get(&'a self, name: Option<&str>) -> Option<&'a Profile<'a>> {
115        match name {
116            None => Some(&self.base),
117            Some(name) => self.profiles.get(name)
118        }
119    }
120
121    /// [`Self::get`] but consumes `self` and discards everything else.
122    pub fn into_profile(mut self, name: Option<&str>) -> Option<Profile<'a>> {
123        match name {
124            None => Some(self.base),
125            Some(name) => self.profiles.remove(name)
126        }
127    }
128}
129
130/// A [`ParamsDiff`] profile.
131///
132/// Constructed by giving [`ProfilesConfig::make`] a [`Params`].
133#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
134pub struct Profile<'a> {
135    /// The [`ParamsDiff`].
136    params_diff: ParamsDiff,
137    /// The [`Params`].
138    #[serde(skip)]
139    params: Params<'a>
140}
141
142impl<'a> Profile<'a> {
143    /// Get the [`Params`].
144    pub fn params(&self) -> &Params<'a> {
145        &self.params
146    }
147
148    /// Get the [`ParamsDiff`].
149    pub fn params_diff(&self) -> &ParamsDiff {
150        &self.params_diff
151    }
152}
153
154impl From<Profile<'_>> for ParamsDiff {
155    fn from(value: Profile) -> Self {
156        value.params_diff
157    }
158}
159
160impl<'a> From<Profile<'a>> for Params<'a> {
161    fn from(value: Profile<'a>) -> Self {
162        value.params
163    }
164}
165
166/// A [`Cleaner`] and a [`ProfilesConfig`] to make a [`ProfiledCleaner`].
167#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
168#[serde(deny_unknown_fields)]
169pub struct ProfiledCleanerConfig<'a> {
170    /// The [`Cleaner`] to use.
171    pub cleaner: Cleaner<'a>,
172    /// The [`ProfilesConfig`] to use.
173    pub profiles: ProfilesConfig
174}
175
176impl<'a> ProfiledCleanerConfig<'a> {
177    /// Make the [`ProfiledCleaner`].
178    pub fn make(self) -> ProfiledCleaner<'a> {
179        ProfiledCleaner {
180            profiles: self.profiles.make(self.cleaner.params),
181            cleaner: UnprofiledCleaner {
182                docs   : self.cleaner.docs,
183                commons: self.cleaner.commons,
184                actions: self.cleaner.actions
185            }
186        }
187    }
188}
189
190/// The configuration for a [`Profile`]s.
191#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Default)]
192#[serde(deny_unknown_fields)]
193pub struct ProfilesConfig {
194    /// The base [`ProfileConfig`].
195    ///
196    /// Defaults to the default [`ProfileConfig`].
197    #[serde(default, skip_serializing_if = "is_default")]
198    pub base: ProfileConfig,
199    /// The [`Profile`]s.
200    ///
201    /// Defaults to an empty [`HashMap`].
202    #[serde(default, skip_serializing_if = "is_default")]
203    pub profiles: HashMap<String, ProfileConfig>
204}
205
206impl ProfilesConfig {
207    /// Get the specified [`ProfileConfig`].
208    pub fn get<'a>(&'a self, name: Option<&str>) -> Option<&'a ProfileConfig> {
209        match name {
210            None => Some(&self.base),
211            Some(name) => self.profiles.get(name)
212        }
213    }
214
215    /// Create and return only the [`Params`] for the specified profile.
216    pub fn into_params<'a>(mut self, name: Option<&str>, mut params: Params<'a>) -> Option<Params<'a>> {
217        self.base.params_diff.apply_once(&mut params);
218        match name {
219            None => Some(params),
220            Some(name) => {
221                self.profiles.remove(name)?.params_diff.apply_once(&mut params);
222                Some(params)
223            }
224        }
225    }
226
227    /// Make a [`Profiles`] with the provided [`Params`].
228    pub fn make(self, params: Params) -> Profiles {
229        let base = self.base.make(params);
230        Profiles {
231            profiles: self.profiles.into_iter().map(|(name, profile)| (name, profile.make(base.params().clone()))).collect(),
232            base
233        }
234    }
235}
236
237/// A [`ParamsDiff`] profile.
238#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Default)]
239#[serde(deny_unknown_fields)]
240pub struct ProfileConfig {
241    /// The [`ParamsDiff`].
242    ///
243    /// Defaults to the default [`ParamsDiff`].
244    #[serde(default, skip_serializing_if = "is_default")]
245    pub params_diff: ParamsDiff
246}
247
248impl ProfileConfig {
249    /// Make a [`Profile`] with the provided [`Params`].
250    pub fn make(self, mut params: Params) -> Profile {
251        Profile {
252            params: {self.params_diff.apply_multiple(&mut params); params},
253            params_diff: self.params_diff
254        }
255    }
256}