use crate::{
error::{parse::validate::ValidationError, utils::MetaData},
knot::Address,
line::{InternalChoice, InternalLine},
story::validate::{ValidateContent, ValidationData},
};
#[cfg(feature = "serde_support")]
use serde::{Deserialize, Serialize};
#[derive(Clone, Debug)]
#[cfg_attr(feature = "serde_support", derive(Deserialize, Serialize))]
pub struct RootNode {
pub address: Address,
pub items: Vec<NodeItem>,
}
#[derive(Clone, Debug)]
#[cfg_attr(feature = "serde_support", derive(Deserialize, Serialize))]
pub struct Branch {
pub choice: InternalChoice,
pub items: Vec<NodeItem>,
pub num_visited: u32,
}
#[derive(Clone, Debug)]
#[cfg_attr(feature = "serde_support", derive(Deserialize, Serialize))]
pub enum NodeItem {
Line(InternalLine),
BranchingPoint(Vec<Branch>),
}
#[cfg(test)]
impl NodeItem {
pub fn is_branching_choice(&self) -> bool {
match self {
NodeItem::BranchingPoint(..) => true,
_ => false,
}
}
pub fn is_line(&self) -> bool {
match self {
NodeItem::Line(..) => true,
_ => false,
}
}
}
impl ValidateContent for RootNode {
fn validate(
&mut self,
error: &mut ValidationError,
current_location: &Address,
meta_data: &MetaData,
data: &ValidationData,
) {
self.items
.iter_mut()
.for_each(|item| item.validate(error, current_location, meta_data, data))
}
}
impl ValidateContent for Branch {
fn validate(
&mut self,
error: &mut ValidationError,
current_location: &Address,
meta_data: &MetaData,
data: &ValidationData,
) {
let num_errors = error.num_errors();
self.choice
.validate(error, current_location, meta_data, data);
if let Some((choice_display_line, items)) = self.items.split_first_mut() {
if num_errors == error.num_errors() {
choice_display_line.validate(error, current_location, meta_data, data);
}
items
.iter_mut()
.for_each(|item| item.validate(error, current_location, meta_data, data));
}
}
}
impl ValidateContent for NodeItem {
fn validate(
&mut self,
error: &mut ValidationError,
current_location: &Address,
meta_data: &MetaData,
data: &ValidationData,
) {
match self {
NodeItem::BranchingPoint(branches) => branches
.iter_mut()
.for_each(|item| item.validate(error, current_location, meta_data, data)),
NodeItem::Line(line) => line.validate(error, current_location, meta_data, data),
};
}
}
pub mod builders {
use super::{Branch, NodeItem, RootNode};
use crate::{
knot::{Address, AddressKind},
line::{InternalChoice, InternalLine},
};
#[cfg(test)]
use crate::line::LineChunk;
pub struct RootNodeBuilder {
address: Address,
items: Vec<NodeItem>,
}
impl RootNodeBuilder {
pub fn from_address(knot: &str, stitch: &str) -> Self {
let address = Address::Validated(AddressKind::Location {
knot: knot.to_string(),
stitch: stitch.to_string(),
});
RootNodeBuilder {
address,
items: Vec::new(),
}
}
pub fn build(self) -> RootNode {
RootNode {
address: self.address,
items: self.items,
}
}
pub fn add_branching_choice(&mut self, branching_set: Vec<Branch>) {
self.add_item(NodeItem::BranchingPoint(branching_set));
}
pub fn add_item(&mut self, item: NodeItem) {
self.items.push(item);
}
pub fn add_line(&mut self, line: InternalLine) {
self.add_item(NodeItem::Line(line));
}
#[cfg(test)]
pub fn empty() -> Self {
Self::from_address("", "")
}
#[cfg(test)]
pub fn with_item(mut self, item: NodeItem) -> Self {
self.items.push(item);
self
}
#[cfg(test)]
pub fn with_branching_choice(self, branching_choice_set: NodeItem) -> Self {
self.with_item(branching_choice_set)
}
#[cfg(test)]
pub fn with_line_chunk(self, chunk: LineChunk) -> Self {
self.with_item(NodeItem::Line(InternalLine::from_chunk(chunk)))
}
#[cfg(test)]
pub fn with_text_line_chunk(self, content: &str) -> Self {
self.with_item(NodeItem::Line(InternalLine::from_string(content)))
}
}
pub struct BranchBuilder {
choice: InternalChoice,
items: Vec<NodeItem>,
}
impl BranchBuilder {
pub fn from_choice(choice: InternalChoice) -> Self {
let line = choice.display_text.clone();
BranchBuilder {
choice,
items: vec![NodeItem::Line(line)],
}
}
pub fn build(self) -> Branch {
Branch {
choice: self.choice,
items: self.items,
num_visited: 0,
}
}
pub fn add_branching_choice(&mut self, branching_set: Vec<Branch>) {
self.add_item(NodeItem::BranchingPoint(branching_set));
}
pub fn add_item(&mut self, item: NodeItem) {
self.items.push(item);
}
pub fn add_line(&mut self, line: InternalLine) {
self.add_item(NodeItem::Line(line));
}
#[cfg(test)]
pub fn with_item(mut self, item: NodeItem) -> Self {
self.items.push(item);
self
}
#[cfg(test)]
pub fn with_branching_choice(self, branching_choice_set: NodeItem) -> Self {
self.with_item(branching_choice_set)
}
#[cfg(test)]
pub fn with_text_line_chunk(self, content: &str) -> Self {
self.with_item(NodeItem::Line(InternalLine::from_string(content)))
}
}
#[cfg(test)]
pub struct BranchingPointBuilder {
items: Vec<Branch>,
}
#[cfg(test)]
impl BranchingPointBuilder {
pub fn new() -> Self {
BranchingPointBuilder { items: Vec::new() }
}
pub fn with_branch(mut self, choice: Branch) -> Self {
self.items.push(choice);
self
}
pub fn build(self) -> NodeItem {
NodeItem::BranchingPoint(self.items)
}
}
}