summary refs log blame commit diff stats
path: root/src/data/effective.rs
blob: bcfff6eef16118168b7699c1d5e7668dffdc39e3 (plain) (tree)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16















                                                                              








                                                                            


                               


                           
                      
                          

                           
                  
 







                                                                           

                                                     



                                                                             
































































                                                                               
                                            







                                      





                                                                            



























































                                                                              
// This file is part of GAnarchy - decentralized development hub
// Copyright (C) 2021  Soni L.
// 
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// 
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Affero General Public License for more details.
// 
// You should have received a copy of the GNU Affero General Public License
// along with this program.  If not, see <https://www.gnu.org/licenses/>.

//! Effective data sources and kinds.
//!
//! An [`EffectiveDataSource`] is a wrapper around [`DataSource`] that
//! handles [`OverridableKind`], particularly those built around [`Vec`].
//!
//! An [`EffectiveKind`] is a wrapper around [`Kind`] that handles
//! [`OverridableKind`], particularly those built around [`BTreeSet`].
//!
//! This asymmetry is necessary for the correct, order-dependent, semantics.

use std::collections::BTreeSet;
use std::collections::HashSet;

use impl_trait::impl_trait;

use super::DataSource;
use super::DataSourceBase;
use super::Kind;
use super::OverridableKind;
use super::Update;

#[cfg(test)]
mod tests;

/// A wrapper for [`DataSource`] that handles [`OverridableKind`].
///
/// This filters [`Vec`]-type [`Kind`]s to return only the first occurrence
/// (by key) of a value.
#[derive(Debug)]
pub struct EffectiveDataSource<T: DataSourceBase>(T);

/// A wrapper for [`OverridableKind`] for use in [`BTreeSet`].
///
/// This compares like the key, allowing one to extend a [`BTreeSet`] and get
/// the appropriate override semantics.
#[repr(transparent)]
#[derive(Debug)]
pub struct EffectiveKind<T: OverridableKind>(pub T);

impl<T: Kind<Values=BTreeSet<T>> + OverridableKind> Kind for EffectiveKind<T> {
    type Values = BTreeSet<Self>;
}

impl_trait! {
    impl<T: Kind + OverridableKind> EffectiveKind<T> where Self: Kind {
        impl trait OverridableKind {
            type Key = T::Key;

            fn as_key(&self) -> &Self::Key {
                self.0.as_key()
            }
        }
        impl trait PartialEq {
            fn eq(&self, other: &Self) -> bool {
                self.as_key().eq(other.as_key())
            }
            fn ne(&self, other: &Self) -> bool {
                self.as_key().ne(other.as_key())
            }
        }
        impl trait Eq {
        }
        impl trait PartialOrd {
            fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
                Some(self.cmp(other))
            }
        }
        impl trait Ord {
            fn cmp(&self, other: &Self) -> std::cmp::Ordering {
                self.as_key().cmp(other.as_key())
            }
        }
        impl trait std::hash::Hash {
            fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
                self.as_key().hash(state);
            }
        }
    }
}

/// Hack to provide appropriate impls for [`EffectiveDataSource`].
pub trait EffectiveDataSourceHelper<K: Kind<Values=V>, V> {
    /// Returns the values associated with this kind.
    fn get_values_impl(&self) -> K::Values;
}

impl_trait! {
    impl<T: DataSourceBase> EffectiveDataSource<T> {
        /// Wraps the given [`DataSource`].
        pub fn new(source: T) -> Self {
            Self(source)
        }

        /// Unwraps and returns the inner [`DataSource`].
        pub fn into_inner(self) -> T {
            self.0
        }

        /// Forwards to the inner [`DataSourceBase`].
        impl trait DataSourceBase {
            fn update(&mut self) -> Update {
                self.0.update()
            }

            fn exists(&self) -> bool {
                self.0.exists()
            }
        }

        impl trait std::fmt::Display {
            fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
                self.0.fmt(f)
            }
        }

        /// Filters the inner [`DataSource`] using the appropriate impl.
        impl trait<K: Kind> DataSource<K>
        where
            Self: EffectiveDataSourceHelper<K, K::Values>
        {
            fn get_values(&self) -> K::Values {
                self.get_values_impl()
            }
        }

        /// Filters the inner [`DataSource`] such that only the first instance
        /// of a given key is returned.
        impl trait<K> EffectiveDataSourceHelper<K, Vec<K>>
        where
            K: Kind<Values=Vec<K>> + OverridableKind,
            T: DataSource<K>
        {
            fn get_values_impl(&self) -> Vec<K> {
                let mut values: Vec<K> = self.0.get_values();
                let mut seen = HashSet::<&K::Key>::new();
                let mut keep = Vec::with_capacity(values.len());
                for value in &values {
                    keep.push(seen.insert(value.as_key()));
                }
                drop(seen);
                let mut keep = keep.into_iter();
                values.retain(|_| keep.next().unwrap());
                values
            }
        }

        /// Forwards to the inner [`DataSource`] as there's no filtering we
        /// can/need to do here.
        impl trait<K> EffectiveDataSourceHelper<
            EffectiveKind<K>, 
            BTreeSet<EffectiveKind<K>>,
        >
        where
            K: Kind<Values=BTreeSet<K>> + OverridableKind,
            T: DataSource<EffectiveKind<K>>,
            EffectiveKind<K>: Kind<Values=BTreeSet<EffectiveKind<K>>>,
            EffectiveKind<K>: OverridableKind,
        {
            fn get_values_impl(&self) -> BTreeSet<EffectiveKind<K>> {
                self.0.get_values()
            }
        }

        /// Forwards to the inner [`DataSource`].
        impl trait<K> EffectiveDataSourceHelper<K, Option<K>>
        where
            K: Kind<Values=Option<K>>,
            T: DataSource<K>
        {
            fn get_values_impl(&self) -> Option<K> {
                self.0.get_values()
            }
        }
    }
}