rule34/
search_query_builder.rs

1/// A helper to build a search query.
2#[derive(Debug)]
3pub struct SearchQueryBuilder(String);
4
5impl SearchQueryBuilder {
6    /// Make a new [`SearchQueryBuilder`].
7    pub fn new() -> Self {
8        SearchQueryBuilder(String::new())
9    }
10
11    /// Add a tag.
12    ///
13    /// Spaces are replaced with underscores, so this only adds one tag.
14    pub fn add_tag(&mut self, tag: &str) -> &mut Self {
15        self.0.reserve(tag.len());
16        for c in tag.chars() {
17            if c == ' ' {
18                self.0.push('_');
19            } else {
20                self.0.push(c);
21            }
22        }
23        self.0.push(' ');
24
25        self
26    }
27
28    /// Call [`SearchQueryBuilder::add_tag`] on each element of the given iterator.
29    pub fn add_tag_iter<I, S>(&mut self, iter: I) -> &mut Self
30    where
31        I: Iterator<Item = S>,
32        S: AsRef<str>,
33    {
34        for s in iter {
35            self.add_tag(s.as_ref());
36        }
37
38        self
39    }
40
41    /// Take the built query string out.
42    ///
43    /// This resets this builder's state.
44    /// The backing string is returned, so this does not preserve the string allocation.
45    pub fn take_query_string(&mut self) -> String {
46        if self.0.ends_with(' ') {
47            self.0.pop();
48        }
49
50        std::mem::take(&mut self.0)
51    }
52
53    /// Convert into a usable query string.
54    pub fn into_query_string(mut self) -> String {
55        if self.0.ends_with(' ') {
56            self.0.pop();
57        }
58
59        self.0
60    }
61}
62
63impl From<SearchQueryBuilder> for String {
64    fn from(search_query_builder: SearchQueryBuilder) -> Self {
65        search_query_builder.into_query_string()
66    }
67}
68
69impl Default for SearchQueryBuilder {
70    fn default() -> Self {
71        Self::new()
72    }
73}
74
75#[cfg(test)]
76mod test {
77    use super::*;
78
79    #[test]
80    fn build_search_query_works() {
81        let query = SearchQueryBuilder::new()
82            .add_tag("deep space waifu")
83            .take_query_string();
84        assert_eq!(query, "deep_space_waifu");
85    }
86}