use std::io::{Read, Write};
use serde::{Deserialize, Serialize};
use crate::{
context::{BuildEventContext, read_build_event_context, write_build_event_context},
error::MuninError,
field_flags::BuildEventArgsFieldFlags,
primitives::{BinlogDateTime, read_7bit_count, read_7bit_int, read_datetime},
string_table::StringTable,
writers::{WriteContext, write_7bit_int, write_datetime, write_dedup_string},
};
#[derive(Debug, Clone, PartialEq, Eq, Default, Serialize, Deserialize)]
pub struct ExtendedDataFields {
pub extended_type: Option<String>,
pub extended_metadata_index: i32,
pub extended_data: Option<String>,
}
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
pub struct BuildEventArgsFields {
pub flags: BuildEventArgsFieldFlags,
pub message: Option<String>,
pub build_event_context: Option<BuildEventContext>,
pub thread_id: i32,
pub help_keyword: Option<String>,
pub sender_name: Option<String>,
pub timestamp: Option<BinlogDateTime>,
pub extended: Option<ExtendedDataFields>,
pub subcategory: Option<String>,
pub code: Option<String>,
pub file: Option<String>,
pub project_file: Option<String>,
pub line_number: i32,
pub column_number: i32,
pub end_line_number: i32,
pub end_column_number: i32,
pub arguments: Option<Vec<Option<String>>>,
pub importance: i32,
}
fn read_dedup_string(
reader: &mut impl Read,
strings: &StringTable,
) -> Result<Option<String>, MuninError> {
let index = read_7bit_int(reader)?;
Ok(strings.get(index)?.map(|s| s.to_string()))
}
pub fn read_build_event_args_fields(
reader: &mut impl Read,
strings: &StringTable,
file_format_version: i32,
read_importance: bool,
) -> Result<BuildEventArgsFields, MuninError> {
let flags_raw = read_7bit_int(reader)? as u32;
let flags = BuildEventArgsFieldFlags::from_raw(flags_raw);
let mut fields = BuildEventArgsFields {
flags,
..Default::default()
};
if flags.contains(BuildEventArgsFieldFlags::MESSAGE) {
fields.message = read_dedup_string(reader, strings)?;
}
if flags.contains(BuildEventArgsFieldFlags::BUILD_EVENT_CONTEXT) {
fields.build_event_context = Some(read_build_event_context(reader, file_format_version)?);
}
if flags.contains(BuildEventArgsFieldFlags::THREAD_ID) {
fields.thread_id = read_7bit_int(reader)?;
}
if flags.contains(BuildEventArgsFieldFlags::HELP_KEYWORD) {
fields.help_keyword = read_dedup_string(reader, strings)?;
}
if flags.contains(BuildEventArgsFieldFlags::SENDER_NAME) {
fields.sender_name = read_dedup_string(reader, strings)?;
}
if flags.contains(BuildEventArgsFieldFlags::TIMESTAMP) {
fields.timestamp = Some(read_datetime(reader)?);
}
if flags.contains(BuildEventArgsFieldFlags::EXTENDED) {
let extended_type = read_dedup_string(reader, strings)?;
let extended_metadata_index = read_7bit_int(reader)?;
let extended_data = read_dedup_string(reader, strings)?;
fields.extended = Some(ExtendedDataFields {
extended_type,
extended_metadata_index,
extended_data,
});
}
if flags.contains(BuildEventArgsFieldFlags::SUBCATEGORY) {
fields.subcategory = read_dedup_string(reader, strings)?;
}
if flags.contains(BuildEventArgsFieldFlags::CODE) {
fields.code = read_dedup_string(reader, strings)?;
}
if flags.contains(BuildEventArgsFieldFlags::FILE) {
fields.file = read_dedup_string(reader, strings)?;
}
if flags.contains(BuildEventArgsFieldFlags::PROJECT_FILE) {
fields.project_file = read_dedup_string(reader, strings)?;
}
if flags.contains(BuildEventArgsFieldFlags::LINE_NUMBER) {
fields.line_number = read_7bit_int(reader)?;
}
if flags.contains(BuildEventArgsFieldFlags::COLUMN_NUMBER) {
fields.column_number = read_7bit_int(reader)?;
}
if flags.contains(BuildEventArgsFieldFlags::END_LINE_NUMBER) {
fields.end_line_number = read_7bit_int(reader)?;
}
if flags.contains(BuildEventArgsFieldFlags::END_COLUMN_NUMBER) {
fields.end_column_number = read_7bit_int(reader)?;
}
if flags.contains(BuildEventArgsFieldFlags::ARGUMENTS) {
let count = read_7bit_count(reader, "event arguments count")?;
let mut args = Vec::with_capacity(count);
for _ in 0..count {
args.push(read_dedup_string(reader, strings)?);
}
fields.arguments = Some(args);
}
if (file_format_version < 13 && read_importance)
|| (file_format_version >= 13 && flags.contains(BuildEventArgsFieldFlags::IMPORTANCE))
{
fields.importance = read_7bit_int(reader)?;
}
Ok(fields)
}
pub fn write_build_event_args_fields<W: Write>(
w: &mut W,
ctx: &mut WriteContext,
fields: &BuildEventArgsFields,
write_importance: bool,
) -> std::io::Result<()> {
let flags = fields.flags;
write_7bit_int(w, flags.bits() as i32)?;
if flags.contains(BuildEventArgsFieldFlags::MESSAGE) {
write_dedup_string(w, ctx, fields.message.as_deref())?;
}
if flags.contains(BuildEventArgsFieldFlags::BUILD_EVENT_CONTEXT) {
let bec = fields.build_event_context.unwrap_or_default();
write_build_event_context(w, &bec, ctx.file_format_version)?;
}
if flags.contains(BuildEventArgsFieldFlags::THREAD_ID) {
write_7bit_int(w, fields.thread_id)?;
}
if flags.contains(BuildEventArgsFieldFlags::HELP_KEYWORD) {
write_dedup_string(w, ctx, fields.help_keyword.as_deref())?;
}
if flags.contains(BuildEventArgsFieldFlags::SENDER_NAME) {
write_dedup_string(w, ctx, fields.sender_name.as_deref())?;
}
if flags.contains(BuildEventArgsFieldFlags::TIMESTAMP) {
let ts = fields.timestamp.unwrap_or_default();
write_datetime(w, ts)?;
}
if flags.contains(BuildEventArgsFieldFlags::EXTENDED) {
let ext = fields.extended.clone().unwrap_or_default();
write_dedup_string(w, ctx, ext.extended_type.as_deref())?;
write_7bit_int(w, ext.extended_metadata_index)?;
write_dedup_string(w, ctx, ext.extended_data.as_deref())?;
}
if flags.contains(BuildEventArgsFieldFlags::SUBCATEGORY) {
write_dedup_string(w, ctx, fields.subcategory.as_deref())?;
}
if flags.contains(BuildEventArgsFieldFlags::CODE) {
write_dedup_string(w, ctx, fields.code.as_deref())?;
}
if flags.contains(BuildEventArgsFieldFlags::FILE) {
write_dedup_string(w, ctx, fields.file.as_deref())?;
}
if flags.contains(BuildEventArgsFieldFlags::PROJECT_FILE) {
write_dedup_string(w, ctx, fields.project_file.as_deref())?;
}
if flags.contains(BuildEventArgsFieldFlags::LINE_NUMBER) {
write_7bit_int(w, fields.line_number)?;
}
if flags.contains(BuildEventArgsFieldFlags::COLUMN_NUMBER) {
write_7bit_int(w, fields.column_number)?;
}
if flags.contains(BuildEventArgsFieldFlags::END_LINE_NUMBER) {
write_7bit_int(w, fields.end_line_number)?;
}
if flags.contains(BuildEventArgsFieldFlags::END_COLUMN_NUMBER) {
write_7bit_int(w, fields.end_column_number)?;
}
if flags.contains(BuildEventArgsFieldFlags::ARGUMENTS) {
let args = fields.arguments.as_deref().unwrap_or(&[]);
write_7bit_int(w, args.len() as i32)?;
for a in args {
write_dedup_string(w, ctx, a.as_deref())?;
}
}
if (ctx.file_format_version < 13 && write_importance)
|| (ctx.file_format_version >= 13 && flags.contains(BuildEventArgsFieldFlags::IMPORTANCE))
{
write_7bit_int(w, fields.importance)?;
}
Ok(())
}
#[cfg(test)]
mod tests;