use assemblage_db::{
broadcast::Broadcast,
data::{BlockStyle, Id, Parent, SpanStyle},
};
use serde::{Deserialize, Serialize};
use std::collections::BTreeSet;
pub struct Space {
pub tiles: Vec<Tile>,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Hash)]
pub struct Tile {
pub id: Id,
pub preview: Block,
pub broadcasts: BTreeSet<Broadcast>,
pub sections: Vec<Section>,
pub branches: Vec<Branch>,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Hash)]
pub struct Section {
pub id: Option<Id>,
#[serde(rename = "hasMultipleParents")]
pub has_multiple_parents: bool,
pub subsections: Vec<Subsection>,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Hash)]
pub struct Subsection {
pub id: Id,
pub block: Block,
#[serde(default)]
#[serde(skip_serializing_if = "Vec::is_empty")]
pub before: Vec<Branch>,
#[serde(default)]
#[serde(skip_serializing_if = "Vec::is_empty")]
pub after: Vec<Branch>,
}
impl Subsection {
pub fn styled_with(mut self, b: &BTreeSet<BlockStyle>, s: &BTreeSet<SpanStyle>) -> Self {
self.block = self.block.styled_with(b, s);
self
}
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialOrd, Ord, PartialEq, Eq, Hash)]
#[serde(tag = "type")]
pub enum Block {
Text {
#[serde(default)]
#[serde(skip_serializing_if = "BTreeSet::is_empty")]
styles: BTreeSet<BlockStyle>,
spans: Vec<Span>,
},
Cyclic,
}
impl Block {
pub fn text(spans: Vec<Span>) -> Self {
Self::Text {
spans,
styles: BTreeSet::new(),
}
}
pub fn styled_with(self, b: &BTreeSet<BlockStyle>, s: &BTreeSet<SpanStyle>) -> Self {
match self {
Self::Text { mut styles, spans } => {
styles.extend(b);
Self::Text {
styles,
spans: spans.into_iter().map(|span| span.styled_with(s)).collect(),
}
}
Self::Cyclic => self,
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Hash)]
#[serde(tag = "type")]
pub enum Branch {
Sibling {
link: Lineage,
timestamp: u64,
},
}
impl Ord for Branch {
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
match (self, other) {
(
Branch::Sibling {
link: l1,
timestamp: t1,
},
Branch::Sibling {
link: l2,
timestamp: t2,
},
) => t1
.cmp(t2)
.then(l1.descendant.id.cmp(&l2.descendant.id))
.then(l1.cmp(l2)),
}
}
}
impl PartialOrd for Branch {
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
Some(self.cmp(other))
}
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialOrd, Ord, PartialEq, Eq, Hash)]
pub struct Lineage {
pub descendant: PreviewLink,
#[serde(default)]
#[serde(skip_serializing_if = "Option::is_none")]
pub ancestor: Option<PreviewLink>,
pub descent: Vec<Parent>,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialOrd, Ord, PartialEq, Eq, Hash)]
pub struct PreviewLink {
pub id: Id,
pub block: Block,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialOrd, Ord, PartialEq, Eq, Hash)]
#[serde(tag = "type")]
pub enum Span {
Text {
#[serde(default)]
#[serde(skip_serializing_if = "BTreeSet::is_empty")]
styles: BTreeSet<SpanStyle>,
text: String,
},
Link {
#[serde(default)]
#[serde(skip_serializing_if = "BTreeSet::is_empty")]
styles: BTreeSet<SpanStyle>,
link: Lineage,
},
}
impl Span {
pub fn text(s: impl Into<String>) -> Self {
Self::Text {
styles: BTreeSet::new(),
text: s.into(),
}
}
pub fn link(link: Lineage) -> Self {
Self::Link {
styles: BTreeSet::new(),
link,
}
}
pub fn styled_with(mut self, styles: &BTreeSet<SpanStyle>) -> Self {
match &mut self {
Self::Text { styles: s, .. } => s.extend(styles),
Self::Link { styles: s, .. } => s.extend(styles),
}
self
}
}