From d3b15a5d4f4c1b1f01117b0623ab4c8763e52ae4 Mon Sep 17 00:00:00 2001 From: SoniEx2 Date: Wed, 18 Aug 2021 00:25:53 -0300 Subject: Prepare design of data --- src/data/effective.rs | 173 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 173 insertions(+) create mode 100644 src/data/effective.rs (limited to 'src/data/effective.rs') 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 . + +//! 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); + +/// A wrapper for [`OverridableKind`] that acts like the key for Eq/Hash/Ord. +#[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) -> ( + Duration, + Result<(), Box>, + ) { + self.0.update() + } + + fn exists(&self) -> bool { + self.0.exists() + } + } + + /// 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() + } + } + } +} -- cgit 1.4.1