use crate::{BufferIterator, FromBytes, ToBytes};
use crate::ksm::errors::{DebugEntryParseError, DebugSectionParseError};
use crate::ksm::{fewest_bytes_to_hold, read_var_int, write_var_int, IntSize};
use std::slice::Iter;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct DebugRange {
pub start: usize,
pub end: usize,
}
impl DebugRange {
pub fn new(start: usize, end: usize) -> Self {
DebugRange { start, end }
}
pub fn size_bytes(&self, range_size: IntSize) -> usize {
2 * range_size as usize
}
pub fn write(&self, buf: &mut Vec<u8>, range_size: IntSize) {
write_var_int(self.start as u32, buf, range_size);
write_var_int(self.end as u32, buf, range_size);
}
pub fn parse(source: &mut BufferIterator, range_size: IntSize) -> Result<Self, ()> {
let start = read_var_int(source, range_size)? as usize;
let end = read_var_int(source, range_size)? as usize;
Ok(Self { start, end })
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct DebugEntry {
pub line_number: isize,
ranges: Vec<DebugRange>,
}
impl DebugEntry {
pub fn new(line_number: isize) -> Self {
Self {
line_number,
ranges: Vec::new(),
}
}
pub fn with_range(mut self, range: DebugRange) -> Self {
self.ranges.push(range);
self
}
pub fn with_ranges(mut self, iter: impl IntoIterator<Item = DebugRange>) -> Self {
self.ranges.extend(iter);
self
}
pub fn add(&mut self, range: DebugRange) {
self.ranges.push(range);
}
pub fn number_ranges(&self) -> usize {
self.ranges.len()
}
pub fn ranges(&self) -> Iter<DebugRange> {
self.ranges.iter()
}
pub fn get_range(&self, index: usize) -> Option<&DebugRange> {
self.ranges.get(index)
}
pub fn size_bytes(&self, range_size: IntSize) -> usize {
3 + self
.ranges
.iter()
.map(|r| r.size_bytes(range_size))
.sum::<usize>()
}
pub fn write(&self, buf: &mut Vec<u8>, range_size: IntSize) {
(self.line_number as i16).to_bytes(buf);
(self.number_ranges() as u8).to_bytes(buf);
for range in self.ranges.iter() {
range.write(buf, range_size);
}
}
pub fn parse(
source: &mut BufferIterator,
range_size: IntSize,
) -> Result<Self, DebugEntryParseError> {
let line_number =
i16::from_bytes(source).map_err(|_| DebugEntryParseError::MissingLineNumber)? as isize;
let number_ranges =
u8::from_bytes(source).map_err(|_| DebugEntryParseError::MissingNumRanges)? as usize;
let mut ranges = Vec::new();
for i in 0..number_ranges {
let range = DebugRange::parse(source, range_size)
.map_err(|_| DebugEntryParseError::MissingRange(i))?;
ranges.push(range);
}
Ok(Self {
line_number,
ranges,
})
}
}
#[derive(Debug, Clone)]
pub struct DebugSection {
range_size: IntSize,
debug_entries: Vec<DebugEntry>,
}
impl DebugSection {
const BEGIN_SIZE: usize = 3;
pub fn new(first_entry: DebugEntry) -> Self {
let mut section = Self {
range_size: IntSize::One,
debug_entries: Vec::with_capacity(1),
};
section.add(first_entry);
section
}
pub fn new_empty() -> Self {
Self {
range_size: IntSize::One,
debug_entries: Vec::new(),
}
}
pub fn with_entries(mut self, iter: impl IntoIterator<Item = DebugEntry>) -> Self {
for item in iter {
self.add(item);
}
self
}
pub fn add(&mut self, entry: DebugEntry) {
for range in entry.ranges() {
let size = fewest_bytes_to_hold(range.start.max(range.end) as u32);
if size > self.range_size {
self.range_size = size;
}
}
self.debug_entries.push(entry);
}
pub fn debug_entries(&self) -> Iter<DebugEntry> {
self.debug_entries.iter()
}
pub fn range_size(&self) -> IntSize {
self.range_size
}
pub fn size_bytes(&self) -> usize {
Self::BEGIN_SIZE
+ self
.debug_entries
.iter()
.map(|e| e.size_bytes(self.range_size))
.sum::<usize>()
}
pub fn write(&self, buf: &mut Vec<u8>) {
b'%'.to_bytes(buf);
b'D'.to_bytes(buf);
(self.range_size as u8).to_bytes(buf);
for entry in self.debug_entries.iter() {
entry.write(buf, self.range_size);
}
}
pub fn parse(source: &mut BufferIterator) -> Result<Self, DebugSectionParseError> {
assert_eq!(source.next().unwrap(), b'D');
let raw_range_size =
u8::from_bytes(source).map_err(|_| DebugSectionParseError::MissingDebugRangeSize)?;
let range_size = IntSize::try_from(raw_range_size)
.map_err(|_| DebugSectionParseError::InvalidDebugRangeSize(raw_range_size))?;
let mut debug_entries = Vec::new();
while source.peek().is_some() {
let debug_entry = DebugEntry::parse(source, range_size).map_err(|e| {
DebugSectionParseError::DebugEntryParseError(source.current_index(), e)
})?;
debug_entries.push(debug_entry);
}
Ok(Self {
range_size,
debug_entries,
})
}
}
impl FromIterator<DebugEntry> for DebugSection {
fn from_iter<T: IntoIterator<Item = DebugEntry>>(iter: T) -> Self {
Self::new_empty().with_entries(iter)
}
}
#[cfg(test)]
impl PartialEq for DebugSection {
fn eq(&self, other: &Self) -> bool {
if self.size_bytes() != other.size_bytes() {
return false;
}
if self.range_size != other.range_size {
return false;
}
for (value1, value2) in self.debug_entries.iter().zip(other.debug_entries.iter()) {
if value1 != value2 {
return false;
}
}
true
}
}
#[cfg(test)]
mod tests {
use crate::ksm::sections::{DebugEntry, DebugRange, DebugSection};
#[test]
fn size() {
let mut debug_section = DebugSection::new_empty();
let entry_1 = DebugEntry::new(1).with_range(DebugRange::new(0x04, 0x16));
let entry_2 = DebugEntry::new(2).with_ranges(vec![
DebugRange::new(0x17, 0x19),
DebugRange::new(0x1a, 0x011f),
]);
debug_section.add(entry_1);
debug_section.add(entry_2);
let mut buffer = Vec::with_capacity(128);
debug_section.write(&mut buffer);
assert_eq!(debug_section.size_bytes(), buffer.len());
}
}