use std::borrow::Cow;
use std::collections::BTreeSet;
use std::slice;
use std::sync::Arc;
#[derive(Clone, Debug, Hash, Eq, Ord, PartialEq, PartialOrd)]
pub struct Component {
name: Cow<'static, str>,
}
impl Component {
pub fn new(name: impl Into<Cow<'static, str>>) -> Self {
Self { name: name.into() }
}
pub fn name(&self) -> &str {
self.name.as_ref()
}
}
#[derive(Clone, Debug, Eq)]
pub struct ComponentSet {
components: Arc<[Component]>,
}
impl ComponentSet {
pub fn len(&self) -> usize {
self.components.len()
}
pub fn is_empty(&self) -> bool {
self.components.is_empty()
}
pub fn contains(&self, component: &Component) -> bool {
self.components.contains(component)
}
pub fn iter(&self) -> slice::Iter<'_, Component> {
self.components.iter()
}
pub fn as_slice(&self) -> &[Component] {
&self.components
}
}
impl Default for ComponentSet {
fn default() -> Self {
Self {
components: Vec::new().into(),
}
}
}
impl PartialEq for ComponentSet {
fn eq(&self, other: &Self) -> bool {
Arc::ptr_eq(&self.components, &other.components) || self.components == other.components
}
}
impl FromIterator<Component> for ComponentSet {
fn from_iter<I: IntoIterator<Item = Component>>(iter: I) -> Self {
let unique = iter.into_iter().collect::<BTreeSet<_>>();
Self {
components: unique.into_iter().collect(),
}
}
}
impl From<Vec<Component>> for ComponentSet {
fn from(components: Vec<Component>) -> Self {
components.into_iter().collect()
}
}
impl<'a> IntoIterator for &'a ComponentSet {
type Item = &'a Component;
type IntoIter = slice::Iter<'a, Component>;
fn into_iter(self) -> Self::IntoIter {
self.components.iter()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn new_instance() {
let c = Component::new("sample");
assert_eq!(c.name(), "sample");
}
mod component_set {
use super::*;
use std::ptr;
#[test]
fn an_empty_set() {
let set = ComponentSet::default();
assert!(set.is_empty());
assert_eq!(set.len(), 0);
}
#[test]
fn a_set_is_ordered_by_name() {
let set = [Component::new("rustc"), Component::new("cargo")]
.into_iter()
.collect::<ComponentSet>();
let names = set.iter().map(|c| c.name()).collect::<Vec<_>>();
assert_eq!(names, ["cargo", "rustc"]);
}
#[test]
fn a_set_holds_every_component_once() {
let set = [Component::new("cargo"), Component::new("cargo")]
.into_iter()
.collect::<ComponentSet>();
assert_eq!(set.len(), 1);
assert!(set.contains(&Component::new("cargo")));
}
#[test]
fn a_set_is_equal_regardless_of_the_order_it_was_built_in() {
let left = [Component::new("rustc"), Component::new("cargo")]
.into_iter()
.collect::<ComponentSet>();
let right = [Component::new("cargo"), Component::new("rustc")]
.into_iter()
.collect::<ComponentSet>();
assert_eq!(left, right);
}
#[test]
fn a_clone_shares_the_components_of_the_set_it_was_cloned_from() {
let set = [Component::new("cargo")]
.into_iter()
.collect::<ComponentSet>();
let clone = set.clone();
assert!(ptr::eq(set.as_slice(), clone.as_slice()));
}
}
}