use crate::enums::event_type::EventType;
use crate::functions::format_append::formatAppend;
use crate::macros::luau_assert::LUAU_ASSERT;
use crate::records::event::Event;
use crate::records::global_context::GlobalContext;
use alloc::string::String;
use core::ffi::{c_char, CStr};
use std::io::Write;
fn data_str(data: &[c_char], pos: u32) -> alloc::borrow::Cow<'_, str> {
let ptr = unsafe { data.as_ptr().add(pos as usize) };
unsafe { CStr::from_ptr(ptr) }.to_string_lossy()
}
pub fn flush_events(context: &GlobalContext, thread_id: u32, events: &[Event], data: &[c_char]) {
let mut state = context
.state
.lock()
.expect("TimeTrace GlobalContext mutex poisoned");
if state.trace_file.is_none() {
match std::fs::File::create("trace.json") {
Ok(mut file) => {
let _ = file.write_all(b"[\n");
state.trace_file = Some(file);
}
Err(_) => return,
}
}
let mut temp = String::new();
const TEMP_RESERVE: usize = 64 * 1024;
temp.reserve(TEMP_RESERVE);
let mut unfinished_enter = false;
let mut unfinished_args = false;
for ev in events {
match ev.r#type {
EventType::Enter => {
if unfinished_args {
formatAppend(&mut temp, format_args!("}}"));
unfinished_args = false;
}
if unfinished_enter {
formatAppend(&mut temp, format_args!("}},\n"));
unfinished_enter = false;
}
let token = state.tokens[ev.token as usize];
let name = unsafe { CStr::from_ptr(token.name) }.to_string_lossy();
let category = unsafe { CStr::from_ptr(token.category) }.to_string_lossy();
let microsec = unsafe { ev.data.microsec };
formatAppend(
&mut temp,
format_args!(
r#"{{"name": "{}", "cat": "{}", "ph": "B", "ts": {}, "pid": 0, "tid": {}"#,
name, category, microsec, thread_id
),
);
unfinished_enter = true;
}
EventType::Leave => {
if unfinished_args {
formatAppend(&mut temp, format_args!("}}"));
unfinished_args = false;
}
if unfinished_enter {
formatAppend(&mut temp, format_args!("}},\n"));
unfinished_enter = false;
}
let microsec = unsafe { ev.data.microsec };
formatAppend(
&mut temp,
format_args!(
"{{\"ph\": \"E\", \"ts\": {}, \"pid\": 0, \"tid\": {}}},\n",
microsec, thread_id
),
);
}
EventType::ArgName => {
LUAU_ASSERT!(unfinished_enter);
let pos = unsafe { ev.data.dataPos };
let arg = data_str(data, pos);
if !unfinished_args {
formatAppend(&mut temp, format_args!(r#", "args": {{ "{}": "#, arg));
unfinished_args = true;
} else {
formatAppend(&mut temp, format_args!(r#", "{}": "#, arg));
}
}
EventType::ArgValue => {
LUAU_ASSERT!(unfinished_args);
let pos = unsafe { ev.data.dataPos };
let value = data_str(data, pos);
formatAppend(&mut temp, format_args!(r#""{}""#, value));
}
}
if temp.len() > TEMP_RESERVE - 1024 {
if let Some(file) = state.trace_file.as_mut() {
let _ = file.write_all(temp.as_bytes());
}
temp.clear();
}
}
if unfinished_args {
formatAppend(&mut temp, format_args!("}}"));
}
if unfinished_enter {
formatAppend(&mut temp, format_args!("}},\n"));
}
if let Some(file) = state.trace_file.as_mut() {
let _ = file.write_all(temp.as_bytes());
let _ = file.flush();
}
}