// 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 std::error;
use std::time::Duration;
use impl_trait::impl_trait;
use super::DataSource;
use super::DataSourceBase;
use super::Kind;
use super::OverridableKind;
#[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) -> (
Option,
Result<(), Box>,
) {
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()
}
}
}
}