use super::*;
fn replace_type_references_for_type_ref(
this: &mut TypeReference,
resolved_type_ref: &TypeReference,
declaring_type_parameters: &Vec<TypeParameter>,
) {
if declaring_type_parameters.is_empty() {
this.name.clone_from(&resolved_type_ref.name);
this.arguments.clone_from(&resolved_type_ref.arguments);
} else {
let unresolved_parsed = this.clone();
this.name.clone_from(&resolved_type_ref.name);
this.arguments.clone_from(&resolved_type_ref.arguments);
replace_specific_type_ref_by_generic_for_type_ref(
this,
&unresolved_parsed,
declaring_type_parameters,
)
}
}
fn replace_specific_type_ref_by_generic_for_type_ref(
this: &mut TypeReference,
unresolved_with_generics: &TypeReference,
declaring_type_parameters: &Vec<TypeParameter>,
) {
if declaring_type_parameters
.iter()
.any(|i| i.name() == unresolved_with_generics.name())
{
*this = unresolved_with_generics.clone();
}
for t in this
.arguments
.iter_mut()
.zip(unresolved_with_generics.arguments.iter())
{
replace_specific_type_ref_by_generic_for_type_ref(t.0, t.1, declaring_type_parameters);
}
}
pub(crate) fn replace_type_references_for_type(
this: &mut Type,
remap: &std::collections::HashMap<TypeReference, TypeReference>,
schema: &Typespace,
) {
match this {
Type::Primitive(_) => {}
Type::Struct(s) => replace_type_references_for_struct(s, remap, schema),
Type::Enum(e) => replace_type_references_for_enum(e, remap, schema),
}
}
fn replace_type_references_for_struct(
this: &mut Struct,
remap: &std::collections::HashMap<TypeReference, TypeReference>,
schema: &Typespace,
) {
for field in this.fields.iter_mut() {
replace_type_references_for_field(field, remap, schema, &this.parameters);
}
}
fn replace_type_references_for_field(
this: &mut Field,
remap: &std::collections::HashMap<TypeReference, TypeReference>,
schema: &Typespace,
declaring_type_parameters: &Vec<TypeParameter>,
) {
if let Some(new_type_ref) = remap.get(&this.type_ref) {
replace_type_references_for_type_ref(
&mut this.type_ref,
new_type_ref,
declaring_type_parameters,
);
}
if let Some(transform_callback_fn) = this.transform_callback_fn {
transform_callback_fn(&mut this.type_ref, schema);
}
}
fn replace_type_references_for_enum(
this: &mut Enum,
remap: &std::collections::HashMap<TypeReference, TypeReference>,
schema: &Typespace,
) {
for variant in this.variants.iter_mut() {
replace_type_references_for_variant(variant, remap, schema, &this.parameters);
}
}
fn replace_type_references_for_variant(
this: &mut Variant,
remap: &std::collections::HashMap<TypeReference, TypeReference>,
schema: &Typespace,
declaring_type_parameters: &Vec<TypeParameter>,
) {
for field in this.fields.iter_mut() {
replace_type_references_for_field(field, remap, schema, declaring_type_parameters);
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_replace_specific_with_generic() {
let mut resolved = TypeReference::new(
"Vec2",
vec![
TypeReference::new("Vec", vec!["u8".into()]),
TypeReference::new("Vec", vec!["u16".into(), "u8".into()]),
],
);
let unresolved = TypeReference::new(
"Vec",
vec![
TypeReference::new("Vec", vec!["T".into()]),
TypeReference::new("Vec", vec!["U".into(), "T".into()]),
],
);
let declaring_type_parameters = vec![TypeParameter::from("T"), TypeParameter::from("U")];
replace_specific_type_ref_by_generic_for_type_ref(
&mut resolved,
&unresolved,
&declaring_type_parameters,
);
assert_eq!(
resolved,
TypeReference::new(
"Vec2",
vec![
TypeReference::new("Vec", vec!["T".into()]),
TypeReference::new("Vec", vec!["U".into(), "T".into()])
]
)
);
}
#[test]
fn test_replace_specific_with_generic_more() {
let mut resolved = TypeReference::new(
"Vec2",
vec![
TypeReference::new("Vec", vec!["u8".into()]),
TypeReference::new("Vec", vec!["u16".into(), "u8".into()]),
],
);
let unresolved = TypeReference::new(
"Vec",
vec![
TypeReference::new("T", vec![]),
TypeReference::new(
"Vec",
vec![
TypeReference::new("U", vec![]),
TypeReference::new("X", vec![]),
],
),
],
);
let declaring_type_parameters = vec![TypeParameter::from("T"), TypeParameter::from("U")];
replace_specific_type_ref_by_generic_for_type_ref(
&mut resolved,
&unresolved,
&declaring_type_parameters,
);
assert_eq!(
resolved,
TypeReference::new(
"Vec2",
vec![
TypeReference::new("T", vec![]),
TypeReference::new("Vec", vec!["U".into(), "u8".into()])
]
)
);
}
#[test]
fn test_replace_circular_with_generic() {
let mut resolved = TypeReference::new("GenericStruct", vec!["A".into()]);
let unresolved = TypeReference::new(
"GenericStruct",
vec![TypeReference::new("GenericStruct", vec!["u8".into()])],
);
let declaring_type_parameters = vec![TypeParameter::from("A")];
replace_specific_type_ref_by_generic_for_type_ref(
&mut resolved,
&unresolved,
&declaring_type_parameters,
);
assert_eq!(
resolved,
TypeReference::new("GenericStruct", vec!["A".into()])
);
}
}