jfrs 0.2.5

Java Flight Recorder reader for Rust
Documentation
use crate::reader::type_descriptor::TypeDescriptor;
use crate::reader::value_descriptor::ValueDescriptor;
use crate::reader::{Chunk, Error, HeapByteStream, Result};
use crate::{EVENT_TYPE_CONSTANT_POOL, EVENT_TYPE_METADATA};

pub struct Event<'a> {
    pub byte_offset: u64,
    pub class: &'a TypeDescriptor,
    pub(crate) chunk: &'a Chunk,
    pub(crate) value: ValueDescriptor,
}

impl<'a> Event<'a> {
    pub fn value(&'a self) -> Accessor<'a> {
        Accessor {
            chunk: self.chunk,
            value: &self.value,
        }
    }
}

pub struct Accessor<'a> {
    chunk: &'a Chunk,
    pub value: &'a ValueDescriptor,
}

impl<'a> Accessor<'a> {
    pub fn new(chunk: &'a Chunk, value: &'a ValueDescriptor) -> Self {
        Self { chunk, value }
    }

    pub fn get_field(&self, name: &str) -> Option<Self> {
        self.value.get_field(name, self.chunk).map(|v| Self {
            chunk: self.chunk,
            value: v,
        })
    }

    pub fn get_field_raw(&self, name: &str) -> Option<Self> {
        self.value.get_field_raw(name, self.chunk).map(|v| Self {
            chunk: self.chunk,
            value: v,
        })
    }

    pub fn resolve(self) -> Option<Self> {
        match self.value {
            ValueDescriptor::ConstantPool {
                class_id,
                constant_index,
            } => self
                .chunk
                .constant_pool
                .get(class_id, constant_index)
                .map(|v| Self {
                    chunk: self.chunk,
                    value: v,
                }),
            _ => Some(self),
        }
    }

    pub fn as_iter(self) -> Option<impl Iterator<Item = Accessor<'a>>> {
        let array = match self.value {
            ValueDescriptor::Array(a) => a,
            ValueDescriptor::ConstantPool {
                class_id,
                constant_index,
            } => match self.chunk.constant_pool.get(class_id, constant_index) {
                Some(ValueDescriptor::Array(a)) => a,
                _ => return None,
            },
            _ => return None,
        };
        Some(array.iter().map(|v| Accessor {
            value: v,
            chunk: self.chunk,
        }))
    }
}

pub struct EventIterator<'a, 'b> {
    chunk: &'a Chunk,
    stream: &'b mut HeapByteStream,
    offset: u64,
}

impl<'a, 'b> EventIterator<'a, 'b> {
    pub fn new(chunk: &'a Chunk, stream: &'b mut HeapByteStream) -> Self {
        Self {
            chunk,
            stream,
            offset: 0,
        }
    }

    pub fn seek(&mut self, offset: u64) {
        self.offset = offset;
    }

    fn internal_next(&mut self) -> Result<Option<Event<'a>>> {
        let end_offset = self.chunk.header.chunk_body_size();

        while self.offset < end_offset {
            self.stream
                .seek(self.chunk.header.body_start_offset() + self.offset)?;
            let event_offset = self.offset;

            let size = self.stream.read_i32()?;
            let event_type = self.stream.read_i64()?;
            self.offset += size as u64;

            match event_type {
                EVENT_TYPE_METADATA | EVENT_TYPE_CONSTANT_POOL => {}
                _ => {
                    let type_desc = self
                        .chunk
                        .metadata
                        .type_pool
                        .get(event_type)
                        .ok_or(Error::ClassNotFound(event_type))?;
                    let value =
                        ValueDescriptor::try_new(self.stream, event_type, &self.chunk.metadata)?;

                    return Ok(Some(Event {
                        byte_offset: event_offset,
                        class: type_desc,
                        chunk: self.chunk,
                        value,
                    }));
                }
            }
        }
        Ok(None)
    }
}

impl<'a, 'b> Iterator for EventIterator<'a, 'b> {
    type Item = Result<Event<'a>>;

    fn next(&mut self) -> Option<Self::Item> {
        match self.internal_next() {
            Ok(Some(e)) => Some(Ok(e)),
            Ok(None) => None,
            Err(e) => Some(Err(e)),
        }
    }
}