use crate::core::types::{InterfaceMethod, TypeFingerprint};
use crate::core::{SharedUniverse, Type, TypeId, TypeKind};
use dashmap::DashMap;
use rayon::prelude::*;
use std::sync::Arc;
#[derive(Debug, Clone)]
pub struct QueryResult<T> {
pub item: T,
pub score: f32,
pub match_details: MatchDetails,
}
#[derive(Debug, Clone, Default)]
pub struct MatchDetails {
pub exact_match: bool,
pub fingerprint_match: bool,
pub struct_field_matches: Vec<(String, f32)>,
pub method_matches: Vec<(String, f32)>,
}
pub struct QueryEngine {
universe: SharedUniverse,
cache: DashMap<QueryKey, Arc<Vec<QueryResult<TypeId>>>>,
impl_cache: DashMap<(TypeId, TypeId), bool>,
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
struct QueryKey {
pattern: QueryPattern,
}
#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Hash)]
pub struct QueryFilterFlags(u32);
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
enum QueryPattern {
ById(TypeId),
ByFingerprint(TypeFingerprint),
Implements(TypeId), SimilarTo(TypeId),
Named(String),
}
impl QueryEngine {
pub fn new(universe: SharedUniverse) -> Self {
Self {
universe,
cache: DashMap::new(),
impl_cache: DashMap::new(),
}
}
pub fn get_type(&self, id: TypeId) -> Option<Arc<Type>> {
self.universe.get_type(id)
}
pub fn query_by_fingerprint(&self, fingerprint: TypeFingerprint) -> Vec<QueryResult<TypeId>> {
let candidates = self.universe.find_similar_types(fingerprint);
candidates
.into_iter()
.filter_map(|id| {
self.universe.get_type(id).map(|t| QueryResult {
item: id,
score: 1.0,
match_details: MatchDetails {
exact_match: t.fingerprint == fingerprint,
fingerprint_match: true,
..Default::default()
},
})
})
.collect()
}
pub fn implements_interface(&self, typ_id: TypeId, interface_id: TypeId) -> bool {
let cache_key = (typ_id, interface_id);
if let Some(result) = self.impl_cache.get(&cache_key) {
return *result;
}
let result = self.check_interface_impl(typ_id, interface_id);
self.impl_cache.insert(cache_key, result);
result
}
fn check_interface_impl(&self, typ_id: TypeId, interface_id: TypeId) -> bool {
let (type_kind, interface_kind) = match (
self.universe.get_type(typ_id),
self.universe.get_type(interface_id),
) {
(Some(t), Some(i)) => (t.kind.clone(), i.kind.clone()),
_ => return false,
};
match (&type_kind, &interface_kind) {
(_, TypeKind::Interface { methods, .. }) if methods.is_empty() => true,
(
TypeKind::Interface {
methods: type_methods,
..
},
TypeKind::Interface {
methods: iface_methods,
..
},
) => self.check_method_satisfaction(type_methods, iface_methods),
(_, TypeKind::Interface { methods, .. }) => self.check_type_implements(typ_id, methods),
_ => false,
}
}
fn check_method_satisfaction(
&self,
_type_methods: &[InterfaceMethod],
_iface_methods: &[InterfaceMethod],
) -> bool {
true
}
fn check_type_implements(&self, _typ_id: TypeId, _methods: &[InterfaceMethod]) -> bool {
true
}
pub fn find_implementors(&self, _interface_id: TypeId) -> Vec<QueryResult<TypeId>> {
Vec::new()
}
pub fn find_similar(&self, reference_id: TypeId, threshold: f32) -> Vec<QueryResult<TypeId>> {
let reference = match self.universe.get_type(reference_id) {
Some(t) => t,
None => return Vec::new(),
};
let fingerprint = reference.fingerprint;
let candidates = self.universe.find_similar_types(fingerprint);
candidates
.into_par_iter()
.filter_map(|id| {
if id == reference_id {
return None;
}
let typ = self.universe.get_type(id)?;
let similarity = self.compute_similarity(&reference, &typ);
if similarity >= threshold {
Some(QueryResult {
item: id,
score: similarity,
match_details: MatchDetails {
fingerprint_match: typ.fingerprint == fingerprint,
..Default::default()
},
})
} else {
None
}
})
.collect()
}
fn compute_similarity(&self, a: &Type, b: &Type) -> f32 {
if a.id == b.id {
return 1.0;
}
if a.fingerprint == b.fingerprint {
return 0.95;
}
match (&a.kind, &b.kind) {
(TypeKind::Struct { fields: a_fields }, TypeKind::Struct { fields: b_fields }) => {
self.struct_similarity(a_fields, b_fields)
}
(
TypeKind::Func {
params: a_params,
results: a_results,
..
},
TypeKind::Func {
params: b_params,
results: b_results,
..
},
) => self.func_similarity(a_params, a_results, b_params, b_results),
(TypeKind::Pointer { elem: a_elem }, TypeKind::Pointer { elem: b_elem })
| (TypeKind::Slice { elem: a_elem }, TypeKind::Slice { elem: b_elem })
| (TypeKind::Array { elem: a_elem, .. }, TypeKind::Array { elem: b_elem, .. }) => {
match (
self.universe.get_type(*a_elem),
self.universe.get_type(*b_elem),
) {
(Some(ae), Some(be)) => self.compute_similarity(&ae, &be) * 0.9,
_ => 0.0,
}
}
_ => 0.0,
}
}
fn struct_similarity(
&self,
a: &[crate::core::types::StructField],
b: &[crate::core::types::StructField],
) -> f32 {
if a.is_empty() || b.is_empty() {
return if a.len() == b.len() { 0.5 } else { 0.0 };
}
let mut matches = 0;
let mut total_score = 0.0;
for a_field in a {
for b_field in b {
if a_field.name == b_field.name {
matches += 1;
if let (Some(at), Some(bt)) = (
self.universe.get_type(a_field.typ),
self.universe.get_type(b_field.typ),
) {
total_score += self.compute_similarity(&at, &bt);
}
}
}
}
let coverage = (matches as f32) / (a.len().max(b.len()) as f32);
let avg_similarity = if matches > 0 {
total_score / matches as f32
} else {
0.0
};
coverage * 0.3 + avg_similarity * 0.7
}
fn func_similarity(
&self,
a_params: &[crate::core::types::FuncParam],
a_results: &[crate::core::types::FuncParam],
b_params: &[crate::core::types::FuncParam],
b_results: &[crate::core::types::FuncParam],
) -> f32 {
let params_match = self.params_similarity(a_params, b_params);
let results_match = self.params_similarity(a_results, b_results);
params_match * 0.6 + results_match * 0.4
}
fn params_similarity(
&self,
a: &[crate::core::types::FuncParam],
b: &[crate::core::types::FuncParam],
) -> f32 {
if a.len() != b.len() {
return 0.0;
}
let mut total = 0.0;
for (ap, bp) in a.iter().zip(b.iter()) {
if let (Some(at), Some(bt)) = (
self.universe.get_type(ap.typ),
self.universe.get_type(bp.typ),
) {
total += self.compute_similarity(&at, &bt);
}
}
total / a.len() as f32
}
pub fn find_by_constraint(&self, constraint: TypeConstraint) -> Vec<QueryResult<TypeId>> {
match constraint {
TypeConstraint::Implements(interface_id) => self.find_implementors(interface_id),
TypeConstraint::AssignableTo(target_id) => self.find_assignable_to(target_id),
TypeConstraint::Comparable => self.find_comparable_types(),
}
}
fn find_assignable_to(&self, target_id: TypeId) -> Vec<QueryResult<TypeId>> {
if let Some(target) = self.universe.get_type(target_id) {
self.query_by_fingerprint(target.fingerprint)
} else {
Vec::new()
}
}
fn find_comparable_types(&self) -> Vec<QueryResult<TypeId>> {
Vec::new() }
pub fn clear_cache(&self) {
self.cache.clear();
self.impl_cache.clear();
}
}
#[derive(Debug, Clone)]
pub enum TypeConstraint {
Implements(TypeId),
AssignableTo(TypeId),
Comparable,
}
#[cfg(test)]
mod tests {
use super::*;
use crate::core::{PrimitiveType, TypeUniverse};
use std::sync::Arc;
fn setup_universe() -> SharedUniverse {
Arc::new(TypeUniverse::new())
}
#[test]
fn test_get_type() {
let universe = setup_universe();
let engine = QueryEngine::new(universe);
let int_type = engine.get_type(TypeId(1));
assert!(int_type.is_some());
}
#[test]
fn test_fingerprint_query() {
let universe = setup_universe();
let engine = QueryEngine::new(universe);
let fingerprint = PrimitiveType::Int.fingerprint();
let _results = engine.query_by_fingerprint(fingerprint);
}
#[test]
fn test_query_engine_creation() {
let universe = setup_universe();
let engine = QueryEngine::new(universe);
let _ = engine.universe.type_count();
}
#[test]
fn test_cache_clear() {
let universe = setup_universe();
let engine = QueryEngine::new(universe);
engine.clear_cache();
}
#[test]
fn test_type_constraint_enum() {
let universe = setup_universe();
let engine = QueryEngine::new(universe);
let _constraint = TypeConstraint::Comparable;
let _constraint2 = TypeConstraint::AssignableTo(TypeId(1));
let _results = engine.find_by_constraint(TypeConstraint::Comparable);
}
}