Skip to content

Commit 337bff5

Browse files
committed
feat: add tracer to help with generating traces
1 parent 2d3df7e commit 337bff5

File tree

5 files changed

+195
-19
lines changed

5 files changed

+195
-19
lines changed

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "trace_types"
3-
version = "0.4.2"
3+
version = "0.5.0"
44
edition = "2021"
55

66
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

rustfmt.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
max_width = 150

src/lib.rs

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,34 @@
1+
use std::path::PathBuf;
2+
mod tracer;
13
mod types;
4+
pub use crate::tracer::{Tracer, NONE_TYPE_ID, NONE_VALUE};
25
pub use crate::types::*;
36

7+
#[cfg(test)]
8+
mod tests {
9+
use super::*;
10+
11+
#[test]
12+
fn simple_trace() {
13+
let mut tracer = Tracer::new("path.small", &vec![]);
14+
let path = PathBuf::from("/test/path.small");
15+
tracer.start(&path, Line(1));
16+
tracer.register_step(&path, Line(1));
17+
tracer.register_step(&path, Line(2));
18+
tracer.register_special_event(EventLogKind::Write, "test");
19+
tracer.register_special_event(EventLogKind::Write, "test2");
20+
let function_id = tracer.ensure_function_id("function", &path, Line(3));
21+
tracer.register_call(function_id, vec![]);
22+
23+
let int_value = ValueRecord::Int {
24+
i: 1,
25+
type_id: tracer.ensure_type_id(TypeKind::Int, "Int")
26+
};
27+
tracer.register_variable_with_full_value("test_variable", int_value);
28+
tracer.register_return(NONE_VALUE);
29+
assert_eq!(tracer.events.len(), 14);
30+
// visible with
31+
// cargo tets -- --nocapture
32+
println!("{:#?}", tracer.events);
33+
}
34+
}

src/tracer.rs

