use crate::document::Document;
use crate::ids::NodeId;
use crate::kind::NodeKind;
use crate::tree::{
Component, Constraint, Criterion, Details, Feature, FeatureGroup, Product, QualityAttribute,
Requirement, Section,
};
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Node<'a> {
Product(&'a Product),
FeatureGroup(&'a FeatureGroup),
Feature(&'a Feature),
Requirement(&'a Requirement),
Criterion(&'a Criterion),
Component(&'a Component),
Constraint(&'a Constraint),
QualityAttribute(&'a QualityAttribute),
Section(&'a Section),
}
impl<'a> Node<'a> {
#[must_use]
pub const fn kind(self) -> NodeKind {
match self {
Self::Product(_) => NodeKind::Product,
Self::FeatureGroup(_) => NodeKind::FeatureGroup,
Self::Feature(_) => NodeKind::Feature,
Self::Requirement(_) => NodeKind::Requirement,
Self::Criterion(_) => NodeKind::Criterion,
Self::Component(_) => NodeKind::Component,
Self::Constraint(_) => NodeKind::Constraint,
Self::QualityAttribute(_) => NodeKind::QualityAttribute,
Self::Section(_) => NodeKind::Section,
}
}
#[must_use]
pub fn id(self) -> Option<NodeId> {
match self {
Self::Product(node) => node.id.map(NodeId::from),
Self::FeatureGroup(node) => node.id.map(NodeId::from),
Self::Feature(node) => node.id.map(NodeId::from),
Self::Requirement(node) => node.id.map(NodeId::from),
Self::Criterion(node) => node.id.map(NodeId::from),
Self::Component(node) => node.id.map(NodeId::from),
Self::Constraint(node) => node.id.map(NodeId::from),
Self::QualityAttribute(node) => node.id.map(NodeId::from),
Self::Section(node) => node.id.map(NodeId::from),
}
}
#[must_use]
pub const fn details(self) -> Option<&'a Details> {
match self {
Self::Product(node) => Some(&node.details),
Self::FeatureGroup(node) => Some(&node.details),
Self::Feature(node) => Some(&node.details),
Self::Requirement(node) => Some(&node.details),
Self::Criterion(node) => Some(&node.details),
Self::Component(node) => Some(&node.details),
Self::Constraint(node) => Some(&node.details),
Self::QualityAttribute(node) => Some(&node.details),
Self::Section(_) => None,
}
}
#[must_use]
pub fn sections(self) -> &'a [Section] {
match self {
Self::Product(node) => &node.details.sections,
Self::FeatureGroup(node) => &node.details.sections,
Self::Feature(node) => &node.details.sections,
Self::Requirement(node) => &node.details.sections,
Self::Criterion(node) => &node.details.sections,
Self::Component(node) => &node.details.sections,
Self::Constraint(node) => &node.details.sections,
Self::QualityAttribute(node) => &node.details.sections,
Self::Section(node) => &node.sections,
}
}
#[must_use]
pub fn children(self) -> Vec<Self> {
let mut children = Vec::new();
match self {
Self::Product(node) => {
children.extend(node.feature_groups.iter().map(Self::FeatureGroup));
}
Self::FeatureGroup(node) => {
children.extend(node.features.iter().map(Self::Feature));
children.extend(node.constraints.iter().map(Self::Constraint));
}
Self::Feature(node) => {
children.extend(node.requirements.iter().map(Self::Requirement));
children.extend(node.quality_attributes.iter().map(Self::QualityAttribute));
}
Self::Requirement(node) => {
children.extend(node.criteria.iter().map(Self::Criterion));
}
Self::Component(node) => {
children.extend(node.components.iter().map(Self::Component));
children.extend(node.constraints.iter().map(Self::Constraint));
children.extend(node.quality_attributes.iter().map(Self::QualityAttribute));
}
Self::Criterion(_)
| Self::Constraint(_)
| Self::QualityAttribute(_)
| Self::Section(_) => {}
}
children.extend(self.sections().iter().map(Self::Section));
children
}
pub fn walk(self, visit: &mut impl FnMut(Self)) {
visit(self);
for child in self.children() {
child.walk(visit);
}
}
}
macro_rules! from_refs {
($($kind:ident),*) => {$(
impl<'a> From<&'a $kind> for Node<'a> {
fn from(node: &'a $kind) -> Self {
Self::$kind(node)
}
}
)*};
}
from_refs!(
Product,
FeatureGroup,
Feature,
Requirement,
Criterion,
Component,
Constraint,
QualityAttribute,
Section
);
impl Document {
pub fn root_nodes(&self) -> impl Iterator<Item = Node<'_>> {
let components = self
.components
.iter()
.map(|root| Node::Component(&root.component));
self.products.iter().map(Node::Product).chain(components)
}
pub fn walk<'a>(&'a self, visit: &mut impl FnMut(Node<'a>)) {
for root in self.root_nodes() {
root.walk(visit);
}
}
}