clankerdiff_markdown/
stream.rs1use std::{
2 ops::Range,
3 sync::atomic::{AtomicU64, Ordering},
4};
5
6#[derive(Debug, Clone, PartialEq, Eq)]
7pub struct MarkdownStreamUpdate {
8 pub revision: u64,
9 pub changed_source: Range<usize>,
10 pub reset: bool,
11 pub finished: bool,
12}
13
14#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
15pub struct MarkdownStreamIdentity(u64);
16
17impl Default for MarkdownStreamIdentity {
18 fn default() -> Self {
19 static NEXT: AtomicU64 = AtomicU64::new(0);
20 Self(NEXT.fetch_add(1, Ordering::Relaxed))
21 }
22}
23
24#[derive(Debug, Default)]
25pub struct MarkdownStream {
26 source: String,
27 revision: u64,
28 identity: MarkdownStreamIdentity,
29 finished: bool,
30}
31
32impl Clone for MarkdownStream {
33 fn clone(&self) -> Self {
34 Self {
35 source: self.source.clone(),
36 revision: self.revision,
37 identity: MarkdownStreamIdentity::default(),
38 finished: self.finished,
39 }
40 }
41}
42
43impl MarkdownStream {
44 #[must_use]
45 pub fn new() -> Self {
46 Self::default()
47 }
48
49 pub fn push(&mut self, chunk: &str) -> MarkdownStreamUpdate {
50 if chunk.is_empty() && !self.finished {
51 return self.unchanged();
52 }
53 let start = self.source.len();
54 let reset = std::mem::take(&mut self.finished);
55 self.source.push_str(chunk);
56 self.update(start..self.source.len(), reset)
57 }
58
59 pub fn replace(&mut self, source: impl Into<String>) -> MarkdownStreamUpdate {
60 self.source = source.into();
61 self.finished = false;
62 self.update(0..self.source.len(), true)
63 }
64
65 pub fn finish(&mut self) -> MarkdownStreamUpdate {
66 if self.finished {
67 return self.unchanged();
68 }
69 self.finished = true;
70 self.update(self.source.len()..self.source.len(), false)
71 }
72
73 #[must_use]
74 pub fn source(&self) -> &str {
75 &self.source
76 }
77
78 #[must_use]
79 pub const fn revision(&self) -> u64 {
80 self.revision
81 }
82
83 #[must_use]
84 pub const fn identity(&self) -> MarkdownStreamIdentity {
85 self.identity
86 }
87
88 #[must_use]
89 pub const fn is_finished(&self) -> bool {
90 self.finished
91 }
92
93 fn update(&mut self, changed_source: Range<usize>, reset: bool) -> MarkdownStreamUpdate {
94 self.revision = self.revision.wrapping_add(1);
95 MarkdownStreamUpdate {
96 revision: self.revision,
97 changed_source,
98 reset,
99 finished: self.finished,
100 }
101 }
102
103 fn unchanged(&self) -> MarkdownStreamUpdate {
104 MarkdownStreamUpdate {
105 revision: self.revision,
106 changed_source: self.source.len()..self.source.len(),
107 reset: false,
108 finished: self.finished,
109 }
110 }
111}