use std::fmt;
use std::str::FromStr;
use crate::errors::{ParamParseError, ParseError};
use crate::tl::{Category, Flag, Parameter, ParameterType, Type};
use crate::utils::tl_id;
#[derive(Clone, Debug, PartialEq)]
pub struct Definition {
pub namespace: Vec<String>,
pub name: String,
pub id: u32,
pub params: Vec<Parameter>,
pub ty: Type,
pub category: Category,
}
impl Definition {
pub fn full_name(&self) -> String {
let cap = self.namespace.iter().map(|ns| ns.len() + 1).sum::<usize>() + self.name.len();
let mut s = String::with_capacity(cap);
for ns in &self.namespace {
s.push_str(ns);
s.push('.');
}
s.push_str(&self.name);
s
}
}
impl fmt::Display for Definition {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
for ns in &self.namespace {
write!(f, "{ns}.")?;
}
write!(f, "{}#{:x}", self.name, self.id)?;
let mut generics: Vec<&str> = Vec::new();
for p in &self.params {
if let ParameterType::Normal { ty, .. } = &p.ty {
ty.collect_generic_refs(&mut generics);
}
}
generics.sort_unstable();
generics.dedup();
for g in generics {
write!(f, " {{{g}:Type}}")?;
}
for p in &self.params {
write!(f, " {p}")?;
}
write!(f, " = {}", self.ty)
}
}
impl FromStr for Definition {
type Err = ParseError;
fn from_str(raw: &str) -> Result<Self, Self::Err> {
let raw = raw.trim();
if raw.is_empty() {
return Err(ParseError::Empty);
}
let (lhs, ty_str) = raw.split_once('=').ok_or(ParseError::MissingType)?;
let lhs = lhs.trim();
let ty_str = ty_str.trim().trim_end_matches(';').trim();
if ty_str.is_empty() {
return Err(ParseError::MissingType);
}
let mut ty = Type::from_str(ty_str).map_err(|_| ParseError::MissingType)?;
let (head, rest) = match lhs.split_once(|c: char| c.is_whitespace()) {
Some((h, r)) => (h.trim_end(), r.trim_start()),
None => (lhs, ""),
};
let (full_name, explicit_id) = match head.split_once('#') {
Some((n, id)) => (n, Some(id)),
None => (head, None),
};
let (namespace, name) = match full_name.rsplit_once('.') {
Some((ns_part, n)) => (ns_part.split('.').map(String::from).collect::<Vec<_>>(), n),
None => (Vec::new(), full_name),
};
if namespace.iter().any(|p| p.is_empty()) || name.is_empty() {
return Err(ParseError::MissingName);
}
let id = match explicit_id {
Some(hex) => u32::from_str_radix(hex.trim(), 16).map_err(ParseError::InvalidId)?,
None => tl_id(raw),
};
let mut type_defs: Vec<String> = Vec::new();
let mut flag_defs: Vec<String> = Vec::new();
let params = rest
.split_whitespace()
.filter_map(|token| match Parameter::from_str(token) {
Err(ParamParseError::TypeDef { name }) => {
type_defs.push(name);
None
}
Ok(p) => {
match &p {
Parameter {
ty: ParameterType::Flags,
..
} => {
flag_defs.push(p.name.clone());
}
Parameter {
ty:
ParameterType::Normal {
ty:
Type {
name: tn,
generic_ref: true,
..
},
..
},
..
} if !type_defs.contains(tn) => {
return Some(Err(ParseError::InvalidParam(
ParamParseError::MissingDef,
)));
}
Parameter {
ty:
ParameterType::Normal {
flag: Some(Flag { name: fn_, .. }),
..
},
..
} if !flag_defs.contains(fn_) => {
return Some(Err(ParseError::InvalidParam(
ParamParseError::MissingDef,
)));
}
_ => {}
}
Some(Ok(p))
}
Err(ParamParseError::NotImplemented) => Some(Err(ParseError::NotImplemented)),
Err(e) => Some(Err(ParseError::InvalidParam(e))),
})
.collect::<Result<Vec<_>, ParseError>>()?;
if type_defs.contains(&ty.name) {
ty.generic_ref = true;
}
Ok(Definition {
namespace,
name: name.to_owned(),
id,
params,
ty,
category: Category::Types, })
}
}