// 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 . //! 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); /// 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(pub T); impl> + OverridableKind> Kind for EffectiveKind { type Values = BTreeSet; } impl_trait! { impl EffectiveKind 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 { 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(&self, state: &mut H) { self.as_key().hash(state); } } } } /// Hack to provide appropriate impls for [`EffectiveDataSource`]. pub trait EffectiveDataSourceHelper, V> { /// Returns the values associated with this kind. fn get_values_impl(&self) -> K::Values; } impl_trait! { impl EffectiveDataSource { /// 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 DataSource where Self: EffectiveDataSourceHelper { 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 EffectiveDataSourceHelper> where K: Kind> + OverridableKind, T: DataSource { fn get_values_impl(&self) -> Vec { let mut values: Vec = 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 EffectiveDataSourceHelper< EffectiveKind, BTreeSet>, > where K: Kind> + OverridableKind, T: DataSource>, EffectiveKind: Kind>>, EffectiveKind: OverridableKind, { fn get_values_impl(&self) -> BTreeSet> { self.0.get_values() } } /// Forwards to the inner [`DataSource`]. impl trait EffectiveDataSourceHelper> where K: Kind>, T: DataSource { fn get_values_impl(&self) -> Option { self.0.get_values() } } } }