reflectapi_schema/
subst.rsuse std::collections::HashMap;
use crate::{Enum, Field, Fields, Struct, TypeParameter, TypeReference, Variant};
#[doc(hidden)]
pub fn mk_subst(
    parameters: &[TypeParameter],
    args: &[TypeReference],
) -> HashMap<String, TypeReference> {
    assert_eq!(
        parameters.len(),
        args.len(),
        "expected {} type arguments, got {}",
        parameters.len(),
        args.len()
    );
    parameters
        .iter()
        .map(|p| p.name.to_owned())
        .zip(args.iter().cloned())
        .collect()
}
pub trait Instantiate {
    fn instantiate(self, args: &[TypeReference]) -> Self;
}
#[doc(hidden)]
pub trait Substitute {
    fn subst(self, subst: &HashMap<String, TypeReference>) -> Self;
}
impl Substitute for TypeReference {
    fn subst(self, subst: &HashMap<String, TypeReference>) -> Self {
        match subst.get(&self.name) {
            Some(ty) => {
                assert!(
                    self.arguments.is_empty(),
                    "type parameter cannot have type arguments"
                );
                ty.clone()
            }
            None => TypeReference {
                name: self.name,
                arguments: self.arguments.into_iter().map(|a| a.subst(subst)).collect(),
            },
        }
    }
}
impl Substitute for Fields {
    fn subst(self, subst: &HashMap<String, TypeReference>) -> Self {
        match self {
            Fields::Named(fields) => {
                Fields::Named(fields.into_iter().map(|f| f.subst(subst)).collect())
            }
            Fields::Unnamed(fields) => {
                Fields::Unnamed(fields.into_iter().map(|f| f.subst(subst)).collect())
            }
            Fields::None => Fields::None,
        }
    }
}
impl Substitute for Field {
    fn subst(self, subst: &HashMap<String, TypeReference>) -> Self {
        Field {
            type_ref: self.type_ref.subst(subst),
            ..self
        }
    }
}
impl Substitute for Variant {
    fn subst(self, subst: &HashMap<String, TypeReference>) -> Self {
        Self {
            fields: self.fields.subst(subst),
            ..self
        }
    }
}
impl Instantiate for Struct {
    fn instantiate(self, type_args: &[TypeReference]) -> Self {
        let subst = mk_subst(&self.parameters, type_args);
        Self {
            parameters: vec![],
            fields: self.fields.subst(&subst),
            ..self
        }
    }
}
impl Instantiate for Enum {
    fn instantiate(self, type_args: &[TypeReference]) -> Self {
        let subst = mk_subst(&self.parameters, type_args);
        Self {
            parameters: vec![],
            variants: self.variants.into_iter().map(|v| v.subst(&subst)).collect(),
            ..self
        }
    }
}