Lines changed: 155 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,155 @@
1+
use crate::types::{
2+
ArgRecord, CallRecord, EventLogKind, FullValueRecord, FunctionId, FunctionRecord, Line, PathId, RecordEvent, ReturnRecord, StepRecord,
3+
TraceLowLevelEvent, TypeId, ValueRecord, VariableId, TypeSpecificInfo, TypeRecord, TypeKind,
4+
};
5+
use std::collections::HashMap;
6+
use std::env;
7+
use std::path::{Path, PathBuf};
8+
9+
pub struct Tracer {
10+
// trace metadata:
11+
workdir: PathBuf,
12+
program: String,
13+
args: Vec<String>,
14+
// trace events
15+
pub events: Vec<TraceLowLevelEvent>,
16+
17+
// internal tracer state:
18+
paths: HashMap<PathBuf, PathId>,
19+
functions: HashMap<String, FunctionId>,
20+
variables: HashMap<String, VariableId>,
21+
types: HashMap<String, TypeId>,
22+
}
23+
24+
// we ensure in start they are registered with those id-s
25+
26+
// pub const EXAMPLE_INT_TYPE_ID: TypeId = TypeId(0);
27+
// pub const EXAMPLE_FLOAT_TYPE_ID: TypeId = TypeId(1);
28+
// pub const EXAMPLE_BOOL_TYPE_ID: TypeId = TypeId(2);
29+
// pub const EXAMPLE_STRING_TYPE_ID: TypeId = TypeId(3);
30+
pub const NONE_TYPE_ID: TypeId = TypeId(0);
31+
pub const NONE_VALUE: ValueRecord = ValueRecord::None { type_id: NONE_TYPE_ID };
32+
33+
impl Tracer {
34+
pub fn new(program: &str, args: &[String]) -> Self {
35+
Tracer {
36+
workdir: env::current_dir().unwrap(),
37+
program: program.to_string(),
38+
args: args.to_vec(),
39+
events: vec![],
40+
41+
paths: HashMap::new(),
42+
functions: HashMap::new(),
43+
variables: HashMap::new(),
44+
types: HashMap::new(),
45+
}
46+
}
47+
48+
pub fn start(&mut self, path: &PathBuf, line: Line) {
49+
let path_id = self.ensure_path_id(path);
50+
let function_id = self.ensure_function_id("<toplevel>", path, line);
51+
self.register_call(function_id, vec![]);
52+
53+
// probably we let the user choose, as different languages have
54+
// different base types/names
55+
// assert!(EXAMPLE_INT_TYPE_ID == self.load_type_id(TypeKind::Int, "Int"));
56+
// assert!(EXAMPLE_FLOAT_TYPE_ID == self.load_type_id(TypeKind::Float, "Float"));
57+
// assert!(EXAMPLE_BOOL_TYPE_ID == self.load_type_id(TypeKind::Bool, "Bool"));
58+
// assert!(EXAMPLE_STRING_TYPE_ID == self.load_type_id(TypeKind::Bool, "String"));
59+
assert!(NONE_TYPE_ID == self.ensure_type_id(TypeKind::None, "None"));
60+
}
61+
62+
pub fn ensure_path_id(&mut self, path: &Path) -> PathId {
63+
if !self.paths.contains_key(path) {
64+
self.paths.insert(path.to_path_buf(), PathId(self.paths.len()));
65+
self.register_path(path);
66+
}
67+
*self.paths.get(path).unwrap()
68+
}
69+
70+
pub fn ensure_function_id(&mut self, function_name: &str, path: &Path, line: Line) -> FunctionId {
71+
if !self.functions.contains_key(function_name) {
72+
// same function names for different path line? TODO
73+
self.functions.insert(function_name.to_string(), FunctionId(self.functions.len()));
74+
self.register_function(function_name, path, line);
75+
}
76+
*self.functions.get(function_name).unwrap()
77+
}
78+
79+
pub fn ensure_type_id(&mut self, kind: TypeKind, lang_type: &str) -> TypeId {
80+
if !self.types.contains_key(lang_type) {
81+
self.types.insert(lang_type.to_string(), TypeId(self.types.len()));
82+
self.register_type(kind, lang_type);
83+
}
84+
*self.types.get(lang_type).unwrap()
85+
}
86+
87+
pub fn ensure_variable_id(&mut self, variable_name: &str) -> VariableId {
88+
if !self.variables.contains_key(variable_name) {
89+
self.variables.insert(variable_name.to_string(), VariableId(self.variables.len()));
90+
self.register_variable_event(variable_name);
91+
}
92+
*self.variables.get(variable_name).unwrap()
93+
}
94+
95+
pub fn register_path(&mut self, path: &Path) {
96+
self.events.push(TraceLowLevelEvent::Path(path.to_path_buf()));
97+
}
98+
99+
pub fn register_function(&mut self, name: &str, path: &Path, line: Line) {
100+
let path_id = self.ensure_path_id(path);
101+
self.events.push(TraceLowLevelEvent::Function(FunctionRecord {
102+
name: name.to_string(),
103+
path_id,
104+
line,
105+
}));
106+
}
107+
108+
pub fn register_step(&mut self, path: &PathBuf, line: Line) {
109+
let path_id = self.ensure_path_id(path);
110+
self.events.push(TraceLowLevelEvent::Step(StepRecord { path_id, line: line }));
111+
}
112+
113+
pub fn register_call(&mut self, function_id: FunctionId, args: Vec<ArgRecord>) {
114+
self.events.push(TraceLowLevelEvent::Call(CallRecord { function_id, args }));
115+
}
116+
117+
pub fn register_return(&mut self, return_value: ValueRecord) {
118+
self.events.push(TraceLowLevelEvent::Return(ReturnRecord { return_value }));
119+
}
120+
121+
pub fn register_special_event(&mut self, kind: EventLogKind, content: &str) {
122+
self.events.push(TraceLowLevelEvent::Event(RecordEvent {
123+
kind,
124+
content: content.to_string(),
125+
}));
126+
}
127+
128+
pub fn register_type(&mut self, kind: TypeKind, lang_type: &str) {
129+
let typ = TypeRecord {
130+
kind,
131+
lang_type: lang_type.to_string(),
132+
specific_info: TypeSpecificInfo::None,
133+
};
134+
self.events.push(TraceLowLevelEvent::Type(typ));
135+
}
136+
137+
pub fn register_variable_with_full_value(&mut self, name: &str, value: ValueRecord) {
138+
let variable_id = self.ensure_variable_id(name);
139+
self.register_full_value(variable_id, value);
140+
}
141+
142+
pub fn register_variable_event(&mut self, variable_name: &str) {
143+
self.events.push(TraceLowLevelEvent::Variable(variable_name.to_string()));
144+
}
145+
146+
pub fn register_full_value(&mut self, variable_id: VariableId, value: ValueRecord) {
147+
self.events.push(
148+
TraceLowLevelEvent::Value(FullValueRecord {
149+
variable_id,
150+
value,
151+
})
152+
);
153+
}
154+
155+
}

