use scroll::ctx::TryFromCtx;
use crate::common::*;
use crate::tpi::constants::*;
#[inline]
fn parse_optional_id_index(buf: &mut ParseBuffer<'_>) -> Result<Option<IdIndex>> {
Ok(match buf.parse()? {
IdIndex(0) => None,
index => Some(index),
})
}
#[inline]
fn parse_string<'t>(leaf: u16, buf: &mut ParseBuffer<'t>) -> Result<RawString<'t>> {
if leaf > LF_ST_MAX {
buf.parse_cstring()
} else {
buf.parse_u8_pascal_string()
}
}
#[non_exhaustive]
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum IdData<'t> {
Function(FunctionId<'t>),
MemberFunction(MemberFunctionId<'t>),
BuildInfo(BuildInfoId),
StringList(StringListId),
String(StringId<'t>),
UserDefinedTypeSource(UserDefinedTypeSourceId),
}
impl<'t> IdData<'t> {}
impl<'t> TryFromCtx<'t, scroll::Endian> for IdData<'t> {
type Error = Error;
fn try_from_ctx(this: &'t [u8], _ctx: scroll::Endian) -> Result<(Self, usize)> {
let mut buf = ParseBuffer::from(this);
let leaf = buf.parse_u16()?;
let data = match leaf {
LF_FUNC_ID => IdData::Function(FunctionId {
scope: parse_optional_id_index(&mut buf)?,
function_type: buf.parse()?,
name: parse_string(leaf, &mut buf)?,
}),
LF_MFUNC_ID => IdData::MemberFunction(MemberFunctionId {
parent: buf.parse()?,
function_type: buf.parse()?,
name: parse_string(leaf, &mut buf)?,
}),
LF_BUILDINFO => IdData::BuildInfo({
let count = buf.parse::<u16>()?;
let mut arguments = Vec::with_capacity(count as usize);
for _ in 0..count {
arguments.push(buf.parse()?);
}
BuildInfoId { arguments }
}),
LF_SUBSTR_LIST => IdData::StringList({
let count = buf.parse::<u32>()?;
let mut substrings = Vec::with_capacity(count as usize);
for _ in 0..count {
substrings.push(buf.parse()?);
}
StringListId { substrings }
}),
LF_STRING_ID => IdData::String(StringId {
substrings: parse_optional_id_index(&mut buf)?,
name: parse_string(leaf, &mut buf)?,
}),
LF_UDT_SRC_LINE | LF_UDT_MOD_SRC_LINE => {
let udt = buf.parse()?;
let file_id = buf.parse()?;
let line = buf.parse()?;
let source_file = if leaf == self::LF_UDT_SRC_LINE {
UserDefinedTypeSourceFileRef::Local(IdIndex(file_id))
} else {
UserDefinedTypeSourceFileRef::Remote(buf.parse()?, StringRef(file_id))
};
IdData::UserDefinedTypeSource(UserDefinedTypeSourceId {
udt,
source_file,
line,
})
}
_ => return Err(Error::UnimplementedTypeKind(leaf)),
};
Ok((data, buf.pos()))
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct FunctionId<'t> {
pub scope: Option<IdIndex>,
pub function_type: TypeIndex,
pub name: RawString<'t>,
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct MemberFunctionId<'t> {
pub parent: TypeIndex,
pub function_type: TypeIndex,
pub name: RawString<'t>,
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct BuildInfoId {
pub arguments: Vec<IdIndex>,
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct StringListId {
pub substrings: Vec<TypeIndex>,
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct StringId<'t> {
pub substrings: Option<IdIndex>,
pub name: RawString<'t>,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum UserDefinedTypeSourceFileRef {
Local(IdIndex),
Remote(u16, StringRef),
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct UserDefinedTypeSourceId {
pub udt: TypeIndex,
pub source_file: UserDefinedTypeSourceFileRef,
pub line: u32,
}