use crate::structures::{goslice::GoSlice, util::read_uintptr};
#[derive(Debug, Clone, Copy, Default)]
pub struct StructTypeExtra {
pub pkg_path: u64,
pub fields: GoSlice,
}
impl StructTypeExtra {
pub fn size(ps: u8) -> usize {
(ps as usize).saturating_add(GoSlice::size(ps))
}
pub fn parse(data: &[u8], ps: u8) -> Option<Self> {
let p = ps as usize;
if data.len() < Self::size(ps) {
return None;
}
let pkg_path = read_uintptr(data, 0, ps)?;
let fields = GoSlice::parse(data, p, ps)?;
Some(Self { pkg_path, fields })
}
}
#[derive(Debug, Clone, Copy, Default)]
pub struct GoStructField {
pub name: u64,
pub typ: u64,
pub offset: u64,
}
impl GoStructField {
pub fn size(ps: u8) -> usize {
(ps as usize).saturating_mul(3)
}
pub fn parse(data: &[u8], ps: u8) -> Option<Self> {
let p = ps as usize;
if data.len() < Self::size(ps) {
return None;
}
Some(Self {
name: read_uintptr(data, 0, ps)?,
typ: read_uintptr(data, p, ps)?,
offset: read_uintptr(data, p.saturating_mul(2), ps)?,
})
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn parse_struct_type_extra_64bit() {
let mut buf = vec![0u8; 32];
buf[0..8].copy_from_slice(&0x1111u64.to_le_bytes());
buf[8..16].copy_from_slice(&0x2222u64.to_le_bytes());
buf[16..24].copy_from_slice(&5u64.to_le_bytes());
buf[24..32].copy_from_slice(&5u64.to_le_bytes());
let s = StructTypeExtra::parse(&buf, 8).unwrap();
assert_eq!(s.pkg_path, 0x1111);
assert_eq!(s.fields.ptr, 0x2222);
assert_eq!(s.fields.len, 5);
assert_eq!(s.fields.cap, 5);
}
#[test]
fn parse_struct_type_extra_32bit() {
let mut buf = vec![0u8; 16];
buf[0..4].copy_from_slice(&0x3333u32.to_le_bytes());
buf[4..8].copy_from_slice(&0x4444u32.to_le_bytes());
buf[8..12].copy_from_slice(&3u32.to_le_bytes());
buf[12..16].copy_from_slice(&3u32.to_le_bytes());
let s = StructTypeExtra::parse(&buf, 4).unwrap();
assert_eq!(s.pkg_path, 0x3333);
assert_eq!(s.fields.ptr, 0x4444);
assert_eq!(s.fields.len, 3);
}
#[test]
fn parse_go_struct_field_64bit() {
let mut buf = vec![0u8; 24];
buf[0..8].copy_from_slice(&0xAAAAu64.to_le_bytes());
buf[8..16].copy_from_slice(&0xBBBBu64.to_le_bytes());
buf[16..24].copy_from_slice(&16u64.to_le_bytes());
let f = GoStructField::parse(&buf, 8).unwrap();
assert_eq!(f.name, 0xAAAA);
assert_eq!(f.typ, 0xBBBB);
assert_eq!(f.offset, 16);
}
#[test]
fn parse_go_struct_field_32bit() {
let mut buf = vec![0u8; 12];
buf[0..4].copy_from_slice(&0xCCCCu32.to_le_bytes());
buf[4..8].copy_from_slice(&0xDDDDu32.to_le_bytes());
buf[8..12].copy_from_slice(&8u32.to_le_bytes());
let f = GoStructField::parse(&buf, 4).unwrap();
assert_eq!(f.name, 0xCCCC);
assert_eq!(f.typ, 0xDDDD);
assert_eq!(f.offset, 8);
}
#[test]
fn struct_type_extra_too_short() {
let buf = vec![0u8; 28];
assert!(StructTypeExtra::parse(&buf, 8).is_none());
}
#[test]
fn go_struct_field_too_short() {
let buf = vec![0u8; 20];
assert!(GoStructField::parse(&buf, 8).is_none());
}
#[test]
fn size_calculations() {
assert_eq!(StructTypeExtra::size(4), 16);
assert_eq!(StructTypeExtra::size(8), 32);
assert_eq!(GoStructField::size(4), 12);
assert_eq!(GoStructField::size(8), 24);
}
}