src/types.rs

Lines changed: 7 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,10 @@ use serde_repr::*;
99
#[derive(Debug, Clone, Serialize, Deserialize)]
1010
pub enum TraceLowLevelEvent {
1111
Step(StepRecord),
12-
Path(PathBuf), // should be always generated before usage, so we can stop stream at random n
13-
Variable(String), // interning new name for it
14-
Type(TypeRecord), // should be always generated before Value referencing it
15-
Value(FullValueRecord), // full values: simpler case working even without modification support
12+
Path(PathBuf), // should be always generated before usage, so we can stop stream at random n
13+
Variable(String), // interning new name for it
14+
Type(TypeRecord), // should be always generated before Value referencing it
15+
Value(FullValueRecord), // full values: simpler case working even without modification support
1616
Function(FunctionRecord), // should be always generated before CallRecord referencing it
1717
Call(CallRecord),
1818
Return(ReturnRecord),
@@ -81,9 +81,7 @@ impl Line {
8181
}
8282
}
8383

84-
#[derive(
85-
Hash, Debug, Default, Copy, Clone, Serialize, Deserialize, Ord, PartialOrd, Eq, PartialEq,
86-
)]
84+
#[derive(Hash, Debug, Default, Copy, Clone, Serialize, Deserialize, Ord, PartialOrd, Eq, PartialEq)]
8785
#[serde(transparent)]
8886
pub struct PathId(pub usize);
8987

@@ -119,7 +117,6 @@ pub struct VariableId(pub usize);
119117
#[derive(Debug, Copy, Clone, Serialize, Deserialize)]
120118
pub struct FunctionId(pub usize);
121119

122-
123120
#[derive(Debug, Clone, Serialize, Deserialize)]
124121
pub struct CallRecord {
125122
// pub key: CallKey,
@@ -140,7 +137,6 @@ pub struct FunctionRecord {
140137
pub name: String,
141138
}
142139

143-
144140
#[derive(Debug, Clone, Serialize, Deserialize)]
145141
pub struct ArgRecord {
146142
pub name: String,
@@ -233,11 +229,7 @@ pub enum ValueRecord {
233229
},
234230
}
235231

236-
237-
238-
#[derive(
239-
Debug, Default, Copy, Clone, FromPrimitive, Serialize_repr, Deserialize_repr, PartialEq,
240-
)]
232+
#[derive(Debug, Default, Copy, Clone, FromPrimitive, Serialize_repr, Deserialize_repr, PartialEq)]
241233
#[repr(u8)]
242234
pub enum TypeKind {
243235
#[default]
@@ -295,9 +287,7 @@ pub enum TypeKind {
295287
Slice,
296288
}
297289

298-
#[derive(
299-
Debug, Default, Copy, Clone, FromPrimitive, Serialize_repr, Deserialize_repr, PartialEq,
300-
)]
290+
#[derive(Debug, Default, Copy, Clone, FromPrimitive, Serialize_repr, Deserialize_repr, PartialEq)]
301291
#[repr(u8)]
302292
pub enum EventLogKind {
303293
#[default]
@@ -333,4 +323,3 @@ pub enum EventLogKind {
333323

334324
// events: Vec<TraceLowLevelEvent>,
335325
// }
336-

0 commit comments

Comments
 (0)