#![allow(clippy::needless_return)]
use std::cmp::Ordering;
#[allow(dead_code)]
#[path = "../src/enums.rs"]
mod enums;
#[allow(dead_code)]
#[path = "../src/field_option.rs"]
mod field_option;
#[path = "../src/field_options.rs"]
mod field_options;
#[allow(dead_code)]
#[path = "../src/strings.rs"]
mod strings;
use enums::*;
use field_option::*;
use field_options::FIELD_OPTIONS;
fn main() {
println!("/// | Field Type | Rust Type | ETW Type");
println!("/// |------------|-----------|---------");
let mut options = Vec::from_iter(FIELD_OPTIONS);
options.sort_by(|a, b| option_name_cmp(a.option_name, b.option_name));
for field in options {
let s = field.to_markdown();
if !s.is_empty() {
println!("{}", &s);
}
}
}
fn option_name_cmp(val1: &str, val2: &str) -> Ordering {
let mut v1 = val1.as_bytes();
let mut v2 = val2.as_bytes();
let mut pos1 = 0;
let mut pos2 = 0;
const SLICE: &[u8] = b"_slice";
let slice1 = v1.ends_with(SLICE);
if slice1 {
v1 = &v1[..v1.len() - SLICE.len()];
}
let slice2 = v2.ends_with(SLICE);
if slice2 {
v2 = &v2[..v2.len() - SLICE.len()];
}
let len1 = v1.len();
let len2 = v2.len();
let cmp = loop {
if pos1 == len1 {
if pos2 == len2 {
break slice1.cmp(&slice2);
} else {
break Ordering::Less;
}
} else if pos2 == len2 {
break Ordering::Greater;
}
let ch1 = v1[pos1];
let ch2 = v2[pos2];
if ch1.is_ascii_digit() && ch2.is_ascii_digit() {
let num1 = parse_int(v1, pos1);
let num2 = parse_int(v2, pos2);
let num_cmp = num1.value.cmp(&num2.value);
if num_cmp != Ordering::Equal {
break num_cmp;
} else {
pos1 = num1.end_pos;
pos2 = num2.end_pos;
}
} else {
let char_cmp = ch1.cmp(&ch2);
if char_cmp != Ordering::Equal {
if ch1 == b'_' {
break Ordering::Less;
} else if ch2 == b'_' {
break Ordering::Greater;
} else {
break char_cmp;
}
}
pos1 += 1;
pos2 += 1;
}
};
return cmp;
}
trait ToMarkdown {
fn to_markdown(&self) -> String;
fn normal_field(&self, s: &mut String, type_path: &[&str], is_slice: bool, note: &str);
}
impl ToMarkdown for FieldOption {
fn to_markdown(&self) -> String {
let mut s = String::new();
match self.strategy {
FieldStrategy::Scalar => {
self.normal_field(&mut s, self.value_type, false, "");
}
FieldStrategy::SystemTime => {
self.normal_field(&mut s, &["std", "time", "SystemTime"], false, "systemtime");
}
FieldStrategy::Sid => {
self.normal_field(&mut s, self.value_type, true, "sid");
}
FieldStrategy::CStr => {
self.normal_field(&mut s, self.value_type, true, "cstr");
}
FieldStrategy::Counted => {
let note = if matches!(self.intype, InType::BinaryC) {
"binaryc"
} else {
""
};
self.normal_field(&mut s, self.value_type, self.value_array_count == 0, note);
}
FieldStrategy::Slice => {
self.normal_field(&mut s, self.value_type, true, "");
}
FieldStrategy::Struct
| FieldStrategy::RawStruct
| FieldStrategy::RawStructSlice
| FieldStrategy::RawData
| FieldStrategy::RawField
| FieldStrategy::RawFieldSlice
| FieldStrategy::RawMeta
| FieldStrategy::RawMetaSlice => {}
}
return s;
}
fn normal_field(&self, s: &mut String, type_path: &[&str], is_slice: bool, note: &str) {
use std::fmt::Write;
s.push_str("/// | ");
s.push('`');
s.push_str(self.option_name);
s.push('`');
if !note.is_empty() {
s.push_str(" [^");
s.push_str(note);
s.push(']');
}
s.push_str(" | `&");
if is_slice {
s.push('[');
}
if self.value_array_count != 0 {
s.push('[');
}
let type_path_start = if type_path[0] == "core" { 2 } else { 0 };
s.push_str(type_path[type_path_start]);
for type_path_part in type_path.iter().skip(type_path_start + 1) {
s.push_str("::");
s.push_str(type_path_part);
}
if self.value_array_count != 0 {
write!(s, "; {}]", self.value_array_count).unwrap();
}
if is_slice {
s.push(']');
}
s.push_str("` | ");
push_enum_value(s, "InType", intype_to_string(self.intype));
if !matches!(self.outtype, OutType::Default) {
s.push_str(" + ");
push_enum_value(s, "OutType", outtype_to_string(self.outtype));
}
}
}
struct ParseResult {
end_pos: usize,
value: u32,
}
fn push_enum_value(s: &mut String, enum_name: &str, enum_value: &str) {
s.push_str("[`");
s.push_str(enum_value);
s.push_str("`](");
s.push_str(enum_name);
s.push_str("::");
s.push_str(enum_value);
s.push(')');
}
fn parse_int(str: &[u8], pos: usize) -> ParseResult {
let mut end_pos = pos + 1;
let mut value = (str[pos] - b'0') as u32;
while end_pos != str.len() && str[end_pos].is_ascii_digit() {
value = value * 10 + (str[end_pos] - b'0') as u32;
end_pos += 1;
}
return ParseResult { end_pos, value };
}
fn intype_to_string(value: InType) -> &'static str {
return match value {
InType::Invalid => "Invalid",
InType::CStr16 => "CStr16",
InType::CStr8 => "CStr8",
InType::I8 => "I8",
InType::U8 => "U8",
InType::I16 => "I16",
InType::U16 => "U16",
InType::I32 => "I32",
InType::U32 => "U32",
InType::I64 => "I64",
InType::U64 => "U64",
InType::F32 => "F32",
InType::F64 => "F64",
InType::Bool32 => "Bool32",
InType::Binary => "Binary",
InType::Guid => "Guid",
InType::_HexSizePlatformSpecific => "HexSizePlatformSpecific",
InType::FileTime => "FileTime",
InType::SystemTime => "SystemTime",
InType::Sid => "Sid",
InType::Hex32 => "Hex32",
InType::Hex64 => "Hex64",
InType::Str16 => "Str16",
InType::Str8 => "Str8",
InType::Struct => "Struct",
InType::BinaryC => "BinaryC",
InType::ISize => "ISize",
InType::USize => "USize",
InType::HexSize => "HexSize",
};
}
fn outtype_to_string(value: OutType) -> &'static str {
return match value {
OutType::Default => "Default",
OutType::_NoPrint => "NoPrint",
OutType::String => "String",
OutType::Boolean => "Boolean",
OutType::Hex => "Hex",
OutType::Pid => "Pid",
OutType::Tid => "Tid",
OutType::Port => "Port",
OutType::IPv4 => "IPv4",
OutType::IPv6 => "IPv6",
OutType::SocketAddress => "SocketAddress",
OutType::Xml => "Xml",
OutType::Json => "Json",
OutType::Win32Error => "Win32Error",
OutType::NtStatus => "NtStatus",
OutType::HResult => "HResult",
OutType::_DateTime => "DateTime",
OutType::_Signed => "Signed",
OutType::_Unsigned => "Unsigned",
OutType::_DateTimeCultureInsensitive => "DateTimeCultureInsensitive",
OutType::Utf8 => "Utf8",
OutType::_Pkcs7WithTypeInfo => "Pkcs7WithTypeInfo",
OutType::CodePointer => "CodePointer",
OutType::DateTimeUtc => "DateTimeUtc",
};
}