use crate::structures::util::read_uintptr;
#[derive(Debug, Clone, Copy, Default)]
pub struct GoSlice {
pub ptr: u64,
pub len: u64,
pub cap: u64,
}
#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
pub struct GoStr {
pub ptr: u64,
pub len: u64,
}
impl GoStr {
pub fn size(ps: u8) -> usize {
(ps as usize).saturating_mul(2)
}
pub fn parse(data: &[u8], offset: usize, ps: u8) -> Option<Self> {
let p = ps as usize;
Some(Self {
ptr: read_uintptr(data, offset, ps)?,
len: read_uintptr(data, offset.checked_add(p)?, ps)?,
})
}
pub fn is_empty(&self) -> bool {
self.len == 0
}
}
impl GoSlice {
pub fn size(ps: u8) -> usize {
(ps as usize).saturating_mul(3)
}
pub fn parse(data: &[u8], offset: usize, ps: u8) -> Option<Self> {
let p = ps as usize;
Some(Self {
ptr: read_uintptr(data, offset, ps)?,
len: read_uintptr(data, offset.checked_add(p)?, ps)?,
cap: read_uintptr(data, offset.checked_add(p.saturating_mul(2))?, ps)?,
})
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn parse_64bit() {
let mut data = vec![0u8; 24];
data[0..8].copy_from_slice(&0x1000u64.to_le_bytes());
data[8..16].copy_from_slice(&10u64.to_le_bytes());
data[16..24].copy_from_slice(&10u64.to_le_bytes());
let s = GoSlice::parse(&data, 0, 8).unwrap();
assert_eq!(s.ptr, 0x1000);
assert_eq!(s.len, 10);
assert_eq!(s.cap, 10);
}
#[test]
fn parse_32bit() {
let mut data = vec![0u8; 12];
data[0..4].copy_from_slice(&0x2000u32.to_le_bytes());
data[4..8].copy_from_slice(&5u32.to_le_bytes());
data[8..12].copy_from_slice(&5u32.to_le_bytes());
let s = GoSlice::parse(&data, 0, 4).unwrap();
assert_eq!(s.ptr, 0x2000);
assert_eq!(s.len, 5);
}
#[test]
fn parse_at_offset() {
let mut data = vec![0u8; 32];
data[8..16].copy_from_slice(&0x3000u64.to_le_bytes());
data[16..24].copy_from_slice(&7u64.to_le_bytes());
data[24..32].copy_from_slice(&7u64.to_le_bytes());
let s = GoSlice::parse(&data, 8, 8).unwrap();
assert_eq!(s.ptr, 0x3000);
assert_eq!(s.len, 7);
}
#[test]
fn parse_too_short() {
let data = vec![0u8; 20];
assert!(GoSlice::parse(&data, 0, 8).is_none());
}
#[test]
fn size_calculations() {
assert_eq!(GoSlice::size(4), 12);
assert_eq!(GoSlice::size(8), 24);
}
}