use crate::{
graph::{
feature::{FeatureId, FeatureLabel},
PackageMetadata,
},
sorted_set::SortedSet,
PackageId,
};
use std::{fmt, slice, vec};
#[derive(Clone, Eq, PartialEq)]
pub struct FeatureList<'g> {
package: PackageMetadata<'g>,
labels: SortedSet<FeatureLabel<'g>>,
}
impl<'g> FeatureList<'g> {
pub fn new(
package: PackageMetadata<'g>,
labels: impl IntoIterator<Item = FeatureLabel<'g>>,
) -> Self {
Self {
package,
labels: labels.into_iter().collect(),
}
}
pub fn package(&self) -> &PackageMetadata<'g> {
&self.package
}
pub fn contains(&self, label: FeatureLabel<'_>) -> bool {
self.labels.contains(&label)
}
#[inline]
pub fn has_base(&self) -> bool {
self.contains(FeatureLabel::Base)
}
#[inline]
pub fn has_named_feature(&self, feature_name: &str) -> bool {
self.contains(FeatureLabel::Named(feature_name))
}
#[inline]
pub fn has_optional_dependency(&self, dep_name: &str) -> bool {
self.contains(FeatureLabel::OptionalDependency(dep_name))
}
pub fn labels(&self) -> &[FeatureLabel<'g>] {
self.labels.as_slice()
}
pub fn named_features(&self) -> impl Iterator<Item = &'g str> + '_ {
self.labels.iter().filter_map(|label| match label {
FeatureLabel::Named(feature_name) => Some(*feature_name),
_ => None,
})
}
pub fn optional_deps(&self) -> impl Iterator<Item = &'g str> + '_ {
self.labels.iter().filter_map(|label| match label {
FeatureLabel::OptionalDependency(dep_name) => Some(*dep_name),
_ => None,
})
}
pub fn iter<'a>(&'a self) -> Iter<'g, 'a> {
self.into_iter()
}
pub fn display_features<'a>(&'a self) -> DisplayFeatures<'g, 'a> {
DisplayFeatures(self.labels())
}
pub fn into_labels(self) -> Vec<FeatureLabel<'g>> {
self.labels.into_inner().into_vec()
}
}
impl<'g> fmt::Debug for FeatureList<'g> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("FeatureList")
.field("package", self.package.id())
.field("labels", &self.display_features())
.finish()
}
}
impl<'g> IntoIterator for FeatureList<'g> {
type Item = FeatureId<'g>;
type IntoIter = IntoIter<'g>;
fn into_iter(self) -> Self::IntoIter {
IntoIter::new(self)
}
}
impl<'a, 'g> IntoIterator for &'a FeatureList<'g> {
type Item = FeatureId<'g>;
type IntoIter = Iter<'g, 'a>;
fn into_iter(self) -> Self::IntoIter {
Iter::new(self)
}
}
pub struct IntoIter<'g> {
package_id: &'g PackageId,
iter: vec::IntoIter<FeatureLabel<'g>>,
}
impl<'g> IntoIter<'g> {
pub fn new(feature_list: FeatureList<'g>) -> Self {
Self {
package_id: feature_list.package.id(),
iter: feature_list.into_labels().into_iter(),
}
}
}
impl<'g> Iterator for IntoIter<'g> {
type Item = FeatureId<'g>;
fn next(&mut self) -> Option<Self::Item> {
self.iter
.next()
.map(|label| FeatureId::new(self.package_id, label))
}
}
pub struct Iter<'g, 'a> {
package_id: &'g PackageId,
iter: slice::Iter<'a, FeatureLabel<'g>>,
}
impl<'g, 'a> Iter<'g, 'a> {
pub fn new(feature_list: &'a FeatureList<'g>) -> Self {
Self {
package_id: feature_list.package.id(),
iter: feature_list.labels().iter(),
}
}
}
impl<'g, 'a> Iterator for Iter<'g, 'a> {
type Item = FeatureId<'g>;
fn next(&mut self) -> Option<Self::Item> {
self.iter
.next()
.map(|&label| FeatureId::new(self.package_id, label))
}
}
#[derive(Clone, Copy)]
pub struct DisplayFeatures<'g, 'a>(&'a [FeatureLabel<'g>]);
impl<'g, 'a> fmt::Display for DisplayFeatures<'g, 'a> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let len = self.0.len();
for (idx, label) in self.0.iter().enumerate() {
write!(f, "{}", label)?;
if idx < len - 1 {
write!(f, ", ")?;
}
}
Ok(())
}
}
impl<'g, 'a> fmt::Debug for DisplayFeatures<'g, 'a> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self)
}
}