mwtitle 0.2.0-alpha.2

MediaWiki title validation and formatting
Documentation
/*
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"));
}