Collection work

Signed-off-by: Luca Fulchir <luca.fulchir@runesauth.com>
This commit is contained in:
Luca Fulchir 2024-11-11 16:03:34 +01:00
parent 860659548f
commit cfd50cf8be
Signed by: luca.fulchir
GPG Key ID: 8F6440603D13A78E
6 changed files with 104 additions and 30 deletions

21
Cargo.lock generated
View File

@ -77,6 +77,7 @@ dependencies = [
"quote", "quote",
"semver", "semver",
"sha3", "sha3",
"thiserror",
] ]
[[package]] [[package]]
@ -283,6 +284,26 @@ dependencies = [
"unicode-ident", "unicode-ident",
] ]
[[package]]
name = "thiserror"
version = "2.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c006c85c7651b3cf2ada4584faa36773bd07bac24acfb39f3c431b36d7e667aa"
dependencies = [
"thiserror-impl",
]
[[package]]
name = "thiserror-impl"
version = "2.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f077553d607adc1caf65430528a576c757a71ed73944b66ebb58ef2bbd243568"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]] [[package]]
name = "typenum" name = "typenum"
version = "1.17.0" version = "1.17.0"

View File

@ -42,7 +42,7 @@ pub fn repository(attrs: TokenStream, input: TokenStream) -> TokenStream {
} }
quote! { quote! {
#[derive(::bok::Repository)] #[derive(::bok::Repository, Debug)]
#ast #ast
} }
.into() .into()

View File

@ -21,3 +21,4 @@ proc-macro2 = "1.0"
quote = "1.0" quote = "1.0"
semver = { version = "1.0" } semver = { version = "1.0" }
sha3 = { version = "0.10" } sha3 = { version = "0.10" }
thiserror = { version = "2.0" }

View File

@ -16,29 +16,99 @@
*/ */
use ::std::{ use ::std::{
collections::HashMap, collections::BTreeMap,
sync::{Arc, RwLock}, sync::{Arc, RwLock},
vec::Vec, vec::Vec,
}; };
use crate::{Path, Pkg, PkgName, RepoName, Repository};
#[derive(Debug, ::thiserror::Error)]
pub enum Error {
#[error("package already present")]
AlreadyPresent((Arc<dyn Repository>, ArcLock<dyn Pkg>)),
#[error("not found")]
NotFound,
}
type ArcLock<T> = Arc<RwLock<T>>; type ArcLock<T> = Arc<RwLock<T>>;
type PkgMap = HashMap<crate::PkgName, ArcLock<dyn crate::Pkg>>; type PkgMap = BTreeMap<Path<PkgName>, (Arc<dyn Repository>, ArcLock<dyn Pkg>)>;
/// Collection of packages, subset of what is present on one repository only /// Collection of packages, subset of what is present on one repository only
pub struct Collection { pub struct Collection {
repos: RwLock<Vec<ArcLock<dyn crate::Repository>>>, repos: RwLock<Vec<Arc<dyn Repository>>>,
pkgs: RwLock<PkgMap>, repos_pkgs: RwLock<BTreeMap<Path<RepoName>, PkgMap>>,
repos_pkgs: RwLock<HashMap<crate::RepoName, PkgMap>>,
//repos_pkgs: RwLock<HashMap<crate::Repository, PkgMap>>,
} }
impl Collection { impl Collection {
/// Create a new empty collection of pkgs
pub fn new() -> Collection { pub fn new() -> Collection {
const PKGNUM: usize = 512;
Collection { Collection {
repos: RwLock::new(Vec::with_capacity(8)), repos: RwLock::new(Vec::with_capacity(8)),
pkgs: RwLock::new(HashMap::with_capacity(PKGNUM)), repos_pkgs: RwLock::new(BTreeMap::new()),
repos_pkgs: RwLock::new(HashMap::with_capacity(PKGNUM)), }
}
pub fn add_pkg(
&self,
r: Arc<dyn Repository>,
p: ArcLock<dyn Pkg>,
) -> Result<(), Error> {
let repo_name = r.path();
let mut repos = self.repos.write().unwrap();
let mut repos_pkgs = self.repos_pkgs.write().unwrap();
if repos
.binary_search_by(|x| x.path().cmp(&repo_name))
.is_err()
{
repos.push(r.clone());
repos.sort_by(|a, b| a.path().cmp(&b.path()))
}
let pkg_name = p.read().unwrap().path();
match repos_pkgs.get_mut(&repo_name) {
Some(pkg_map) => match pkg_map.get(&pkg_name) {
Some((r, p)) => {
return Err(Error::AlreadyPresent((r.clone(), p.clone())));
}
None => {
pkg_map.insert(pkg_name, (r, p));
}
},
None => {
let mut pkg_map: PkgMap = BTreeMap::new();
pkg_map.insert(pkg_name, (r, p));
repos_pkgs.insert(repo_name, pkg_map);
}
}
Ok(())
}
pub fn find(
&self,
pkg_path: Path<PkgName>,
) -> Result<(Arc<dyn Repository>, ArcLock<dyn Pkg>), Error> {
let repos_pkgs = self.repos_pkgs.read().unwrap();
for (_, pkg_map) in repos_pkgs.iter() {
match pkg_map.get(&pkg_path) {
Some((r, p)) => {
return Ok((r.clone(), p.clone()));
}
None => {}
}
}
Err(Error::NotFound)
}
pub fn find_in_repo(
&self,
repo_path: Path<RepoName>,
pkg_path: Path<PkgName>,
) -> Result<(Arc<dyn Repository>, ArcLock<dyn Pkg>), Error> {
let repos_pkgs = self.repos_pkgs.read().unwrap();
match repos_pkgs.get(&repo_path) {
None => Err(Error::NotFound),
Some(pkg_map) => match pkg_map.get(&pkg_path) {
Some((r, p)) => Ok((r.clone(), p.clone())),
None => Err(Error::NotFound),
},
} }
} }
} }

View File

@ -86,13 +86,13 @@ macro_rules! packages {
} }
/// Marks your struct as a repository /// Marks your struct as a repository
pub trait Repository { pub trait Repository: ::std::fmt::Debug {
fn name(&self) -> RepoName; fn name(&self) -> RepoName;
fn path(&self) -> Path<RepoName>; fn path(&self) -> Path<RepoName>;
} }
/// This is an empty Package List. /// This is an empty Package List.
#[derive(::std::default::Default)] #[derive(::std::default::Default, Debug)]
pub struct RepositoryEmpty {} pub struct RepositoryEmpty {}
impl Repository for RepositoryEmpty { impl Repository for RepositoryEmpty {
fn name(&self) -> RepoName { fn name(&self) -> RepoName {

View File

@ -82,24 +82,6 @@ where
} }
} }
/// Marks your struct as a repository
pub trait Repository {
fn name(&self) -> RepoName;
fn path(&self) -> Path<RepoName>;
}
/// This is an empty Package List.
#[derive(::std::default::Default)]
pub struct RepositoryEmpty {}
impl Repository for RepositoryEmpty {
fn name(&self) -> RepoName {
"RepositoryEmpty".into()
}
fn path(&self) -> Path<RepoName> {
Path::new("::bok::RepositoryEmpty")
}
}
/// Strong typedef for a package name /// Strong typedef for a package name
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone)] #[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone)]
pub struct PkgName(pub String); pub struct PkgName(pub String);