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)]
19#[serde(rename_all = "snake_case")]
20pub(crate) enum MutationSource {
21 User,
22 System,
23}
24
25#[derive(Serialize)]
26struct Mutation<'a> {
27 buffer: BufferTraceId,
28 path: Option<&'a std::path::Path>,
29 source: MutationSource,
30 revision: u64,
31 start_byte: usize,
32 removed_bytes: usize,
33 inserted_bytes: usize,
34 #[serde(skip_serializing_if = "Option::is_none")]
35 inserted_text: Option<&'a str>,
36}
37
38impl Buffer {
39 pub fn trace_id(&self) -> BufferTraceId {
40 self.trace_identity
41 }
42
43 pub(crate) fn trace_edit(
44 &self,
45 source: MutationSource,
46 start_byte: usize,
47 removed_bytes: usize,
48 inserted: &str,
49 ) {
50 if !enabled() {
51 return;
52 }
53 let path = self.path.as_deref().filter(|p| p.to_str().is_some());
56 record(
57 EventKind::Mutation,
58 &Mutation {
59 buffer: self.trace_id(),
60 path,
61 source,
62 revision: self.epoch,
63 start_byte,
64 removed_bytes,
65 inserted_bytes: inserted.len(),
66 inserted_text: capture_content().then_some(inserted),
67 },
68 );
69 }
70
71 pub(crate) fn trace_history(&self, edits: &[crate::history::Edit]) {
72 if !enabled() {
73 return;
74 }
75 #[derive(Serialize)]
76 struct HistoryEdit<'a> {
77 start_byte: usize,
78 bytes: usize,
79 kind: crate::history::EditKind,
80 #[serde(skip_serializing_if = "Option::is_none")]
81 text: Option<&'a str>,
82 }
83 #[derive(Serialize)]
84 struct AppliedHistory<'a> {
85 buffer: BufferTraceId,
86 revision: u64,
87 edits: Vec<HistoryEdit<'a>>,
88 }
89 record(
90 EventKind::History,
91 &AppliedHistory {
92 buffer: self.trace_id(),
93 revision: self.epoch,
94 edits: edits
95 .iter()
96 .map(|edit| HistoryEdit {
97 start_byte: edit.at,
98 bytes: edit.text.len(),
99 kind: edit.kind,
100 text: capture_content().then_some(edit.text.as_str()),
101 })
102 .collect(),
103 },
104 );
105 }
106}