use crate::conflict::Conflict;
use crate::wire::wire_names;
use serde::Deserialize;
use crate::bindings::{Bindings, Counters};
use crate::canonical::Digest;
use crate::decision::{Decision, NodeRef};
use crate::identity::Label;
use crate::ids::{
AuthoredStateId, CategoryId, ComponentId, DecisionId, DocumentId, ElementId, FeatureId,
ProductId, TagId,
};
use crate::names::{CategoryName, TagName};
use crate::tree::{Product, RootComponent};
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub enum EdgeKind {
Realizes,
ScopedTo,
Mentions,
Subject,
}
impl EdgeKind {
#[must_use]
pub const fn as_str(self) -> &'static str {
match self {
Self::Realizes => "realizes",
Self::ScopedTo => "scoped_to",
Self::Mentions => "mentions",
Self::Subject => "subject",
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Deserialize)]
#[serde(rename_all = "lowercase")]
pub enum SubjectRole {
Affected,
Outcome,
}
wire_names!(SubjectRole {
Affected => "affected",
Outcome => "outcome",
});
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Edge {
Realizes {
feature: FeatureId,
component: ComponentId,
},
ScopedTo {
component: ComponentId,
product: ProductId,
},
Mentions {
source: ElementId,
target: ElementId,
},
Subject {
decision: DecisionId,
subject: NodeRef,
role: SubjectRole,
},
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum EdgeTarget {
Element(ElementId),
Former(Label),
}
impl Edge {
#[must_use]
pub const fn kind(self) -> EdgeKind {
match self {
Self::Realizes { .. } => EdgeKind::Realizes,
Self::ScopedTo { .. } => EdgeKind::ScopedTo,
Self::Mentions { .. } => EdgeKind::Mentions,
Self::Subject { .. } => EdgeKind::Subject,
}
}
#[must_use]
pub fn source(self) -> ElementId {
match self {
Self::Realizes { feature, .. } => feature.into(),
Self::ScopedTo { component, .. } => component.into(),
Self::Mentions { source, .. } => source,
Self::Subject { decision, .. } => decision.into(),
}
}
#[must_use]
pub fn target(self) -> EdgeTarget {
let element = |element: ElementId| EdgeTarget::Element(element);
match self {
Self::Realizes { component, .. } => element(component.into()),
Self::ScopedTo { product, .. } => element(product.into()),
Self::Mentions { target, .. } => element(target),
Self::Subject {
subject: NodeRef::Held(node),
..
} => element(node.into()),
Self::Subject {
subject: NodeRef::Former(label),
..
} => EdgeTarget::Former(label),
}
}
#[must_use]
pub const fn role(self) -> Option<SubjectRole> {
match self {
Self::Subject { role, .. } => Some(role),
_ => None,
}
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct TagEntry {
pub id: TagId,
pub name: TagName,
pub definition: String,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct CategoryEntry {
pub id: CategoryId,
pub name: CategoryName,
pub definition: String,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct DerivedFrom {
pub authored_state_id: AuthoredStateId,
pub content_address: Digest,
pub publish_sequence: u64,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Document {
pub id: DocumentId,
pub products: Vec<Product>,
pub components: Vec<RootComponent>,
pub edges: Vec<Edge>,
pub tags: Vec<TagEntry>,
pub categories: Vec<CategoryEntry>,
pub decisions: Vec<Decision>,
pub bindings: Bindings,
pub counters: Counters,
pub derived_from: Option<DerivedFrom>,
pub publish_branch: Option<String>,
pub conflicts: Vec<Conflict>,
}
impl Document {
#[must_use]
pub fn empty(id: DocumentId) -> Self {
Self {
id,
products: Vec::new(),
components: Vec::new(),
edges: Vec::new(),
tags: Vec::new(),
categories: Vec::new(),
decisions: Vec::new(),
bindings: Bindings::default(),
counters: Counters::default(),
derived_from: None,
publish_branch: None,
conflicts: Vec::new(),
}
}
}