diff options
author | SoniEx2 <endermoneymod@gmail.com> | 2021-08-18 00:25:53 -0300 |
---|---|---|
committer | SoniEx2 <endermoneymod@gmail.com> | 2021-08-18 00:25:53 -0300 |
commit | d3b15a5d4f4c1b1f01117b0623ab4c8763e52ae4 (patch) | |
tree | 454e24f063e5a5f211af5ec78e9809969936c449 /src/data/effective.rs | |
parent | a67b0812659d1481f4c5be77ce2cf448b0b37b8c (diff) |
Prepare design of data
Diffstat (limited to 'src/data/effective.rs')
-rw-r--r-- | src/data/effective.rs | 173 |
1 files changed, 173 insertions, 0 deletions
diff --git a/src/data/effective.rs b/src/data/effective.rs new file mode 100644 index 0000000..12167dc --- /dev/null +++ b/src/data/effective.rs @@ -0,0 +1,173 @@ +// 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/>. + +//! A wrapper for [`DataSource`] that automatically handles +//! [`OverridableKind`]. + +use std::collections::BTreeSet; +use std::collections::HashSet; +use std::error; +use std::time::Duration; + +use impl_trait::impl_trait; + +use super::DataSourceBase; +use super::DataSource; +use super::Kind; +use super::OverridableKind; + +/// A wrapper for [`DataSource`] that automatically handles +/// [`OverridableKind`]. +pub struct EffectiveDataSource<T: DataSourceBase>(T); + +/// A wrapper for [`OverridableKind`] that acts like the key for Eq/Hash/Ord. +#[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) -> ( + Duration, + Result<(), Box<dyn error::Error + Send + Sync + 'static>>, + ) { + self.0.update() + } + + fn exists(&self) -> bool { + self.0.exists() + } + } + + /// 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() + } + } + } +} |