diff --git a/scopegraphs/examples/overload/main.rs b/scopegraphs/examples/overload/main.rs new file mode 100644 index 0000000..df1bb01 --- /dev/null +++ b/scopegraphs/examples/overload/main.rs @@ -0,0 +1,3 @@ +pub fn main() { + println!("Hello from overload example!") +} diff --git a/scopegraphs/src/containers/env.rs b/scopegraphs/src/containers/env.rs index 104c203..928f59e 100644 --- a/scopegraphs/src/containers/env.rs +++ b/scopegraphs/src/containers/env.rs @@ -1,18 +1,24 @@ use crate::future_wrapper::FutureWrapper; -use crate::resolve::{Env, ResolvedPath}; +use crate::resolve::{DataEquivalence, Env, ResolvedPath}; use futures::future::Shared; use std::hash::Hash; use std::rc::Rc; /// Interface for environment containers that support the operations required for query resolution. -pub trait EnvContainer<'sg, 'rslv, LABEL: 'sg, DATA: 'sg, DWFO>: +pub trait EnvContainer<'sg, 'rslv, LABEL: 'sg, DATA: 'sg>: From> + 'rslv +where + ResolvedPath<'sg, LABEL, DATA>: Eq + Hash + Clone, { - /// Creates a new, container with an empty environment. - fn empty() -> Self; + /// Creates a new container with an empty environment. + fn empty() -> Self { + Self::from(Env::new()) + } - /// Creates a new environment that contains path when `data_ok` is `true`, and is empty otherwise. - fn inject_if(data_ok: DWFO, path: ResolvedPath<'sg, LABEL, DATA>) -> Self; + /// Creates a new container with a single path. + fn single(path: ResolvedPath<'sg, LABEL, DATA>) -> Self { + Self::from(Env::single(path)) + } /// Maps the current container to a new one, based a provided mapping of the underlying environment. fn flat_map( @@ -21,23 +27,11 @@ pub trait EnvContainer<'sg, 'rslv, LABEL: 'sg, DATA: 'sg, DWFO>: ) -> Self; } -impl<'sg: 'rslv, 'rslv, LABEL: Eq, DATA: Eq> EnvContainer<'sg, 'rslv, LABEL, DATA, bool> +impl<'sg: 'rslv, 'rslv, LABEL: Eq, DATA: Eq> EnvContainer<'sg, 'rslv, LABEL, DATA> for Env<'sg, LABEL, DATA> where ResolvedPath<'sg, LABEL, DATA>: Hash + Clone, { - fn empty() -> Self { - Self::new() - } - - fn inject_if(data_ok: bool, path: ResolvedPath<'sg, LABEL, DATA>) -> Self { - if data_ok { - Self::single(path) - } else { - Self::empty() - } - } - fn flat_map( &self, map: impl 'rslv + for<'short> FnOnce(&'short Env<'sg, LABEL, DATA>) -> Self, @@ -46,25 +40,13 @@ where } } -impl<'sg: 'rslv, 'rslv, LABEL, DATA> EnvContainer<'sg, 'rslv, LABEL, DATA, bool> +impl<'sg: 'rslv, 'rslv, LABEL, DATA> EnvContainer<'sg, 'rslv, LABEL, DATA> for Rc> where ResolvedPath<'sg, LABEL, DATA>: Hash, LABEL: 'sg + Eq + Clone, DATA: 'sg + Eq, { - fn empty() -> Self { - Self::new(Env::empty()) - } - - fn inject_if(data_ok: bool, path: ResolvedPath<'sg, LABEL, DATA>) -> Self { - if data_ok { - Env::single(path).into() - } else { - Self::empty() - } - } - fn flat_map( &self, map: impl for<'short> FnOnce(&'short Env<'sg, LABEL, DATA>) -> Self, @@ -73,7 +55,6 @@ where } } -// Implementations for Results impl<'sg, LABEL: 'sg, DATA: 'sg, E> From> for Result, E> { @@ -83,23 +64,11 @@ impl<'sg, LABEL: 'sg, DATA: 'sg, E> From> } impl<'sg: 'rslv, 'rslv, LABEL: 'sg + Eq, DATA: 'sg + Eq, E: 'rslv> - EnvContainer<'sg, 'rslv, LABEL, DATA, bool> for Result, E> + EnvContainer<'sg, 'rslv, LABEL, DATA> for Result, E> where ResolvedPath<'sg, LABEL, DATA>: Hash + Clone, E: Clone, { - fn empty() -> Self { - Ok(Env::empty()) - } - - fn inject_if(data_ok: bool, path: ResolvedPath<'sg, LABEL, DATA>) -> Self { - if data_ok { - Env::single(path).into() - } else { - Env::empty().into() - } - } - fn flat_map(&self, map: impl for<'short> FnOnce(&Env<'sg, LABEL, DATA>) -> Self) -> Self { match self { Ok(env) => map(env), @@ -108,45 +77,22 @@ where } } -impl<'sg: 'rslv, 'rslv, LABEL: 'sg + Eq, DATA: 'sg + Eq, E: 'rslv> - EnvContainer<'sg, 'rslv, LABEL, DATA, Result> for Result, E> +impl<'sg: 'rslv, 'rslv, LABEL, DATA> From> + for FutureWrapper<'rslv, Env<'sg, LABEL, DATA>> where - ResolvedPath<'sg, LABEL, DATA>: Hash + Clone, - E: Clone, + LABEL: Clone, { - fn empty() -> Self { - Ok(Env::empty()) - } - - fn inject_if(data_ok: Result, path: ResolvedPath<'sg, LABEL, DATA>) -> Self { - data_ok.map(|ok| if ok { Env::single(path) } else { Env::empty() }) - } - - fn flat_map(&self, map: impl for<'short> FnOnce(&Env<'sg, LABEL, DATA>) -> Self) -> Self { - match self { - Ok(env) => map(env), - Err(err) => Err(err.clone()), - } + fn from(value: Env<'sg, LABEL, DATA>) -> Self { + FutureWrapper::new(std::future::ready(value)) } } -impl<'sg: 'rslv, 'rslv, LABEL: 'sg + Eq, DATA: 'sg + Eq> EnvContainer<'sg, 'rslv, LABEL, DATA, bool> + +impl<'sg: 'rslv, 'rslv, LABEL: 'sg + Eq, DATA: 'sg + Eq> EnvContainer<'sg, 'rslv, LABEL, DATA> for FutureWrapper<'rslv, Env<'sg, LABEL, DATA>> where ResolvedPath<'sg, LABEL, DATA>: Hash + Clone, LABEL: Clone, { - fn empty() -> Self { - FutureWrapper::new(std::future::ready(Env::empty())) - } - - fn inject_if(data_ok: bool, path: ResolvedPath<'sg, LABEL, DATA>) -> Self { - if data_ok { - Env::single(path).into() - } else { - Env::empty().into() - } - } - fn flat_map( &self, map: impl 'rslv + for<'short> FnOnce(&'short Env<'sg, LABEL, DATA>) -> Self, @@ -159,17 +105,51 @@ where } } +// Injectable + +/// Environment Container in which a path can be injected based on a condition. +pub trait Injectable<'sg, 'rslv, LABEL: 'sg, DATA: 'sg, DWFO>: + EnvContainer<'sg, 'rslv, LABEL, DATA> +where + ResolvedPath<'sg, LABEL, DATA>: Eq + Hash + Clone, +{ + /// Creates a new environment that contains path when `data_ok` is `true`, and is empty otherwise. + fn inject_if(data_ok: DWFO, path: ResolvedPath<'sg, LABEL, DATA>) -> Self; +} + +impl<'sg: 'rslv, 'rslv, LABEL: Eq + 'sg, DATA: Eq + 'sg, ENVC> + Injectable<'sg, 'rslv, LABEL, DATA, bool> for ENVC +where + ENVC: EnvContainer<'sg, 'rslv, LABEL, DATA>, + ResolvedPath<'sg, LABEL, DATA>: Eq + Hash + Clone, +{ + fn inject_if(data_ok: bool, path: ResolvedPath<'sg, LABEL, DATA>) -> Self { + if data_ok { + Self::single(path) + } else { + Self::empty() + } + } +} + +impl<'sg: 'rslv, 'rslv, LABEL: 'sg + Eq, DATA: 'sg + Eq, E: 'rslv> + Injectable<'sg, 'rslv, LABEL, DATA, Result> for Result, E> +where + ResolvedPath<'sg, LABEL, DATA>: Hash + Clone, + E: Clone, +{ + fn inject_if(data_ok: Result, path: ResolvedPath<'sg, LABEL, DATA>) -> Self { + data_ok.map(|ok| if ok { Env::single(path) } else { Env::empty() }) + } +} + impl<'sg: 'rslv, 'rslv, LABEL: 'sg + Eq, DATA: 'sg + Eq> - EnvContainer<'sg, 'rslv, LABEL, DATA, FutureWrapper<'rslv, bool>> + Injectable<'sg, 'rslv, LABEL, DATA, FutureWrapper<'rslv, bool>> for FutureWrapper<'rslv, Env<'sg, LABEL, DATA>> where ResolvedPath<'sg, LABEL, DATA>: Hash + Clone, LABEL: Clone, { - fn empty() -> Self { - FutureWrapper::new(std::future::ready(Env::empty())) - } - fn inject_if( data_ok: FutureWrapper<'rslv, bool>, path: ResolvedPath<'sg, LABEL, DATA>, @@ -183,25 +163,107 @@ where } }) } +} - fn flat_map( - &self, - map: impl 'rslv + for<'short> FnOnce(&'short Env<'sg, LABEL, DATA>) -> Self, +// Filtering + +/// Sub trait of [EnvContainer] that validates that filtering operations (for shadowing) can be applied on it. +pub trait Filterable<'sg, 'rslv, LABEL: 'sg, DATA: 'sg, DEQO>: + EnvContainer<'sg, 'rslv, LABEL, DATA> +where + ResolvedPath<'sg, LABEL, DATA>: Eq + Hash + Clone, +{ + /// Implementation of the filter operation on this container. + fn filter( + base_env: &Env<'sg, LABEL, DATA>, + sub_env: &Env<'sg, LABEL, DATA>, + equiv: &'rslv impl DataEquivalence<'sg, DATA, Output = DEQO>, + ) -> Self; +} + +impl<'sg: 'rslv, 'rslv, LABEL: 'sg, DATA: 'sg, ENVC> Filterable<'sg, 'rslv, LABEL, DATA, bool> + for ENVC +where + ENVC: EnvContainer<'sg, 'rslv, LABEL, DATA>, + Env<'sg, LABEL, DATA>: Clone, + ResolvedPath<'sg, LABEL, DATA>: Eq + Hash + Clone, +{ + fn filter( + base_env: &Env<'sg, LABEL, DATA>, + sub_env: &Env<'sg, LABEL, DATA>, + equiv: &'rslv impl DataEquivalence<'sg, DATA, Output = bool>, ) -> Self { - let fut = Shared::clone(&self.0); - FutureWrapper::new(async move { - let env = fut.await; - map(&env).0.await - }) + sub_env + .iter() + .filter(|p1| !base_env.iter().any(|p2| equiv.data_equiv(p1.data, p2.data))) + .cloned() + .collect::>() + .into() } } -impl<'sg: 'rslv, 'rslv, LABEL, DATA> From> +impl<'sg: 'rslv, 'rslv, LABEL: Clone + Eq + 'sg, DATA: Eq + 'sg, E: Clone + 'rslv> + Filterable<'sg, 'rslv, LABEL, DATA, Result> for Result, E> +where + Env<'sg, LABEL, DATA>: Clone, + ResolvedPath<'sg, LABEL, DATA>: Eq + Hash + Clone, +{ + fn filter( + base_env: &Env<'sg, LABEL, DATA>, + sub_env: &Env<'sg, LABEL, DATA>, + equiv: &'rslv impl DataEquivalence<'sg, DATA, Output = Result>, + ) -> Self { + let sub_env = sub_env.clone(); + sub_env.into_iter().try_fold( + Env::new(), + |mut filtered_env: Env<'sg, LABEL, DATA>, p1: ResolvedPath<'sg, LABEL, DATA>| { + let shadowed = base_env.iter().try_fold( + /* initially, not shadowed */ false, + |previously_shadowed: bool, p2: &ResolvedPath<'sg, LABEL, DATA>| { + if previously_shadowed { + Ok(true) // if it was shadowed, it will be + } else { + // not yet shadowed, try if current path shadows + equiv.data_equiv(p1.data, p2.data) + } + }, + )?; + // p1 is not shadowed, so add it to accumulator + if !shadowed { + filtered_env.insert(p1); + } + + Ok(filtered_env) + }, + ) + } +} + +impl<'sg: 'rslv, 'rslv, LABEL: Clone + Eq + 'sg, DATA: Eq + 'sg> + Filterable<'sg, 'rslv, LABEL, DATA, FutureWrapper<'rslv, bool>> for FutureWrapper<'rslv, Env<'sg, LABEL, DATA>> where - LABEL: Clone, + Env<'sg, LABEL, DATA>: Clone, + ResolvedPath<'sg, LABEL, DATA>: Eq + Hash + Clone, { - fn from(value: Env<'sg, LABEL, DATA>) -> Self { - FutureWrapper::new(std::future::ready(value)) + fn filter( + base_env: &Env<'sg, LABEL, DATA>, + sub_env: &Env<'sg, LABEL, DATA>, + equiv: &'rslv impl DataEquivalence<'sg, DATA, Output = FutureWrapper<'rslv, bool>>, + ) -> Self { + let base_env = base_env.clone(); + let sub_env = sub_env.clone(); + FutureWrapper::new(async move { + let mut filtered_env = Env::new(); + 'outer: for sub_path in sub_env { + for base_path in &base_env { + if equiv.data_equiv(sub_path.data, base_path.data).await { + continue 'outer; + } + } + filtered_env.insert(sub_path.clone()); + } + filtered_env + }) } } diff --git a/scopegraphs/src/containers/path.rs b/scopegraphs/src/containers/path.rs index e3e5c7e..9201dcd 100644 --- a/scopegraphs/src/containers/path.rs +++ b/scopegraphs/src/containers/path.rs @@ -4,7 +4,7 @@ use futures::future::join_all; use std::fmt::Debug; use std::hash::Hash; -use super::EnvContainer; +use super::{Filterable, Injectable}; /// Interface for path containers that support the operations required for query resolution. pub trait PathContainer<'sg, 'rslv, LABEL: 'sg, DATA: 'sg>: Debug + 'rslv { @@ -19,19 +19,25 @@ pub trait PathContainer<'sg, 'rslv, LABEL: 'sg, DATA: 'sg>: Debug + 'rslv { } /// Trait that is auto-implemented for any [PathContainer] implementation that yields a valid [EnvContainer]. -pub trait PathContainerWf<'sg, 'rslv, LABEL: 'sg, DATA: 'sg, DWFO>: +pub trait PathContainerWf<'sg, 'rslv, LABEL: 'sg, DATA: 'sg, DWFO, DEQO>: PathContainer<'sg, 'rslv, LABEL, DATA, EnvContainer = Self::EnvContainerWf> +where + ResolvedPath<'sg, LABEL, DATA>: Eq + Hash + Clone, { /// Witness that ```Self::EnvContainer``` is a valid environment container. - type EnvContainerWf: EnvContainer<'sg, 'rslv, LABEL, DATA, DWFO>; + type EnvContainerWf: Injectable<'sg, 'rslv, LABEL, DATA, DWFO> + + Filterable<'sg, 'rslv, LABEL, DATA, DEQO>; } -impl<'sg, 'rslv, LABEL, DATA, DWFO, T> PathContainerWf<'sg, 'rslv, LABEL, DATA, DWFO> for T +impl<'sg, 'rslv, LABEL, DATA, DWFO, DEQO, T> PathContainerWf<'sg, 'rslv, LABEL, DATA, DWFO, DEQO> + for T where LABEL: Debug + 'sg, DATA: 'sg, T: PathContainer<'sg, 'rslv, LABEL, DATA>, - Self::EnvContainer: EnvContainer<'sg, 'rslv, LABEL, DATA, DWFO>, + Self::EnvContainer: + Injectable<'sg, 'rslv, LABEL, DATA, DWFO> + Filterable<'sg, 'rslv, LABEL, DATA, DEQO>, + ResolvedPath<'sg, LABEL, DATA>: Eq + Hash + Clone, { type EnvContainerWf = Self::EnvContainer; } diff --git a/scopegraphs/src/containers/scope.rs b/scopegraphs/src/containers/scope.rs index 3edca07..b53a4e8 100644 --- a/scopegraphs/src/containers/scope.rs +++ b/scopegraphs/src/containers/scope.rs @@ -1,9 +1,9 @@ use std::fmt::Debug; use std::hash::Hash; -use crate::future_wrapper::FutureWrapper; use crate::resolve::Path; use crate::Scope; +use crate::{future_wrapper::FutureWrapper, resolve::ResolvedPath}; use super::{PathContainer, PathContainerWf}; @@ -36,7 +36,7 @@ pub trait ScopeContainer<'sg, 'rslv, LABEL: Debug + 'sg, DATA: 'sg>: Debug { /// # trait DBound<'sg>: Hash + Eq + 'sg {} /// /// fn test<'sg, 'rslv, LABEL: LBound<'sg>, DATA: DBound<'sg>, DWFO>( -/// cont: impl ScopeContainerWf<'sg, 'rslv, LABEL, DATA, DWFO> +/// cont: impl ScopeContainerWf<'sg, 'rslv, LABEL, DATA, DWFO, DWFO> /// ) { } /// /// # fn scope_vec<'sg, 'rslv, LABEL: LBound<'sg>, DATA: DBound<'sg>>() { @@ -64,9 +64,9 @@ pub trait ScopeContainer<'sg, 'rslv, LABEL: Debug + 'sg, DATA: 'sg>: Debug { /// # use std::hash::Hash; /// /// -/// fn test<'sg, 'rslv, LABEL: Hash + Eq + Debug + 'sg, DATA: Hash + Eq + 'sg, DWFO>(cont: impl ScopeContainerWf<'sg, 'rslv, LABEL, DATA, DWFO>) { -/// -/// } +/// fn test<'sg, 'rslv, LABEL: Clone + Hash + Eq + Debug + 'sg, DATA: Hash + Eq + 'sg, DWFO>( +/// cont: impl ScopeContainerWf<'sg, 'rslv, LABEL, DATA, DWFO, DWFO> +/// ) { } /// ``` /// /// ```no_run @@ -78,27 +78,30 @@ pub trait ScopeContainer<'sg, 'rslv, LABEL: Debug + 'sg, DATA: 'sg>: Debug { /// test::<'_, '_, (), (), bool>(Result::<_, ()>::Ok(Vec::::new())); /// test::<'_, '_, (), (), Result>(Result::<_, ()>::Ok(Vec::::new())); /// -/// fn test<'sg, 'rslv, LABEL: Hash + Eq + Debug + 'sg, DATA: Hash + Eq + 'sg, DWFO>(cont: impl ScopeContainerWf<'sg, 'rslv, LABEL, DATA, DWFO>) { -/// -/// } +/// fn test<'sg, 'rslv, LABEL: Clone + Hash + Eq + Debug + 'sg, DATA: Hash + Eq + 'sg, DWFO>( +/// cont: impl ScopeContainerWf<'sg, 'rslv, LABEL, DATA, DWFO, DWFO> +/// ) { } /// ``` /// -pub trait ScopeContainerWf<'sg, 'rslv, LABEL, DATA, DWFO>: +pub trait ScopeContainerWf<'sg, 'rslv, LABEL, DATA, DWFO, DEQO>: ScopeContainer<'sg, 'rslv, LABEL, DATA, PathContainer = Self::PathContainerWf> where LABEL: Debug + 'sg, DATA: 'sg, + ResolvedPath<'sg, LABEL, DATA>: Eq + Hash + Clone, { /// Refinement of `Self::PathContainer`, carrying proof that this scope container resolves to valid path containers. - type PathContainerWf: PathContainerWf<'sg, 'rslv, LABEL, DATA, DWFO>; + type PathContainerWf: PathContainerWf<'sg, 'rslv, LABEL, DATA, DWFO, DEQO>; } -impl<'sg, 'rslv, LABEL, DATA, DWFO, T> ScopeContainerWf<'sg, 'rslv, LABEL, DATA, DWFO> for T +impl<'sg, 'rslv, LABEL, DATA, DWFO, DEQO, T> ScopeContainerWf<'sg, 'rslv, LABEL, DATA, DWFO, DEQO> + for T where LABEL: Debug + 'sg, DATA: 'sg, T: ScopeContainer<'sg, 'rslv, LABEL, DATA>, - Self::PathContainer: PathContainerWf<'sg, 'rslv, LABEL, DATA, DWFO>, + Self::PathContainer: PathContainerWf<'sg, 'rslv, LABEL, DATA, DWFO, DEQO>, + ResolvedPath<'sg, LABEL, DATA>: Eq + Hash + Clone, { type PathContainerWf = Self::PathContainer; } diff --git a/scopegraphs/src/resolve/lookup.rs b/scopegraphs/src/resolve/lookup.rs index ee3a3f4..559972a 100644 --- a/scopegraphs/src/resolve/lookup.rs +++ b/scopegraphs/src/resolve/lookup.rs @@ -4,6 +4,8 @@ //! The versatile set of parameters guides the search to ensure the resulting environment matches //! the intended semantics of the reference. +#![allow(clippy::type_complexity)] + use std::cell::RefCell; use std::collections::HashMap; use std::fmt::Debug; @@ -14,11 +16,11 @@ use std::sync::Arc; use crate::completeness::Completeness; use crate::containers::{ - EnvContainer, PathContainer, PathContainerWf, ScopeContainer, ScopeContainerWf, + EnvContainer, Filterable, Injectable, PathContainer, PathContainerWf, ScopeContainer, + ScopeContainerWf, }; use crate::resolve::{ - DataEquivalence, DataWellformedness, EdgeOrData, Env, LabelOrder, Path, Query, Resolve, - ResolvedPath, + DataEquivalence, DataWellformedness, EdgeOrData, LabelOrder, Path, Query, Resolve, ResolvedPath, }; use crate::{Label, Scope, ScopeGraph}; use scopegraphs_regular_expressions::RegexMatcher; @@ -30,18 +32,19 @@ where LABEL: Label + Copy + Debug + Hash, DATA: Debug, CMPL: Completeness, - CMPL::GetEdgesResult<'rslv>: ScopeContainerWf<'sg, 'rslv, LABEL, DATA, DWF::Output>, + CMPL::GetEdgesResult<'rslv>: + ScopeContainerWf<'sg, 'rslv, LABEL, DATA, DWF::Output, DEq::Output>, PWF: for<'a> RegexMatcher<&'a LABEL> + 'rslv, DWF: DataWellformedness<'sg, DATA> + 'rslv, // DWF : DataWellFormedNess LO: LabelOrder