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
}
}
}