use brep_render::history::{History, DIAGRAM, PADS, PCB, SYMBOL};
use serde_json::Value;
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum Block {
Diagram,
Pcb,
Symbol,
Pads,
}
impl Block {
pub fn key(self) -> &'static str {
match self {
Block::Diagram => DIAGRAM,
Block::Pcb => PCB,
Block::Symbol => SYMBOL,
Block::Pads => PADS,
}
}
pub fn read(self, history: &History) -> Option<&Value> {
match self {
Block::Diagram => history.diagram_block(),
Block::Pcb => history.pcb_block(),
Block::Symbol => history.symbol_block(),
Block::Pads => history.pads_block(),
}
}
pub fn write(self, history: &mut History, value: Value, coalesce: Option<&str>) {
match self {
Block::Diagram => history.set_diagram_block(Some(value), coalesce),
Block::Pcb => history.set_pcb_block(Some(value), coalesce),
Block::Symbol => history.set_symbol_block(Some(value), coalesce),
Block::Pads => history.set_pads_block(Some(value), coalesce),
}
}
}
#[derive(Debug)]
pub struct BlockSync {
block: Block,
revision: Option<u64>,
held: Option<Value>,
unreadable: Option<String>,
reported: Vec<String>,
refused: Option<Value>,
reloads: u64,
}
impl BlockSync {
pub fn new(block: Block) -> Self {
Self { block, revision: None, held: None, unreadable: None, reported: Vec::new(), refused: None, reloads: 0 }
}
pub fn block(&self) -> Block {
self.block
}
pub fn unreported(&mut self, lines: Vec<String>) -> Vec<String> {
let fresh = lines.iter().filter(|line| !self.reported.contains(line)).cloned().collect();
self.reported = lines;
fresh
}
pub fn store(&mut self, history: &mut History, value: Value, coalesce: Option<&str>) -> Result<(), String> {
if let Some(reason) = &self.unreadable {
return Err(format!("the {} block was not written: {reason}", self.block.key()));
}
self.block.write(history, value.clone(), coalesce);
self.held = Some(value);
self.revision = Some(history.revision());
Ok(())
}
pub fn pulled(&self) -> bool {
self.revision.is_some()
}
pub fn adopt(&mut self, history: &mut History, document: &Value, value: Value) -> Result<(), String> {
if let Some(reason) = &self.unreadable {
return Err(format!("the {} block was not written: {reason}", self.block.key()));
}
history.adopt_document(&document.to_string())?;
self.held = Some(value);
self.revision = Some(history.revision());
Ok(())
}
pub fn pull(&mut self, history: &History) -> Option<Option<Value>> {
let revision = history.revision();
let first = self.revision.is_none();
if self.revision == Some(revision) {
return None;
}
self.revision = Some(revision);
let current = self.block.read(history);
if !first && current == self.held.as_ref() {
return None;
}
self.held = current.cloned();
self.unreadable = None;
Some(self.held.clone())
}
pub fn hold_unwritten(&mut self, history: &History, value: Value) {
self.held = Some(value);
self.revision = Some(history.revision());
}
pub fn reload(&mut self) {
self.revision = None;
self.reloads += 1;
}
pub fn reloads(&self) -> u64 {
self.reloads
}
pub fn refused_again(&mut self, value: &Value) -> bool {
let again = self.refused.as_ref() == Some(value);
self.refused = Some(value.clone());
again
}
pub fn refuse(&mut self, reason: String) {
self.unreadable = Some(reason);
}
pub fn unreadable(&self) -> Option<&str> {
self.unreadable.as_deref()
}
}