badeline-plugin 0.1.0

Darkside reflection for Rust
Documentation
use serde::Deserialize;
use std::any::TypeId;
use std::collections::HashMap;
use std::fs;
use std::path::Path;

#[derive(Debug, Clone, Deserialize)]
pub struct TypeInfo {
    pub name: String,
    pub kind: String,
    pub fields: Vec<FieldInfo>,
    pub methods: Vec<MethodInfo>,
    pub traits: Vec<String>,
}

#[derive(Debug, Clone, Deserialize)]
pub struct FieldInfo {
    pub name: String,
    pub ty: String,
}

#[derive(Debug, Clone, Deserialize)]
pub struct MethodInfo {
    pub name: String,
    pub signature: String,
}

#[derive(Debug, Deserialize)]
struct TypeRegistryRaw {
    types: HashMap<String, TypeInfo>,
}

/// Runtime registry for querying type metadata.
///
/// The registry is loaded from a JSON sidecar file generated by the
/// badeline-rustc compiler plugin.
#[derive(Debug)]
pub struct Registry {
    /// Maps type names to their metadata
    by_name: HashMap<String, TypeInfo>,
    /// Maps TypeId to type name for runtime lookup
    type_ids: HashMap<TypeId, String>,
}

impl Registry {
    /// Load the registry from a JSON file.
    pub fn load<P: AsRef<Path>>(path: P) -> Result<Self, Box<dyn std::error::Error>> {
        let content = fs::read_to_string(path)?;
        let raw: TypeRegistryRaw = serde_json::from_str(&content)?;

        let by_name: HashMap<String, TypeInfo> = raw
            .types
            .into_iter()
            .map(|(_, info)| (info.name.clone(), info))
            .collect();

        Ok(Registry {
            by_name,
            type_ids: HashMap::new(),
        })
    }

    /// Register a type for TypeId-based lookup.
    ///
    /// Call this for each type you want to query by TypeId.
    /// The type name should match the name in the registry.
    pub fn register<T: 'static>(&mut self, type_name: &str) {
        self.type_ids.insert(TypeId::of::<T>(), type_name.to_string());
    }

    /// Get type info by TypeId.
    ///
    /// The type must have been registered with `register` first.
    pub fn get<T: 'static>(&self) -> Option<&TypeInfo> {
        let type_id = TypeId::of::<T>();
        let name = self.type_ids.get(&type_id)?;
        self.by_name.get(name)
    }

    /// Get type info by name.
    pub fn get_by_name(&self, name: &str) -> Option<&TypeInfo> {
        self.by_name.get(name)
    }

    /// List all known type names.
    pub fn type_names(&self) -> impl Iterator<Item = &str> {
        self.by_name.keys().map(|s| s.as_str())
    }
}