1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
/*
Copyright (C) 2021 Erutuon

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

use std::collections::HashSet;

use crate::{
    namespace_map::{NamespaceString, NamespaceStringBorrowed},
    site_info::Interwiki,
};

/// A case-insensitive set for interwikis.
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct InterwikiSet(HashSet<NamespaceString>);

impl InterwikiSet {
    /// Given an iterator of `Interwiki`s, returns an `InterwikiSet`
    /// of all interwikis, and an `InterwikiSet` of local interwikis
    /// (where `local_interwiki == true`).
    pub fn all_and_local_from_iter<I: IntoIterator<Item = Interwiki>>(
        iter: I,
    ) -> (Self, Self) {
        let mut all = Self(HashSet::new());
        let mut local = Self(HashSet::new());
        for interwiki in iter {
            let string = NamespaceString(interwiki.prefix);
            if interwiki.local_interwiki {
                local.0.insert(string.clone());
            }
            all.0.insert(string);
        }
        (all, local)
    }

    /// Equivalent of `InterwikiLookup::isValidInterwiki()`.
    pub fn contains(&self, interwiki: &str) -> bool {
        self.0
            .contains(NamespaceStringBorrowed::from_str(interwiki))
    }
}

/// This implementation makes it possible to construct an `InterwikiSet`
/// even though its item type `NamespaceMap` is private.
impl FromIterator<String> for InterwikiSet {
    fn from_iter<T: IntoIterator<Item = String>>(iter: T) -> Self {
        Self(iter.into_iter().map(NamespaceString).collect())
    }
}

#[test]
fn lookup_is_case_insensitive() {
    let (set, local) = InterwikiSet::all_and_local_from_iter(
        ["w", "wikt"].into_iter().map(|prefix| Interwiki {
            prefix: prefix.into(),
            local_interwiki: prefix == "w",
        }),
    );
    assert!(set.contains("w"));
    assert!(set.contains("W"));
    assert!(set.contains("wikt"));
    assert!(set.contains("WIKT"));
    assert!(set.contains("WiKt"));
    assert!(local.contains("w"));
    assert!(!local.contains("wikt"));
}