#![allow(dead_code)]
use super::library_sources;
use std::collections::BTreeMap;
#[derive(Debug, Default, Clone)]
pub struct Field {
pub has_default: bool,
pub flattened: bool,
pub ty: String,
}
#[derive(Debug, Default)]
pub struct Item {
pub fields: BTreeMap<String, Field>,
pub variants: Vec<String>,
pub is_enum: bool,
pub public: bool,
pub tag: Option<String>,
}
pub fn parse_items() -> BTreeMap<String, Item> {
let mut items: BTreeMap<String, Item> = BTreeMap::new();
for (_path, text) in library_sources() {
let mut current: Option<String> = None;
let mut depth = 0_i32;
let mut attrs: Vec<String> = Vec::new();
let mut container_tag: Option<String> = None;
for line in text.lines() {
let trimmed = line.trim();
if trimmed.starts_with("#[serde(") {
if current.is_none() {
if let Some(tag) = extract_quoted(trimmed, "tag = \"") {
container_tag = Some(tag);
}
}
attrs.push(trimmed.to_owned());
continue;
}
if trimmed.starts_with("#[") || trimmed.starts_with("//") {
continue;
}
if current.is_none() {
let public = trimmed.starts_with("pub ");
let declaration = trimmed.strip_prefix("pub ").unwrap_or(trimmed);
for keyword in ["struct ", "enum "] {
if let Some(rest) = declaration.strip_prefix(keyword) {
let name: String = rest
.chars()
.take_while(|c| c.is_alphanumeric() || *c == '_')
.collect();
if name.is_empty() || !rest.contains('{') {
continue;
}
let entry = items.entry(name.clone()).or_default();
entry.is_enum = keyword.starts_with("enum");
entry.public = public;
entry.tag = container_tag.take();
depth = line.matches('{').count() as i32 - line.matches('}').count() as i32;
current = (depth > 0).then_some(name);
attrs.clear();
}
}
if current.is_none() {
attrs.clear();
container_tag = None;
}
continue;
}
let name = current.clone().unwrap_or_default();
depth += line.matches('{').count() as i32 - line.matches('}').count() as i32;
if depth <= 0 {
current = None;
attrs.clear();
continue;
}
let entry = items.entry(name).or_default();
if entry.is_enum {
let is_variant = trimmed.chars().next().is_some_and(char::is_uppercase);
if is_variant {
if let Some(variant) = trimmed.split('(').next() {
entry
.variants
.push(variant.trim_end_matches([',', ' ', '{']).to_owned());
}
} else if let Some((field, ty)) = trimmed.split_once(':') {
let field = field.trim();
if !field.is_empty() && field.chars().all(|c| c.is_alphanumeric() || c == '_') {
entry.fields.insert(
field.to_owned(),
Field {
flattened: false,
has_default: attrs.join(" ").contains("default"),
ty: ty.trim().trim_end_matches(',').to_owned(),
},
);
}
}
} else {
let rest = trimmed.strip_prefix("pub ").unwrap_or(trimmed);
if let Some((raw_name, _)) = rest.split_once(':') {
let joined = attrs.join(" ");
let wire = extract_quoted(&joined, "rename = \"")
.unwrap_or_else(|| raw_name.trim().to_owned());
let ty = rest
.split_once(':')
.map(|(_, ty)| ty.trim().trim_end_matches(',').to_owned())
.unwrap_or_default();
entry.fields.insert(
wire,
Field {
flattened: joined.contains("flatten"),
has_default: joined.contains("default"),
ty,
},
);
}
}
attrs.clear();
}
}
items
}
pub fn extract_quoted(haystack: &str, prefix: &str) -> Option<String> {
let start = haystack.find(prefix)? + prefix.len();
let rest = &haystack[start..];
Some(rest[..rest.find('"')?].to_owned())
}