Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Ensure data equivalences can be delayed #63

Merged
merged 8 commits into from
Oct 30, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions scopegraphs/examples/overload/main.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
pub fn main() {
println!("Hello from overload example!")
}
248 changes: 155 additions & 93 deletions scopegraphs/src/containers/env.rs
Original file line number Diff line number Diff line change
@@ -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<Env<'sg, LABEL, DATA>> + '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(
Expand All @@ -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,
Expand All @@ -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<Env<'sg, LABEL, DATA>>
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,
Expand All @@ -73,7 +55,6 @@ where
}
}

// Implementations for Results
impl<'sg, LABEL: 'sg, DATA: 'sg, E> From<Env<'sg, LABEL, DATA>>
for Result<Env<'sg, LABEL, DATA>, E>
{
Expand All @@ -83,23 +64,11 @@ impl<'sg, LABEL: 'sg, DATA: 'sg, E> From<Env<'sg, LABEL, DATA>>
}

impl<'sg: 'rslv, 'rslv, LABEL: 'sg + Eq, DATA: 'sg + Eq, E: 'rslv>
EnvContainer<'sg, 'rslv, LABEL, DATA, bool> for Result<Env<'sg, LABEL, DATA>, E>
EnvContainer<'sg, 'rslv, LABEL, DATA> for Result<Env<'sg, LABEL, DATA>, 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),
Expand All @@ -108,45 +77,22 @@ where
}
}

impl<'sg: 'rslv, 'rslv, LABEL: 'sg + Eq, DATA: 'sg + Eq, E: 'rslv>
EnvContainer<'sg, 'rslv, LABEL, DATA, Result<bool, E>> for Result<Env<'sg, LABEL, DATA>, E>
impl<'sg: 'rslv, 'rslv, LABEL, DATA> From<Env<'sg, LABEL, DATA>>
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<bool, E>, 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,
Expand All @@ -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<bool, E>> for Result<Env<'sg, LABEL, DATA>, E>
where
ResolvedPath<'sg, LABEL, DATA>: Hash + Clone,
E: Clone,
{
fn inject_if(data_ok: Result<bool, E>, 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>,
Expand All @@ -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::<Env<_, _>>()
.into()
}
}

impl<'sg: 'rslv, 'rslv, LABEL, DATA> From<Env<'sg, LABEL, DATA>>
impl<'sg: 'rslv, 'rslv, LABEL: Clone + Eq + 'sg, DATA: Eq + 'sg, E: Clone + 'rslv>
Filterable<'sg, 'rslv, LABEL, DATA, Result<bool, E>> for Result<Env<'sg, LABEL, DATA>, 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<bool, E>>,
) -> 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
})
}
}
16 changes: 11 additions & 5 deletions scopegraphs/src/containers/path.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand All @@ -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;
}
Expand Down
Loading
Loading