summary refs log tree commit diff stats
path: root/src/data
diff options
context:
space:
mode:
Diffstat (limited to 'src/data')
-rw-r--r--src/data/effective.rs173
-rw-r--r--src/data/kinds.rs96
-rw-r--r--src/data/managers.rs98
3 files changed, 367 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()
+            }
+        }
+    }
+}
diff --git a/src/data/kinds.rs b/src/data/kinds.rs
new file mode 100644
index 0000000..d492a92
--- /dev/null
+++ b/src/data/kinds.rs
@@ -0,0 +1,96 @@
+// 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/>.
+
+//! Kinds of data for use with `DataSource`.
+
+use arcstr::ArcStr;
+
+use url::Url;
+
+use super::Kind;
+use super::OverridableKind;
+
+/// Title of an instance.
+#[derive(Clone, Eq, Hash, Ord, PartialEq, PartialOrd)]
+pub struct InstanceTitle(pub String);
+
+impl Kind for InstanceTitle {
+    /// A source may only have one `InstanceTitle`.
+    type Values = Option<Self>;
+}
+
+/// URL of an instance.
+#[derive(Clone, Eq, Hash, Ord, PartialEq, PartialOrd)]
+pub struct InstanceBaseUrl(pub Url);
+
+impl Kind for InstanceBaseUrl {
+    /// A source may only have one `InstanceBaseUrl`.
+    type Values = Option<Self>;
+}
+
+/// URL of a repo list.
+#[derive(Clone, Eq, Hash, Ord, PartialEq, PartialOrd)]
+pub struct RepoListUrl {
+    // `Url` is actually fairly expensive, but we don't usually have a lot of
+    // `RepoListUrl` around. Additionally these are generally unique.
+    /// The actual URL that references a repo list.
+    pub url: Url,
+    /// Whether this entry is active.
+    pub active: bool,
+    /// Whether this repo list is allowed to have negative entries.
+    pub allow_negative_entries: bool,
+}
+
+impl Kind for RepoListUrl {
+    /// A source may have many `RepoListUrl`.
+    type Values = Vec<Self>;
+}
+
+impl OverridableKind for RepoListUrl {
+    type Key = Url;
+
+    fn as_key(&self) -> &Self::Key {
+        &self.url
+    }
+}
+
+/// The key for a [`ProjectFork`].
+#[derive(Clone, Eq, Hash, Ord, PartialEq, PartialOrd)]
+pub struct ProjectForkKey {
+    project: ArcStr,
+    url: ArcStr,
+    branch: ArcStr,
+}
+
+/// A fork of a project.
+#[derive(Clone, Eq, Hash, Ord, PartialEq, PartialOrd)]
+pub struct ProjectFork {
+    pub key: ProjectForkKey,
+    pub active: bool,
+}
+
+impl Kind for ProjectFork {
+    /// A source may have many `ProjectFork`.
+    type Values = Vec<Self>;
+}
+
+impl OverridableKind for ProjectFork {
+    type Key = ProjectForkKey;
+
+    fn as_key(&self) -> &Self::Key {
+        &self.key
+    }
+}
diff --git a/src/data/managers.rs b/src/data/managers.rs
new file mode 100644
index 0000000..71a9484
--- /dev/null
+++ b/src/data/managers.rs
@@ -0,0 +1,98 @@
+// 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/>.
+
+use std::error;
+use std::sync::Arc;
+use std::sync::Mutex;
+use std::sync::RwLock;
+use std::time::Duration;
+
+use impl_trait::impl_trait;
+
+use super::DataSourceBase;
+use super::DataSource;
+use super::effective::EffectiveKind;
+//use super::Kind;
+use super::kinds::{InstanceTitle, InstanceBaseUrl, RepoListUrl, ProjectFork};
+//use super::OverridableKind;
+
+/// Stores multiple DataSource capable of ProjectFork
+#[derive(Default)]
+pub struct RepoListManager {
+    repos: Vec<Box<dyn DataSource<EffectiveKind<ProjectFork>> + Send + Sync>>,
+    durations: Vec<Duration>,
+    valid: usize,
+}
+
+/// Stores multiple DataSource capable of InstanceTitle, InstanceBaseUrl and
+/// RepoListUrl
+#[derive(Default)]
+pub struct ConfigManager {
+    // conceptually the actual objects
+    bases: Vec<Arc<RwLock<dyn DataSourceBase + Send + Sync>>>,
+    // conceptually just views of the above objects
+    titles: Vec<Option<Arc<RwLock<dyn DataSource<InstanceTitle> + Send + Sync>>>>,
+    urls: Vec<Option<Arc<RwLock<dyn DataSource<InstanceBaseUrl> + Send + Sync>>>>,
+    repolists: Vec<Option<Arc<RwLock<dyn DataSource<RepoListUrl> + Send + Sync>>>>,
+    durations: Vec<Duration>,
+    // add_source can be called after update.
+    valid: usize,
+}
+
+impl_trait! {
+    impl ConfigManager {
+        /// Creates a new `ConfigManager`.
+        pub fn new() -> Self {
+            Default::default()
+        }
+
+        /// Adds the given combined `DataSource` to this `ConfigManager`.
+        pub fn add_source<T>(&mut self, source: T)
+        where
+            T: DataSource<InstanceTitle>,
+            T: DataSource<InstanceBaseUrl>,
+            T: DataSource<RepoListUrl>,
+            T: Send + Sync + 'static,
+        {
+            let arc = Arc::new(RwLock::new(source));
+            self.bases.push(arc.clone());
+            self.titles.push(Some(arc.clone()));
+            self.urls.push(Some(arc.clone()));
+            self.repolists.push(Some(arc));
+        }
+
+        impl trait DataSourceBase {
+            /// Updates the contained `DataSource`s, and returns the shortest
+            /// duration for the next update.
+            /// 
+            /// # Errors
+            ///
+            /// Returns an error if any `DataSource` returns an error. Always
+            /// updates all `DataSource`s.
+            fn update(&mut self) -> (
+                Duration,
+                Result<(), Box<dyn error::Error + Send + Sync + 'static>>,
+            ) {
+                todo!()
+            }
+
+            /// Returns whether this data source contains any (valid) data.
+            fn exists(&self) -> bool {
+                todo!()
+            }
+        }
+    }
+}