archunit/common/extraction/
import_kind.rsuse std::collections::BTreeSet;
use std::fmt;
use std::iter::FromIterator;
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[non_exhaustive]
pub enum ImportKind {
Use,
PubUse,
ExternCrate,
Mod,
PathReference,
MacroReference,
}
impl ImportKind {
#[must_use]
pub const fn as_str(self) -> &'static str {
match self {
Self::Use => "use",
Self::PubUse => "pub_use",
Self::ExternCrate => "extern_crate",
Self::Mod => "mod",
Self::PathReference => "path_reference",
Self::MacroReference => "macro_reference",
}
}
}
impl fmt::Display for ImportKind {
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
formatter.write_str(self.as_str())
}
}
#[derive(Debug, Clone, Default, PartialEq, Eq, Hash)]
pub struct ImportKindSet {
kinds: BTreeSet<ImportKind>,
}
impl ImportKindSet {
#[must_use]
pub const fn new() -> Self {
Self {
kinds: BTreeSet::new(),
}
}
#[must_use]
pub fn with(mut self, kind: ImportKind) -> Self {
self.kinds.insert(kind);
self
}
#[must_use]
pub fn contains(&self, kind: ImportKind) -> bool {
self.kinds.contains(&kind)
}
#[must_use]
pub fn len(&self) -> usize {
self.kinds.len()
}
#[must_use]
pub fn is_empty(&self) -> bool {
self.kinds.is_empty()
}
pub fn iter(&self) -> impl ExactSizeIterator<Item = ImportKind> + '_ {
self.kinds.iter().copied()
}
}
impl From<ImportKind> for ImportKindSet {
fn from(kind: ImportKind) -> Self {
Self::new().with(kind)
}
}
impl FromIterator<ImportKind> for ImportKindSet {
fn from_iter<T: IntoIterator<Item = ImportKind>>(kinds: T) -> Self {
Self {
kinds: kinds.into_iter().collect(),
}
}
}
impl<'a> IntoIterator for &'a ImportKindSet {
type Item = ImportKind;
type IntoIter = std::iter::Copied<std::collections::btree_set::Iter<'a, ImportKind>>;
fn into_iter(self) -> Self::IntoIter {
self.kinds.iter().copied()
}
}
impl fmt::Display for ImportKindSet {
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
formatter.write_str("[")?;
for (index, kind) in self.iter().enumerate() {
if index > 0 {
formatter.write_str(", ")?;
}
kind.fmt(formatter)?;
}
formatter.write_str("]")
}
}
#[cfg(test)]
mod tests {
use super::{ImportKind, ImportKindSet};
#[test]
fn exposes_stable_kind_names() {
let cases = [
(ImportKind::Use, "use"),
(ImportKind::PubUse, "pub_use"),
(ImportKind::ExternCrate, "extern_crate"),
(ImportKind::Mod, "mod"),
(ImportKind::PathReference, "path_reference"),
(ImportKind::MacroReference, "macro_reference"),
];
for (kind, expected) in cases {
assert_eq!(kind.as_str(), expected);
assert_eq!(kind.to_string(), expected);
}
}
#[test]
fn deduplicates_and_orders_kinds() {
let kinds: ImportKindSet = [
ImportKind::MacroReference,
ImportKind::Use,
ImportKind::PubUse,
ImportKind::Use,
]
.into_iter()
.collect();
assert_eq!(
kinds.iter().collect::<Vec<_>>(),
vec![
ImportKind::Use,
ImportKind::PubUse,
ImportKind::MacroReference
]
);
assert_eq!(kinds.to_string(), "[use, pub_use, macro_reference]");
}
#[test]
fn supports_immutable_extension() {
let base = ImportKindSet::from(ImportKind::Use);
let extended = base.clone().with(ImportKind::Mod);
assert_eq!(base.len(), 1);
assert!(!base.contains(ImportKind::Mod));
assert!(extended.contains(ImportKind::Use));
assert!(extended.contains(ImportKind::Mod));
}
}