#[derive(Clone, Debug, PartialEq, Eq)]
pub struct Block {
pub clean: String,
pub raw: String,
}
#[derive(Default)]
pub struct Settle {
settled: Vec<Block>,
committing: Option<Block>,
live: String,
committing_revised: bool,
}
impl Settle {
pub fn new() -> Self { Self::default() }
pub fn on_partial(&mut self, partial: &str) {
self.live = partial.to_string();
}
pub fn commit(&mut self, raw: &str, clean: &str) {
self.finalize();
self.committing = Some(Block { clean: clean.to_string(), raw: raw.to_string() });
self.committing_revised = false;
self.live.clear();
}
pub fn finalize(&mut self) {
if let Some(b) = self.committing.take() {
self.settled.push(b);
}
}
pub fn upgrade_committing(&mut self, clean: &str) -> bool {
match self.committing.as_mut() {
Some(b) => {
b.clean = clean.to_string();
self.committing_revised = true;
true
}
None => false,
}
}
pub fn revise_committing(&mut self, raw: &str, clean: &str) -> bool {
match self.committing.as_mut() {
Some(b) => {
b.raw = raw.to_string();
b.clean = clean.to_string();
self.committing_revised = true;
true
}
None => false,
}
}
pub fn try_late_revision_settled(&mut self, _index: usize, _new_text: &str) -> bool {
false
}
pub fn settled(&self) -> &[Block] { &self.settled }
pub fn committing(&self) -> Option<&Block> { self.committing.as_ref() }
pub fn live(&self) -> &str { &self.live }
pub fn committing_revised(&self) -> bool { self.committing_revised }
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn partial_updates_only_the_live_edge() {
let mut s = Settle::new();
s.on_partial("um so the thing");
assert_eq!(s.live(), "um so the thing");
assert!(s.settled().is_empty() && s.committing().is_none());
}
#[test]
fn commit_moves_live_into_committing_not_settled() {
let mut s = Settle::new();
s.on_partial("um so the thing is");
s.commit("um so the thing is", "The thing is.");
assert_eq!(s.committing().unwrap().clean, "The thing is.");
assert_eq!(s.live(), "");
assert!(s.settled().is_empty());
}
#[test]
fn second_commit_finalizes_the_first() {
let mut s = Settle::new();
s.commit("a", "A.");
s.commit("b", "B.");
assert_eq!(s.settled().len(), 1);
assert_eq!(s.settled()[0].clean, "A.");
assert_eq!(s.committing().unwrap().clean, "B.");
}
#[test]
fn upgrade_changes_only_the_committing_block() {
let mut s = Settle::new();
s.commit("a", "A.");
s.commit("b raw", "B.");
let settled0 = s.settled()[0].clone();
assert!(s.upgrade_committing("B, refined."));
assert_eq!(s.settled()[0], settled0); assert_eq!(s.committing().unwrap().clean, "B, refined.");
}
#[test]
fn upgrade_is_noop_after_finalize() {
let mut s = Settle::new();
s.commit("a", "A.");
s.finalize();
assert!(!s.upgrade_committing("A!"));
assert_eq!(s.settled()[0].clean, "A.");
}
#[test]
fn revise_replaces_both_raw_and_clean_of_the_committing_block() {
let mut s = Settle::new();
s.commit("a", "A.");
s.commit("live hypothesis", "Live hypothesis.");
assert!(s.revise_committing("better raw", "Better raw."));
assert_eq!(s.settled()[0].clean, "A."); let c = s.committing().unwrap();
assert_eq!(c.raw, "better raw");
assert_eq!(c.clean, "Better raw.");
}
#[test]
fn revise_is_noop_after_finalize() {
let mut s = Settle::new();
s.commit("a", "A.");
s.finalize();
assert!(!s.revise_committing("x", "X."));
assert_eq!(s.settled()[0].raw, "a");
}
#[test]
fn committing_revised_flag_tracks_commit_then_revise_then_recommit() {
let mut s = Settle::new();
s.commit("a", "A.");
assert!(!s.committing_revised());
assert!(s.revise_committing("a2", "A2."));
assert!(s.committing_revised());
s.commit("b", "B.");
assert!(!s.committing_revised());
}
#[test]
fn upgrade_committing_sets_the_revised_flag() {
let mut s = Settle::new();
s.commit("a", "A.");
assert!(!s.committing_revised());
assert!(s.upgrade_committing("A, refined."));
assert!(s.committing_revised());
}
#[test]
fn late_revision_never_mutates_settled() {
let mut s = Settle::new();
s.commit("first", "First.");
s.finalize();
let before = s.settled().to_vec();
assert!(!s.try_late_revision_settled(0, "FIRST!!"));
assert_eq!(s.settled(), &before[..]);
}
}