use eventheader_types::*;
use core::array;
use core::fmt;
#[cfg(feature = "rustc_1_77")]
use core::net;
use crate::*;
#[derive(Clone, Copy, Debug)]
pub enum PerfTextEncoding {
Latin1,
Utf8,
Utf16BE,
Utf16LE,
Utf32BE,
Utf32LE,
}
impl PerfTextEncoding {
pub fn from_bom(bytes: &[u8]) -> (Option<Self>, u8) {
let len = bytes.len();
let result = if len >= 4
&& bytes[0] == 0x00
&& bytes[1] == 0x00
&& bytes[2] == 0xFE
&& bytes[3] == 0xFF
{
(Some(Self::Utf32BE), 4)
} else if len >= 4
&& bytes[0] == 0xFF
&& bytes[1] == 0xFE
&& bytes[2] == 0x00
&& bytes[3] == 0x00
{
(Some(Self::Utf32LE), 4)
} else if len >= 2 && bytes[0] == 0xFE && bytes[1] == 0xFF {
(Some(Self::Utf16BE), 2)
} else if len >= 2 && bytes[0] == 0xFF && bytes[1] == 0xFE {
(Some(Self::Utf16LE), 2)
} else if len >= 3 && bytes[0] == 0xEF && bytes[1] == 0xBB && bytes[2] == 0xBF {
(Some(Self::Utf8), 3)
} else {
(None, 0)
};
return result;
}
}
#[repr(C)]
#[derive(Clone, Copy, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)]
pub struct PerfConvertOptions(u32);
#[allow(non_upper_case_globals)]
impl PerfConvertOptions {
pub const fn from_int(value: u32) -> Self {
return Self(value);
}
pub const fn as_int(self) -> u32 {
return self.0;
}
pub const fn has_flag(self, flag: Self) -> bool {
return self.0 & flag.0 != 0;
}
pub const fn and(self, flag: Self) -> Self {
return Self(self.0 & flag.0);
}
pub const fn and_not(self, flag: Self) -> Self {
return Self(self.0 & !flag.0);
}
pub const fn or(self, flag: Self) -> Self {
return Self(self.0 | flag.0);
}
pub const None: Self = Self(0);
pub const Space: Self = Self(0x01);
pub const RootName: Self = Self(0x02);
pub const FieldTag: Self = Self(0x04);
pub const FloatExtraPrecision: Self = Self(0x10);
pub const FloatNonFiniteAsString: Self = Self(0x20);
pub const IntHexAsString: Self = Self(0x40);
pub const BoolOutOfRangeAsString: Self = Self(0x80);
pub const UnixTimeWithinRangeAsString: Self = Self(0x100);
pub const UnixTimeOutOfRangeAsString: Self = Self(0x200);
pub const ErrnoKnownAsString: Self = Self(0x400);
pub const ErrnoUnknownAsString: Self = Self(0x800);
pub const StringControlCharsReplaceWithSpace: Self = Self(0x10000);
pub const StringControlCharsJsonEscape: Self = Self(0x20000);
pub const StringControlCharsMask: Self =
Self(Self::StringControlCharsReplaceWithSpace.0 | Self::StringControlCharsJsonEscape.0);
pub const Default: Self = Self(
Self::Space.0
| Self::RootName.0
| Self::FieldTag.0
| Self::FloatNonFiniteAsString.0
| Self::IntHexAsString.0
| Self::BoolOutOfRangeAsString.0
| Self::UnixTimeWithinRangeAsString.0
| Self::UnixTimeOutOfRangeAsString.0
| Self::ErrnoKnownAsString.0
| Self::ErrnoUnknownAsString.0
| Self::StringControlCharsReplaceWithSpace.0,
);
pub const All: Self = Self(!0u32);
}
#[repr(C)]
#[derive(Clone, Copy, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)]
pub struct PerfMetaOptions(u32);
#[allow(non_upper_case_globals)]
impl PerfMetaOptions {
pub const fn from_int(value: u32) -> Self {
return Self(value);
}
pub const fn as_int(self) -> u32 {
return self.0;
}
pub const fn has_flag(self, flag: Self) -> bool {
return self.0 & flag.0 != 0;
}
pub const fn and(self, flag: Self) -> Self {
return Self(self.0 & flag.0);
}
pub const fn and_not(self, flag: Self) -> Self {
return Self(self.0 & !flag.0);
}
pub const fn or(self, flag: Self) -> Self {
return Self(self.0 | flag.0);
}
pub const None: Self = Self(0);
pub const N: Self = Self(0x1);
pub const Time: Self = Self(0x2);
pub const Cpu: Self = Self(0x4);
pub const Pid: Self = Self(0x8);
pub const Tid: Self = Self(0x10);
pub const Id: Self = Self(0x20);
pub const Version: Self = Self(0x40);
pub const Level: Self = Self(0x80);
pub const Keyword: Self = Self(0x100);
pub const Opcode: Self = Self(0x200);
pub const Tag: Self = Self(0x400);
pub const Activity: Self = Self(0x800);
pub const RelatedActivity: Self = Self(0x1000);
pub const Provider: Self = Self(0x10000);
pub const Event: Self = Self(0x20000);
pub const Options: Self = Self(0x40000);
pub const Flags: Self = Self(0x80000);
pub const Common: Self = Self(0x100000);
pub const Default: Self = Self(0xffff);
pub const All: Self = Self(!0);
}
#[derive(Clone, Copy, Debug)]
pub struct PerfItemMetadata {
element_count: u16,
field_tag: u16,
type_size: u8,
encoding_and_array_flag_and_is_scalar: FieldEncoding,
format: FieldFormat,
byte_reader: PerfByteReader,
}
impl PerfItemMetadata {
pub const fn null() -> Self {
Self {
element_count: 0,
field_tag: 0,
type_size: 0,
encoding_and_array_flag_and_is_scalar: FieldEncoding::Invalid,
format: FieldFormat::Default,
byte_reader: PerfByteReader::new(false),
}
}
pub const fn new(
byte_reader: PerfByteReader,
encoding_and_array_flag: FieldEncoding,
format: FieldFormat,
is_scalar: bool,
type_size: u8,
element_count: u16,
field_tag: u16,
) -> Self {
debug_assert!(!encoding_and_array_flag.has_chain_flag());
debug_assert!(!format.has_chain_flag());
debug_assert!(encoding_and_array_flag.array_flags() != FieldEncoding::ArrayFlagMask);
#[cfg(debug_assertions)]
if is_scalar {
debug_assert!(element_count == 1);
} else {
debug_assert!(encoding_and_array_flag.is_array());
}
#[cfg(debug_assertions)]
if matches!(
encoding_and_array_flag.without_flags(),
FieldEncoding::Struct
) {
debug_assert!(type_size == 0); debug_assert!(format.as_int() != 0); }
let is_scalar_flag = if is_scalar {
FieldEncoding::ChainFlag
} else {
0
};
return Self {
element_count,
field_tag,
type_size,
encoding_and_array_flag_and_is_scalar: encoding_and_array_flag
.with_flags(is_scalar_flag),
format,
byte_reader,
};
}
pub const fn element_count(&self) -> u16 {
return self.element_count;
}
pub const fn field_tag(&self) -> u16 {
return self.field_tag;
}
pub const fn type_size(&self) -> u8 {
return self.type_size;
}
pub const fn encoding(&self) -> FieldEncoding {
return self.encoding_and_array_flag_and_is_scalar.without_flags();
}
pub const fn array_flag(&self) -> u8 {
return self.encoding_and_array_flag_and_is_scalar.array_flags();
}
pub const fn is_scalar(&self) -> bool {
return self.encoding_and_array_flag_and_is_scalar.has_chain_flag();
}
pub const fn is_element(&self) -> bool {
let enc = self.encoding_and_array_flag_and_is_scalar.as_int();
return 0 != (enc & FieldEncoding::ChainFlag) && 0 != (enc & FieldEncoding::ArrayFlagMask);
}
pub const fn format(&self) -> FieldFormat {
return self.format;
}
pub const fn struct_field_count(&self) -> u8 {
return self.format.as_int();
}
pub const fn byte_reader(&self) -> PerfByteReader {
return self.byte_reader;
}
pub const fn source_big_endian(&self) -> bool {
return self.byte_reader.source_big_endian();
}
}
impl Default for PerfItemMetadata {
fn default() -> Self {
PerfItemMetadata::null()
}
}
#[derive(Clone, Copy, Debug)]
pub struct PerfItemValue<'dat> {
bytes: &'dat [u8],
metadata: PerfItemMetadata,
}
impl<'dat> PerfItemValue<'dat> {
pub const fn new(bytes: &'dat [u8], metadata: PerfItemMetadata) -> Self {
#[cfg(debug_assertions)]
if metadata.type_size != 0 && !bytes.is_empty() {
debug_assert!(
bytes.len() == metadata.type_size as usize * metadata.element_count as usize
);
}
#[cfg(debug_assertions)]
if metadata.encoding().as_int() == FieldEncoding::Struct.as_int() {
debug_assert!(bytes.is_empty());
}
return Self { bytes, metadata };
}
pub fn bytes(&self) -> &'dat [u8] {
return self.bytes;
}
pub fn metadata(&self) -> PerfItemMetadata {
return self.metadata;
}
pub fn byte_reader(&self) -> PerfByteReader {
return self.metadata.byte_reader();
}
pub fn source_big_endian(&self) -> bool {
return self.metadata.source_big_endian();
}
pub fn to_u8x1(&self, index: usize) -> &'dat [u8; 1] {
debug_assert!(self.bytes.len() > index, "index out of range");
return array::from_ref(&self.bytes[index]);
}
pub fn to_u8x2(&self, index: usize) -> &'dat [u8; 2] {
const SIZE: usize = 2;
debug_assert!(self.bytes.len() / SIZE > index, "index out of range");
return self.bytes[index * SIZE..index * SIZE + SIZE]
.try_into()
.unwrap();
}
pub fn to_u8x4(&self, index: usize) -> &'dat [u8; 4] {
const SIZE: usize = 4;
debug_assert!(self.bytes.len() / SIZE > index, "index out of range");
return self.bytes[index * SIZE..index * SIZE + SIZE]
.try_into()
.unwrap();
}
pub fn to_u8x8(&self, index: usize) -> &'dat [u8; 8] {
const SIZE: usize = 8;
debug_assert!(self.bytes.len() / SIZE > index, "index out of range");
return self.bytes[index * SIZE..index * SIZE + SIZE]
.try_into()
.unwrap();
}
pub fn to_u8x16(&self, index: usize) -> &'dat [u8; 16] {
const SIZE: usize = 16;
debug_assert!(self.bytes.len() / SIZE > index, "index out of range");
return self.bytes[index * SIZE..index * SIZE + SIZE]
.try_into()
.unwrap();
}
pub fn to_u8(&self, index: usize) -> u8 {
debug_assert!(self.bytes.len() > index, "index out of range");
return self.bytes[index];
}
pub fn to_i8(&self, index: usize) -> i8 {
debug_assert!(self.bytes.len() > index, "index out of range");
return self.bytes[index] as i8;
}
pub fn to_u16(&self, index: usize) -> u16 {
debug_assert!(self.bytes.len() / 2 > index, "index out of range");
return self.metadata.byte_reader.read_u16(&self.bytes[index * 2..]);
}
pub fn to_i16(&self, index: usize) -> i16 {
debug_assert!(self.bytes.len() / 2 > index, "index out of range");
return self.metadata.byte_reader.read_i16(&self.bytes[index * 2..]);
}
pub fn to_u32(&self, index: usize) -> u32 {
debug_assert!(self.bytes.len() / 4 > index, "index out of range");
return self.metadata.byte_reader.read_u32(&self.bytes[index * 4..]);
}
pub fn to_i32(&self, index: usize) -> i32 {
debug_assert!(self.bytes.len() / 4 > index, "index out of range");
return self.metadata.byte_reader.read_i32(&self.bytes[index * 4..]);
}
pub fn to_u64(&self, index: usize) -> u64 {
debug_assert!(self.bytes.len() / 8 > index, "index out of range");
return self.metadata.byte_reader.read_u64(&self.bytes[index * 8..]);
}
pub fn to_i64(&self, index: usize) -> i64 {
debug_assert!(self.bytes.len() / 8 > index, "index out of range");
return self.metadata.byte_reader.read_i64(&self.bytes[index * 8..]);
}
pub fn to_f32(&self, index: usize) -> f32 {
debug_assert!(self.bytes.len() / 4 > index, "index out of range");
return self.metadata.byte_reader.read_f32(&self.bytes[index * 4..]);
}
pub fn to_f64(&self, index: usize) -> f64 {
debug_assert!(self.bytes.len() / 8 > index, "index out of range");
return self.metadata.byte_reader.read_f64(&self.bytes[index * 8..]);
}
pub fn to_guid(&self, index: usize) -> Guid {
const SIZE: usize = 16;
debug_assert!(self.bytes.len() / SIZE > index, "index out of range");
return Guid::from_bytes_be(
&self.bytes[index * SIZE..index * SIZE + SIZE]
.try_into()
.unwrap(),
);
}
pub fn to_port(&self, index: usize) -> u16 {
const SIZE: usize = 2;
debug_assert!(self.bytes.len() / SIZE > index, "index out of range");
return u16::from_be_bytes(
self.bytes[index * SIZE..index * SIZE + SIZE]
.try_into()
.unwrap(),
);
}
#[cfg(feature = "rustc_1_77")]
pub fn to_ipv4(&self, index: usize) -> net::Ipv4Addr {
const SIZE: usize = 4;
debug_assert!(self.bytes.len() / SIZE > index, "index out of range");
let bits: [u8; SIZE] = self.bytes[index * SIZE..index * SIZE + SIZE]
.try_into()
.unwrap();
return net::Ipv4Addr::new(bits[0], bits[1], bits[2], bits[3]);
}
#[cfg(feature = "rustc_1_77")]
pub fn to_ipv6(&self, index: usize) -> net::Ipv6Addr {
const SIZE: usize = 16;
debug_assert!(self.bytes.len() / SIZE > index, "index out of range");
let bits: &[u8; SIZE] = self.bytes[index * SIZE..index * SIZE + SIZE]
.try_into()
.unwrap();
return net::Ipv6Addr::new(
u16::from_be_bytes(bits[0..2].try_into().unwrap()),
u16::from_be_bytes(bits[2..4].try_into().unwrap()),
u16::from_be_bytes(bits[4..6].try_into().unwrap()),
u16::from_be_bytes(bits[6..8].try_into().unwrap()),
u16::from_be_bytes(bits[8..10].try_into().unwrap()),
u16::from_be_bytes(bits[10..12].try_into().unwrap()),
u16::from_be_bytes(bits[12..14].try_into().unwrap()),
u16::from_be_bytes(bits[14..16].try_into().unwrap()),
);
}
pub fn to_time32(&self, index: usize) -> i32 {
debug_assert!(self.bytes.len() / 4 > index, "index out of range");
return self.metadata.byte_reader.read_i32(&self.bytes[index * 4..]);
}
pub fn to_time64(&self, index: usize) -> i64 {
debug_assert!(self.bytes.len() / 8 > index, "index out of range");
return self.metadata.byte_reader.read_i64(&self.bytes[index * 8..]);
}
pub fn to_string_bytes(&self) -> (&'dat [u8], PerfTextEncoding) {
match self.metadata.format {
FieldFormat::String8 => return (self.bytes, PerfTextEncoding::Latin1),
FieldFormat::StringUtfBom | FieldFormat::StringXml | FieldFormat::StringJson => {
let from_bom = PerfTextEncoding::from_bom(self.bytes);
if let Some(enc) = from_bom.0 {
return (&self.bytes[from_bom.1 as usize..], enc);
}
}
_ => {}
}
let enc = match self.metadata.encoding() {
FieldEncoding::Value8
| FieldEncoding::ZStringChar8
| FieldEncoding::StringLength16Char8
| FieldEncoding::BinaryLength16Char8 => PerfTextEncoding::Utf8,
FieldEncoding::Value16
| FieldEncoding::ZStringChar16
| FieldEncoding::StringLength16Char16 => {
if self.metadata.source_big_endian() {
PerfTextEncoding::Utf16BE
} else {
PerfTextEncoding::Utf16LE
}
}
FieldEncoding::Value32
| FieldEncoding::ZStringChar32
| FieldEncoding::StringLength16Char32 => {
if self.metadata.source_big_endian() {
PerfTextEncoding::Utf32BE
} else {
PerfTextEncoding::Utf32LE
}
}
_ => PerfTextEncoding::Latin1,
};
return (self.bytes, enc);
}
pub fn write_string_to<W: fmt::Write + ?Sized>(&self, writer: &mut W) -> fmt::Result {
let (bytes, enc) = self.to_string_bytes();
let mut writer = filters::WriteFilter::new(writer); let result = match enc {
PerfTextEncoding::Latin1 => charconv::write_latin1_to(bytes, &mut writer),
PerfTextEncoding::Utf8 => {
charconv::write_utf8_with_latin1_fallback_to(bytes, &mut writer)
}
PerfTextEncoding::Utf16BE => charconv::write_utf16be_to(bytes, &mut writer),
PerfTextEncoding::Utf16LE => charconv::write_utf16le_to(bytes, &mut writer),
PerfTextEncoding::Utf32BE => charconv::write_utf32be_to(bytes, &mut writer),
PerfTextEncoding::Utf32LE => charconv::write_utf32le_to(bytes, &mut writer),
};
return result;
}
pub fn display(&self) -> display::PerfItemValueDisplay {
return display::PerfItemValueDisplay::new(self);
}
pub fn write_to<W: fmt::Write + ?Sized>(
&self,
writer: &mut W,
convert_options: PerfConvertOptions,
) -> fmt::Result {
let result = if self.metadata.is_scalar() {
self.write_scalar_to(writer, convert_options)
} else {
self.write_simple_array_to(writer, convert_options)
};
return result;
}
pub fn write_scalar_to<W: fmt::Write + ?Sized>(
&self,
writer: &mut W,
convert_options: PerfConvertOptions,
) -> fmt::Result {
debug_assert!(self.metadata.type_size as usize <= self.bytes.len());
let mut writer = writers::ValueWriter::new(writer, convert_options); let result = match self.metadata.encoding() {
FieldEncoding::Invalid => writer.write_str_with_no_filter("null"),
FieldEncoding::Struct => writer.write_fmt_with_no_filter(format_args!(
"Struct[{}]",
self.metadata.struct_field_count()
)),
FieldEncoding::Value8 => self.write_value8_to(&mut writer, 0),
FieldEncoding::Value16 => self.write_value16_to(&mut writer, 0),
FieldEncoding::Value32 => self.write_value32_to(&mut writer, 0),
FieldEncoding::Value64 => self.write_value64_to(&mut writer, 0),
FieldEncoding::Value128 => self.write_value128_to(&mut writer, 0),
FieldEncoding::ZStringChar8 => {
self.write_scalar_string_to(&mut writer, PerfTextEncoding::Utf8)
}
FieldEncoding::ZStringChar16 | FieldEncoding::StringLength16Char16 => self
.write_scalar_string_to(
&mut writer,
if self.metadata.byte_reader.source_big_endian() {
PerfTextEncoding::Utf16BE
} else {
PerfTextEncoding::Utf16LE
},
),
FieldEncoding::ZStringChar32 | FieldEncoding::StringLength16Char32 => self
.write_scalar_string_to(
&mut writer,
if self.metadata.byte_reader.source_big_endian() {
PerfTextEncoding::Utf32BE
} else {
PerfTextEncoding::Utf32LE
},
),
FieldEncoding::BinaryLength16Char8 | FieldEncoding::StringLength16Char8 => {
match self.metadata.format() {
FieldFormat::UnsignedInt => match self.bytes.len() {
0 => writer.write_str_with_no_filter("null"),
1 => writer.write_display_with_no_filter(self.to_u8(0) as u32),
2 => writer.write_display_with_no_filter(self.to_u16(0) as u32),
4 => writer.write_display_with_no_filter(self.to_u32(0)),
8 => writer.write_display_with_no_filter(self.to_u64(0)),
_ => self.write_char8_default_to(&mut writer),
},
FieldFormat::SignedInt => match self.bytes.len() {
0 => writer.write_str_with_no_filter("null"),
1 => writer.write_display_with_no_filter(self.to_i8(0) as i32),
2 => writer.write_display_with_no_filter(self.to_i16(0) as i32),
4 => writer.write_display_with_no_filter(self.to_i32(0)),
8 => writer.write_display_with_no_filter(self.to_i64(0)),
_ => self.write_char8_default_to(&mut writer),
},
FieldFormat::HexInt => match self.bytes.len() {
0 => writer.write_str_with_no_filter("null"),
1 => writer.write_hex32(self.to_u8(0) as u32),
2 => writer.write_hex32(self.to_u16(0) as u32),
4 => writer.write_hex32(self.to_u32(0)),
8 => writer.write_hex64(self.to_u64(0)),
_ => self.write_char8_default_to(&mut writer),
},
FieldFormat::Errno => match self.bytes.len() {
0 => writer.write_str_with_no_filter("null"),
4 => writer.write_errno(self.to_u32(0)),
_ => self.write_char8_default_to(&mut writer),
},
FieldFormat::Pid => match self.bytes.len() {
0 => writer.write_str_with_no_filter("null"),
4 => writer.write_display_with_no_filter(self.to_i32(0)),
_ => self.write_char8_default_to(&mut writer),
},
FieldFormat::Time => match self.bytes.len() {
0 => writer.write_str_with_no_filter("null"),
4 => writer.write_time64(self.to_time32(0) as i64),
8 => writer.write_time64(self.to_time64(0)),
_ => self.write_char8_default_to(&mut writer),
},
FieldFormat::Boolean => match self.bytes.len() {
0 => writer.write_str_with_no_filter("null"),
1 => writer.write_bool(self.to_u8(0) as u32),
2 => writer.write_bool(self.to_u16(0) as u32),
4 => writer.write_bool(self.to_u32(0)),
_ => self.write_char8_default_to(&mut writer),
},
FieldFormat::Float => match self.bytes.len() {
0 => writer.write_str_with_no_filter("null"),
4 => writer.write_float32(self.to_f32(0)),
8 => writer.write_float64(self.to_f64(0)),
_ => self.write_char8_default_to(&mut writer),
},
FieldFormat::HexBytes => writer.write_hexbytes(self.bytes),
FieldFormat::String8 => {
writer.write_latin1_with_control_chars_filter(self.bytes)
}
FieldFormat::StringUtf => {
writer.write_utf8_with_control_chars_filter(self.bytes)
}
FieldFormat::StringUtfBom
| FieldFormat::StringXml
| FieldFormat::StringJson => {
if let (Some(bom_encoding), bom_len) =
PerfTextEncoding::from_bom(self.bytes)
{
writer.write_with_control_chars_filter(
&self.bytes[bom_len as usize..],
bom_encoding,
)
} else {
writer.write_utf8_with_control_chars_filter(self.bytes)
}
}
FieldFormat::Uuid => match self.bytes.len() {
0 => writer.write_str_with_no_filter("null"),
16 => writer.write_uuid(self.to_u8x16(0)),
_ => self.write_char8_default_to(&mut writer),
},
FieldFormat::Port => match self.bytes.len() {
0 => writer.write_str_with_no_filter("null"),
2 => writer.write_display_with_no_filter(self.to_port(0) as u32),
_ => self.write_char8_default_to(&mut writer),
},
FieldFormat::IPAddress | FieldFormat::IPAddressObsolete => {
match self.bytes.len() {
0 => writer.write_str_with_no_filter("null"),
4 => writer.write_ipv4(*self.to_u8x4(0)),
16 => writer.write_ipv6(self.to_u8x16(0)),
_ => self.write_char8_default_to(&mut writer),
}
}
_ => self.write_char8_default_to(&mut writer),
}
}
_ => writer
.write_fmt_with_no_filter(format_args!("Encoding[{}]", self.metadata.encoding())),
};
return result;
}
pub fn write_simple_element_to<W: fmt::Write + ?Sized>(
&self,
writer: &mut W,
index: usize,
convert_options: PerfConvertOptions,
) -> fmt::Result {
debug_assert!(self.metadata.type_size != 0);
debug_assert!(index <= 65535);
debug_assert!((index + 1) * self.metadata.type_size as usize <= self.bytes.len());
let mut writer = writers::ValueWriter::new(writer, convert_options); let result = match self.metadata.encoding() {
FieldEncoding::Value8 => self.write_value8_to(&mut writer, index),
FieldEncoding::Value16 => self.write_value16_to(&mut writer, index),
FieldEncoding::Value32 => self.write_value32_to(&mut writer, index),
FieldEncoding::Value64 => self.write_value64_to(&mut writer, index),
FieldEncoding::Value128 => self.write_value128_to(&mut writer, index),
_ => writer
.write_fmt_with_no_filter(format_args!("Encoding[{}]", self.metadata.encoding())),
};
return result;
}
pub fn write_simple_array_to<W: fmt::Write + ?Sized>(
&self,
writer: &mut W,
convert_options: PerfConvertOptions,
) -> fmt::Result {
debug_assert!(self.metadata.type_size != 0);
let separator = if convert_options.has_flag(PerfConvertOptions::Space) {
", "
} else {
","
};
let mut writer = writers::ValueWriter::new(writer, convert_options); match self.metadata.encoding() {
FieldEncoding::Value8 => {
let count = self.bytes.len();
for i in 0..count {
if i > 0 {
writer.write_str_with_no_filter(separator)?;
}
self.write_value8_to(&mut writer, i)?;
}
}
FieldEncoding::Value16 => {
let count = self.bytes.len() / 2;
for i in 0..count {
if i > 0 {
writer.write_str_with_no_filter(separator)?;
}
self.write_value16_to(&mut writer, i)?;
}
}
FieldEncoding::Value32 => {
let count = self.bytes.len() / 4;
for i in 0..count {
if i > 0 {
writer.write_str_with_no_filter(separator)?;
}
self.write_value32_to(&mut writer, i)?;
}
}
FieldEncoding::Value64 => {
let count = self.bytes.len() / 8;
for i in 0..count {
if i > 0 {
writer.write_str_with_no_filter(separator)?;
}
self.write_value64_to(&mut writer, i)?;
}
}
FieldEncoding::Value128 => {
let count = self.bytes.len() / 16;
for i in 0..count {
if i > 0 {
writer.write_str_with_no_filter(separator)?;
}
self.write_value128_to(&mut writer, i)?;
}
}
_ => writer
.write_fmt_with_no_filter(format_args!("Encoding[{}]", self.metadata.encoding()))?,
}
return Ok(());
}
pub fn json_display(&self) -> display::PerfItemValueJsonDisplay {
return display::PerfItemValueJsonDisplay::new(self);
}
pub fn write_json_to<W: fmt::Write + ?Sized>(
&self,
writer: &mut W,
convert_options: PerfConvertOptions,
) -> fmt::Result {
let result = if self.metadata.is_scalar() {
self.write_json_scalar_to(writer, convert_options)
} else {
self.write_json_simple_array_to(writer, convert_options)
};
return result;
}
pub fn write_json_scalar_to<W: fmt::Write + ?Sized>(
&self,
writer: &mut W,
convert_options: PerfConvertOptions,
) -> fmt::Result {
let mut writer = writers::ValueWriter::new(writer, convert_options);
return self.write_json_scalar_to_impl(&mut writer);
}
pub(crate) fn write_json_scalar_to_impl<W: fmt::Write + ?Sized>(
&self,
writer: &mut writers::ValueWriter<W>,
) -> fmt::Result {
debug_assert!(self.metadata.type_size as usize <= self.bytes.len());
let result = match self.metadata.encoding() {
FieldEncoding::Invalid => writer.write_str_with_no_filter("null"),
FieldEncoding::Struct => writer.write_str_with_no_filter("{}"),
FieldEncoding::Value8 => self.write_json_value8_to(writer, 0),
FieldEncoding::Value16 => self.write_json_value16_to(writer, 0),
FieldEncoding::Value32 => self.write_json_value32_to(writer, 0),
FieldEncoding::Value64 => self.write_json_value64_to(writer, 0),
FieldEncoding::Value128 => self.write_json_value128_to(writer, 0),
FieldEncoding::ZStringChar8 => {
self.write_json_scalar_string_to(writer, PerfTextEncoding::Utf8)
}
FieldEncoding::ZStringChar16 | FieldEncoding::StringLength16Char16 => self
.write_json_scalar_string_to(
writer,
if self.metadata.byte_reader.source_big_endian() {
PerfTextEncoding::Utf16BE
} else {
PerfTextEncoding::Utf16LE
},
),
FieldEncoding::ZStringChar32 | FieldEncoding::StringLength16Char32 => self
.write_json_scalar_string_to(
writer,
if self.metadata.byte_reader.source_big_endian() {
PerfTextEncoding::Utf32BE
} else {
PerfTextEncoding::Utf32LE
},
),
FieldEncoding::BinaryLength16Char8 | FieldEncoding::StringLength16Char8 => {
match self.metadata.format() {
FieldFormat::UnsignedInt => match self.bytes.len() {
0 => writer.write_str_with_no_filter("null"),
1 => writer.write_display_with_no_filter(self.to_u8(0) as u32),
2 => writer.write_display_with_no_filter(self.to_u16(0) as u32),
4 => writer.write_display_with_no_filter(self.to_u32(0)),
8 => writer.write_display_with_no_filter(self.to_u64(0)),
_ => self.write_json_char8_default_to(writer),
},
FieldFormat::SignedInt => match self.bytes.len() {
0 => writer.write_str_with_no_filter("null"),
1 => writer.write_display_with_no_filter(self.to_i8(0) as i32),
2 => writer.write_display_with_no_filter(self.to_i16(0) as i32),
4 => writer.write_display_with_no_filter(self.to_i32(0)),
8 => writer.write_display_with_no_filter(self.to_i64(0)),
_ => self.write_json_char8_default_to(writer),
},
FieldFormat::HexInt => match self.bytes.len() {
0 => writer.write_str_with_no_filter("null"),
1 => writer.write_json_hex32(self.to_u8(0) as u32),
2 => writer.write_json_hex32(self.to_u16(0) as u32),
4 => writer.write_json_hex32(self.to_u32(0)),
8 => writer.write_json_hex64(self.to_u64(0)),
_ => self.write_json_char8_default_to(writer),
},
FieldFormat::Errno => match self.bytes.len() {
0 => writer.write_str_with_no_filter("null"),
4 => writer.write_json_errno(self.to_u32(0)),
_ => self.write_json_char8_default_to(writer),
},
FieldFormat::Pid => match self.bytes.len() {
0 => writer.write_str_with_no_filter("null"),
4 => writer.write_display_with_no_filter(self.to_i32(0)),
_ => self.write_json_char8_default_to(writer),
},
FieldFormat::Time => match self.bytes.len() {
0 => writer.write_str_with_no_filter("null"),
4 => writer.write_json_time64(self.to_time32(0) as i64),
8 => writer.write_json_time64(self.to_time64(0)),
_ => self.write_json_char8_default_to(writer),
},
FieldFormat::Boolean => match self.bytes.len() {
0 => writer.write_str_with_no_filter("null"),
1 => writer.write_json_bool(self.to_u8(0) as u32),
2 => writer.write_json_bool(self.to_u16(0) as u32),
4 => writer.write_json_bool(self.to_u32(0)),
_ => self.write_json_char8_default_to(writer),
},
FieldFormat::Float => match self.bytes.len() {
0 => writer.write_str_with_no_filter("null"),
4 => writer.write_json_float32(self.to_f32(0)),
8 => writer.write_json_float64(self.to_f64(0)),
_ => self.write_json_char8_default_to(writer),
},
FieldFormat::HexBytes => writer.write_quoted(|w| w.write_hexbytes(self.bytes)),
FieldFormat::String8 => {
writer.write_quoted(|w| w.write_latin1_with_json_escape(self.bytes))
}
FieldFormat::StringUtf => {
writer.write_quoted(|w| w.write_utf8_with_json_escape(self.bytes))
}
FieldFormat::StringUtfBom
| FieldFormat::StringXml
| FieldFormat::StringJson => {
if let (Some(bom_encoding), bom_len) =
PerfTextEncoding::from_bom(self.bytes)
{
writer.write_quoted(|w| {
w.write_with_json_escape(
&self.bytes[bom_len as usize..],
bom_encoding,
)
})
} else {
writer.write_quoted(|w| w.write_utf8_with_json_escape(self.bytes))
}
}
FieldFormat::Uuid => match self.bytes.len() {
0 => writer.write_str_with_no_filter("null"),
16 => writer.write_quoted(|w| w.write_uuid(self.to_u8x16(0))),
_ => self.write_json_char8_default_to(writer),
},
FieldFormat::Port => match self.bytes.len() {
0 => writer.write_str_with_no_filter("null"),
2 => writer.write_display_with_no_filter(self.to_port(0) as u32),
_ => self.write_json_char8_default_to(writer),
},
FieldFormat::IPAddress | FieldFormat::IPAddressObsolete => {
match self.bytes.len() {
0 => writer.write_str_with_no_filter("null"),
4 => writer.write_quoted(|w| w.write_ipv4(*self.to_u8x4(0))),
16 => writer.write_quoted(|w| w.write_ipv6(self.to_u8x16(0))),
_ => self.write_json_char8_default_to(writer),
}
}
_ => self.write_json_char8_default_to(writer),
}
}
_ => writer.write_fmt_with_no_filter(format_args!(
"\"Encoding[{}]\"",
self.metadata.encoding()
)),
};
return result;
}
pub fn write_json_simple_element_to<W: fmt::Write + ?Sized>(
&self,
writer: &mut W,
index: usize,
convert_options: PerfConvertOptions,
) -> fmt::Result {
debug_assert!(self.metadata.type_size != 0);
debug_assert!(index <= 65535);
debug_assert!((index + 1) * self.metadata.type_size as usize <= self.bytes.len());
let mut writer = writers::ValueWriter::new(writer, convert_options); let result = match self.metadata.encoding() {
FieldEncoding::Value8 => self.write_json_value8_to(&mut writer, index),
FieldEncoding::Value16 => self.write_json_value16_to(&mut writer, index),
FieldEncoding::Value32 => self.write_json_value32_to(&mut writer, index),
FieldEncoding::Value64 => self.write_json_value64_to(&mut writer, index),
FieldEncoding::Value128 => self.write_json_value128_to(&mut writer, index),
_ => writer.write_fmt_with_no_filter(format_args!(
"\"Encoding[{}]\"",
self.metadata.encoding()
)),
};
return result;
}
pub fn write_json_simple_array_to<W: fmt::Write + ?Sized>(
&self,
writer: &mut W,
convert_options: PerfConvertOptions,
) -> fmt::Result {
let mut json = writers::JsonWriter::new(writer, convert_options, false);
return self.write_json_simple_array_to_impl(&mut json);
}
pub(crate) fn write_json_simple_array_to_impl<W: fmt::Write + ?Sized>(
&self,
json: &mut writers::JsonWriter<W>,
) -> fmt::Result {
debug_assert!(self.metadata.type_size != 0);
json.write_array_begin()?;
match self.metadata.encoding() {
FieldEncoding::Value8 => {
let count = self.bytes.len();
for i in 0..count {
json.write_value(|w| self.write_json_value8_to(w, i))?;
}
}
FieldEncoding::Value16 => {
let count = self.bytes.len() / 2;
for i in 0..count {
json.write_value(|w| self.write_json_value16_to(w, i))?;
}
}
FieldEncoding::Value32 => {
let count = self.bytes.len() / 4;
for i in 0..count {
json.write_value(|w| self.write_json_value32_to(w, i))?;
}
}
FieldEncoding::Value64 => {
let count = self.bytes.len() / 8;
for i in 0..count {
json.write_value(|w| self.write_json_value64_to(w, i))?;
}
}
FieldEncoding::Value128 => {
let count = self.bytes.len() / 16;
for i in 0..count {
json.write_value(|w| self.write_json_value128_to(w, i))?;
}
}
_ => json.write_value(|w| {
w.write_fmt_with_no_filter(format_args!(
"\"Encoding[{}]\"",
self.metadata.encoding()
))
})?,
}
return json.write_array_end();
}
fn write_value8_to<W: fmt::Write + ?Sized>(
&self,
writer: &mut writers::ValueWriter<W>,
index: usize,
) -> fmt::Result {
return match self.metadata.format() {
FieldFormat::SignedInt => writer.write_display_with_no_filter(self.to_i8(index) as i32),
FieldFormat::HexInt => writer.write_hex32(self.to_u8(index) as u32),
FieldFormat::Boolean => writer.write_bool(self.to_u8(index) as u32),
FieldFormat::HexBytes => writer.write_hexbytes(self.to_u8x1(index)),
FieldFormat::String8 => {
writer.write_latin1_with_control_chars_filter(self.to_u8x1(index))
}
_ => writer.write_display_with_no_filter(self.to_u8(index) as u32), };
}
fn write_json_value8_to<W: fmt::Write + ?Sized>(
&self,
writer: &mut writers::ValueWriter<W>,
index: usize,
) -> fmt::Result {
return match self.metadata.format() {
FieldFormat::SignedInt => writer.write_display_with_no_filter(self.to_i8(index) as i32),
FieldFormat::HexInt => writer.write_json_hex32(self.to_u8(index) as u32),
FieldFormat::Boolean => writer.write_json_bool(self.to_u8(index) as u32),
FieldFormat::HexBytes => writer.write_quoted(|w| w.write_hexbytes(self.to_u8x1(index))),
FieldFormat::String8 => {
writer.write_quoted(|w| w.write_latin1_with_json_escape(self.to_u8x1(index)))
}
_ => writer.write_display_with_no_filter(self.to_u8(index) as u32), };
}
fn write_value16_to<W: fmt::Write + ?Sized>(
&self,
writer: &mut writers::ValueWriter<W>,
index: usize,
) -> fmt::Result {
return match self.metadata.format() {
FieldFormat::SignedInt => {
writer.write_display_with_no_filter(self.to_i16(index) as i32)
}
FieldFormat::HexInt => writer.write_hex32(self.to_u16(index) as u32),
FieldFormat::Boolean => writer.write_bool(self.to_u16(index) as u32),
FieldFormat::HexBytes => writer.write_hexbytes(self.to_u8x2(index)),
FieldFormat::StringUtf => {
writer.write_char32_with_control_chars_filter(self.to_u16(index) as u32)
}
FieldFormat::Port => writer.write_display_with_no_filter(self.to_port(index) as u32),
_ => writer.write_display_with_no_filter(self.to_u16(index) as u32), };
}
fn write_json_value16_to<W: fmt::Write + ?Sized>(
&self,
writer: &mut writers::ValueWriter<W>,
index: usize,
) -> fmt::Result {
return match self.metadata.format() {
FieldFormat::SignedInt => {
writer.write_display_with_no_filter(self.to_i16(index) as i32)
}
FieldFormat::HexInt => writer.write_json_hex32(self.to_u16(index) as u32),
FieldFormat::Boolean => writer.write_json_bool(self.to_u16(index) as u32),
FieldFormat::HexBytes => writer.write_quoted(|w| w.write_hexbytes(self.to_u8x2(index))),
FieldFormat::StringUtf => {
writer.write_quoted(|w| w.write_char32_with_json_escape(self.to_u16(index) as u32))
}
FieldFormat::Port => writer.write_display_with_no_filter(self.to_port(index) as u32),
_ => writer.write_display_with_no_filter(self.to_u16(index) as u32), };
}
fn write_value32_to<W: fmt::Write + ?Sized>(
&self,
writer: &mut writers::ValueWriter<W>,
index: usize,
) -> fmt::Result {
return match self.metadata.format() {
FieldFormat::SignedInt | FieldFormat::Pid => {
writer.write_display_with_no_filter(self.to_i32(index))
}
FieldFormat::HexInt => writer.write_hex32(self.to_u32(index)),
FieldFormat::Errno => writer.write_errno(self.to_u32(index)),
FieldFormat::Time => writer.write_time64(self.to_time32(index) as i64),
FieldFormat::Boolean => writer.write_bool(self.to_u32(index)),
FieldFormat::Float => writer.write_float32(self.to_f32(index)),
FieldFormat::HexBytes => writer.write_hexbytes(self.to_u8x4(index)),
FieldFormat::StringUtf => {
writer.write_char32_with_control_chars_filter(self.to_u32(index))
}
FieldFormat::IPv4 => writer.write_ipv4(*self.to_u8x4(index)),
_ => writer.write_display_with_no_filter(self.to_u32(index)), };
}
fn write_json_value32_to<W: fmt::Write + ?Sized>(
&self,
writer: &mut writers::ValueWriter<W>,
index: usize,
) -> fmt::Result {
return match self.metadata.format() {
FieldFormat::SignedInt | FieldFormat::Pid => {
writer.write_display_with_no_filter(self.to_i32(index))
}
FieldFormat::HexInt => writer.write_quoted(|w| w.write_hex32(self.to_u32(index))),
FieldFormat::Errno => writer.write_json_errno(self.to_u32(index)),
FieldFormat::Time => writer.write_json_time64(self.to_time32(index) as i64),
FieldFormat::Boolean => writer.write_json_bool(self.to_u32(index)),
FieldFormat::Float => writer.write_json_float32(self.to_f32(index)),
FieldFormat::HexBytes => writer.write_quoted(|w| w.write_hexbytes(self.to_u8x4(index))),
FieldFormat::StringUtf => {
writer.write_quoted(|w| w.write_char32_with_json_escape(self.to_u32(index)))
}
FieldFormat::IPv4 => writer.write_quoted(|w| w.write_ipv4(*self.to_u8x4(index))),
_ => writer.write_display_with_no_filter(self.to_u32(index)), };
}
fn write_value64_to<W: fmt::Write + ?Sized>(
&self,
writer: &mut writers::ValueWriter<W>,
index: usize,
) -> fmt::Result {
return match self.metadata.format() {
FieldFormat::SignedInt | FieldFormat::Pid => {
writer.write_display_with_no_filter(self.to_i64(index))
}
FieldFormat::HexInt => writer.write_hex64(self.to_u64(index)),
FieldFormat::Time => writer.write_time64(self.to_time64(index)),
FieldFormat::Float => writer.write_float64(self.to_f64(index)),
FieldFormat::HexBytes => writer.write_hexbytes(self.to_u8x8(index)),
_ => writer.write_display_with_no_filter(self.to_u64(index)), };
}
fn write_json_value64_to<W: fmt::Write + ?Sized>(
&self,
writer: &mut writers::ValueWriter<W>,
index: usize,
) -> fmt::Result {
return match self.metadata.format() {
FieldFormat::SignedInt | FieldFormat::Pid => {
writer.write_display_with_no_filter(self.to_i64(index))
}
FieldFormat::HexInt => writer.write_json_hex64(self.to_u64(index)),
FieldFormat::Time => writer.write_json_time64(self.to_time64(index)),
FieldFormat::Float => writer.write_json_float64(self.to_f64(index)),
FieldFormat::HexBytes => writer.write_quoted(|w| w.write_hexbytes(self.to_u8x8(index))),
_ => writer.write_display_with_no_filter(self.to_u64(index)), };
}
fn write_value128_to<W: fmt::Write + ?Sized>(
&self,
writer: &mut writers::ValueWriter<W>,
index: usize,
) -> fmt::Result {
return match self.metadata.format() {
FieldFormat::Uuid => writer.write_uuid(self.to_u8x16(index)),
FieldFormat::IPv6 => writer.write_ipv6(self.to_u8x16(index)),
_ => writer.write_hexbytes(self.to_u8x16(index)), };
}
fn write_json_value128_to<W: fmt::Write + ?Sized>(
&self,
writer: &mut writers::ValueWriter<W>,
index: usize,
) -> fmt::Result {
return match self.metadata.format() {
FieldFormat::Uuid => writer.write_quoted(|w| w.write_uuid(self.to_u8x16(index))),
FieldFormat::IPv6 => writer.write_quoted(|w| w.write_ipv6(self.to_u8x16(index))),
_ => writer.write_quoted(|w| w.write_hexbytes(self.to_u8x16(index))), };
}
fn write_char8_default_to<W: fmt::Write + ?Sized>(
&self,
writer: &mut writers::ValueWriter<W>,
) -> fmt::Result {
return if self.metadata.encoding() == FieldEncoding::BinaryLength16Char8 {
writer.write_hexbytes(self.bytes)
} else {
writer.write_utf8_with_control_chars_filter(self.bytes)
};
}
fn write_scalar_string_to<W: fmt::Write + ?Sized>(
&self,
writer: &mut writers::ValueWriter<W>,
default_encoding: PerfTextEncoding,
) -> fmt::Result {
let mut bytes = self.bytes;
let mut encoding = default_encoding;
match self.metadata.format {
FieldFormat::HexBytes => return writer.write_hexbytes(bytes),
FieldFormat::String8 => {
return writer.write_latin1_with_control_chars_filter(bytes);
}
FieldFormat::StringUtfBom | FieldFormat::StringXml | FieldFormat::StringJson => {
if let (Some(bom_encoding), bom_len) = PerfTextEncoding::from_bom(bytes) {
bytes = &bytes[bom_len as usize..];
encoding = bom_encoding;
}
}
_ => {}
}
return writer.write_with_control_chars_filter(bytes, encoding);
}
fn write_json_char8_default_to<W: fmt::Write + ?Sized>(
&self,
writer: &mut writers::ValueWriter<W>,
) -> fmt::Result {
return if self.metadata.encoding() == FieldEncoding::BinaryLength16Char8 {
writer.write_quoted(|w| w.write_hexbytes(self.bytes))
} else {
writer.write_quoted(|w| w.write_utf8_with_json_escape(self.bytes))
};
}
fn write_json_scalar_string_to<W: fmt::Write + ?Sized>(
&self,
writer: &mut writers::ValueWriter<W>,
default_encoding: PerfTextEncoding,
) -> fmt::Result {
let mut bytes = self.bytes;
let mut encoding = default_encoding;
let format = self.metadata.format;
match format {
FieldFormat::HexBytes => return writer.write_quoted(|w| w.write_hexbytes(bytes)),
FieldFormat::String8 => {
return writer.write_quoted(|w| w.write_latin1_with_json_escape(bytes))
}
FieldFormat::StringUtfBom | FieldFormat::StringXml | FieldFormat::StringJson => {
if let (Some(bom_encoding), bom_len) = PerfTextEncoding::from_bom(bytes) {
bytes = &bytes[bom_len as usize..];
encoding = bom_encoding;
}
}
_ => {}
}
return writer.write_quoted(|w| w.write_with_json_escape(bytes, encoding));
}
}