strop_core/
diagnostics.rs1use crate::Buffer;
3use serde::Serialize;
4use std::sync::atomic::{AtomicU64, Ordering};
5use strop_trace::{capture_content, enabled, record, EventKind};
6
7static NEXT_BUFFER: AtomicU64 = AtomicU64::new(1);
8
9#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize)]
10#[serde(transparent)]
11pub struct BufferTraceId(u64);
12impl BufferTraceId {
13 pub(crate) fn next() -> Self {
14 Self(NEXT_BUFFER.fetch_add(1, Ordering::Relaxed))
15 }
16}
17
18#[derive(Serialize)]
19struct Mutation {
20 buffer: BufferTraceId,
21 source: crate::ChangeOrigin,
22 revision: u64,
23 start_byte: usize,
24 removed_bytes: usize,
25 inserted_bytes: usize,
26 #[serde(skip_serializing_if = "Option::is_none")]
27 inserted_text: Option<String>,
28 #[serde(skip_serializing_if = "std::ops::Not::not")]
29 text_truncated: bool,
30}
31
32impl Buffer {
33 pub fn trace_id(&self) -> BufferTraceId {
34 self.trace_identity
35 }
36
37 pub(crate) fn trace_edit(
38 &self,
39 source: crate::ChangeOrigin,
40 start_byte: usize,
41 removed_bytes: usize,
42 inserted: &str,
43 ) {
44 if !enabled() {
45 return;
46 }
47 let (text, text_truncated) = strop_trace::excerpt(inserted);
50 record(
51 EventKind::Mutation,
52 &Mutation {
53 buffer: self.trace_id(),
54 source,
55 revision: self.revision().get(),
56 start_byte,
57 removed_bytes,
58 inserted_bytes: inserted.len(),
59 inserted_text: capture_content().then(|| text.to_owned()),
60 text_truncated: text_truncated && capture_content(),
61 },
62 );
63 }
64
65 pub(crate) fn trace_snapshot(&self, removed_bytes: usize) {
66 if !enabled() {
67 return;
68 }
69 let (text, text_truncated) = capture_content()
70 .then(|| self.text_excerpt())
71 .map_or((None, false), |(text, truncated)| (Some(text), truncated));
72 record(
73 EventKind::Mutation,
74 &Mutation {
75 buffer: self.trace_id(),
76 source: crate::ChangeOrigin::System,
77 revision: self.revision().get(),
78 start_byte: 0,
79 removed_bytes,
80 inserted_bytes: self.len_bytes(),
81 inserted_text: text,
82 text_truncated,
83 },
84 );
85 }
86
87 pub(crate) fn trace_history(&self, edits: &[crate::history::Edit]) {
88 if !enabled() {
89 return;
90 }
91 #[derive(Serialize)]
92 struct HistoryEdit<'a> {
93 start_byte: usize,
94 bytes: usize,
95 kind: crate::history::EditKind,
96 #[serde(skip_serializing_if = "Option::is_none")]
97 text: Option<&'a str>,
98 #[serde(skip_serializing_if = "std::ops::Not::not")]
99 text_truncated: bool,
100 }
101 #[derive(Serialize)]
102 struct AppliedHistory<'a> {
103 buffer: BufferTraceId,
104 revision: u64,
105 edits: Vec<HistoryEdit<'a>>,
106 }
107 record(
108 EventKind::History,
109 &AppliedHistory {
110 buffer: self.trace_id(),
111 revision: self.revision().get(),
112 edits: edits
113 .iter()
114 .map(|edit| {
115 let (text, text_truncated) = strop_trace::excerpt(&edit.text);
116 HistoryEdit {
117 start_byte: edit.at,
118 bytes: edit.text.len(),
119 kind: edit.kind,
120 text: capture_content().then_some(text),
121 text_truncated: text_truncated && capture_content(),
122 }
123 })
124 .collect(),
125 },
126 );
127 }
128}