mirror of
https://seed.radicle.dev/rad:z6cFWeWpnZNHh9rUW8phgA3b5yGt.git
synced 2026-11-12 06:30:37 +08:00
247 lines
7.1 KiB
Rust
247 lines
7.1 KiB
Rust
// I think the following `Tags` and `Branches` would be merged
|
|
// using Generic associated types supported in Rust 1.65.0.
|
|
|
|
use std::{
|
|
collections::{btree_set, BTreeSet},
|
|
convert::TryFrom as _,
|
|
};
|
|
|
|
use git_ref_format::{lit, name::Components, Component, Qualified, RefString};
|
|
|
|
use crate::{tag, Branch, Namespace, Tag};
|
|
|
|
/// Iterator over [`Tag`]s.
|
|
#[derive(Default)]
|
|
pub struct Tags<'a> {
|
|
references: Vec<git2::References<'a>>,
|
|
current: usize,
|
|
}
|
|
|
|
/// Iterator over the [`Qualified`] names of [`Tag`]s.
|
|
pub struct TagNames<'a> {
|
|
inner: Tags<'a>,
|
|
}
|
|
|
|
impl<'a> Tags<'a> {
|
|
pub(super) fn push(&mut self, references: git2::References<'a>) {
|
|
self.references.push(references)
|
|
}
|
|
|
|
pub fn names(self) -> TagNames<'a> {
|
|
TagNames { inner: self }
|
|
}
|
|
}
|
|
|
|
impl<'a> Iterator for Tags<'a> {
|
|
type Item = Result<Tag, error::Tag>;
|
|
|
|
fn next(&mut self) -> Option<Self::Item> {
|
|
while self.current < self.references.len() {
|
|
match self.references.get_mut(self.current) {
|
|
Some(refs) => match refs.next() {
|
|
Some(res) => {
|
|
return Some(
|
|
res.map_err(error::Tag::from)
|
|
.and_then(|r| Tag::try_from(&r).map_err(error::Tag::from)),
|
|
);
|
|
},
|
|
None => self.current += 1,
|
|
},
|
|
None => break,
|
|
}
|
|
}
|
|
None
|
|
}
|
|
}
|
|
|
|
impl<'a> Iterator for TagNames<'a> {
|
|
type Item = Result<Qualified<'static>, error::Tag>;
|
|
|
|
fn next(&mut self) -> Option<Self::Item> {
|
|
while self.inner.current < self.inner.references.len() {
|
|
match self.inner.references.get_mut(self.inner.current) {
|
|
Some(refs) => match refs.next() {
|
|
Some(res) => {
|
|
return Some(res.map_err(error::Tag::from).and_then(|r| {
|
|
tag::reference_name(&r)
|
|
.map(|name| lit::refs_tags(name).into())
|
|
.map_err(error::Tag::from)
|
|
}))
|
|
},
|
|
None => self.inner.current += 1,
|
|
},
|
|
None => break,
|
|
}
|
|
}
|
|
None
|
|
}
|
|
}
|
|
|
|
/// Iterator over [`Branch`]es.
|
|
#[derive(Default)]
|
|
pub struct Branches<'a> {
|
|
references: Vec<git2::References<'a>>,
|
|
current: usize,
|
|
}
|
|
|
|
/// Iterator over the [`Qualified`] names of [`Branch`]es.
|
|
pub struct BranchNames<'a> {
|
|
inner: Branches<'a>,
|
|
}
|
|
|
|
impl<'a> Branches<'a> {
|
|
pub(super) fn push(&mut self, references: git2::References<'a>) {
|
|
self.references.push(references)
|
|
}
|
|
|
|
pub fn names(self) -> BranchNames<'a> {
|
|
BranchNames { inner: self }
|
|
}
|
|
}
|
|
|
|
impl<'a> Iterator for Branches<'a> {
|
|
type Item = Result<Branch, error::Branch>;
|
|
|
|
fn next(&mut self) -> Option<Self::Item> {
|
|
while self.current < self.references.len() {
|
|
match self.references.get_mut(self.current) {
|
|
Some(refs) => match refs.next() {
|
|
Some(res) => {
|
|
return Some(
|
|
res.map_err(error::Branch::from)
|
|
.and_then(|r| Branch::try_from(&r).map_err(error::Branch::from)),
|
|
)
|
|
},
|
|
None => self.current += 1,
|
|
},
|
|
None => break,
|
|
}
|
|
}
|
|
None
|
|
}
|
|
}
|
|
|
|
impl<'a> Iterator for BranchNames<'a> {
|
|
type Item = Result<Qualified<'static>, error::Branch>;
|
|
|
|
fn next(&mut self) -> Option<Self::Item> {
|
|
while self.inner.current < self.inner.references.len() {
|
|
match self.inner.references.get_mut(self.inner.current) {
|
|
Some(refs) => match refs.next() {
|
|
Some(res) => {
|
|
return Some(res.map_err(error::Branch::from).and_then(|r| {
|
|
Branch::try_from(&r)
|
|
.map(|branch| branch.refname().into_owned())
|
|
.map_err(error::Branch::from)
|
|
}))
|
|
},
|
|
None => self.inner.current += 1,
|
|
},
|
|
None => break,
|
|
}
|
|
}
|
|
None
|
|
}
|
|
}
|
|
|
|
// TODO: not sure this buys us much
|
|
/// An iterator for namespaces.
|
|
pub struct Namespaces {
|
|
namespaces: btree_set::IntoIter<Namespace>,
|
|
}
|
|
|
|
impl Namespaces {
|
|
pub(super) fn new(namespaces: BTreeSet<Namespace>) -> Self {
|
|
Self {
|
|
namespaces: namespaces.into_iter(),
|
|
}
|
|
}
|
|
}
|
|
|
|
impl Iterator for Namespaces {
|
|
type Item = Namespace;
|
|
fn next(&mut self) -> Option<Self::Item> {
|
|
self.namespaces.next()
|
|
}
|
|
}
|
|
|
|
#[derive(Default)]
|
|
pub struct Categories<'a> {
|
|
references: Vec<git2::References<'a>>,
|
|
current: usize,
|
|
}
|
|
|
|
impl<'a> Categories<'a> {
|
|
pub(super) fn push(&mut self, references: git2::References<'a>) {
|
|
self.references.push(references)
|
|
}
|
|
}
|
|
|
|
impl<'a> Iterator for Categories<'a> {
|
|
type Item = Result<(RefString, RefString), error::Category>;
|
|
|
|
fn next(&mut self) -> Option<Self::Item> {
|
|
while self.current < self.references.len() {
|
|
match self.references.get_mut(self.current) {
|
|
Some(refs) => match refs.next() {
|
|
Some(res) => {
|
|
return Some(res.map_err(error::Category::from).and_then(|r| {
|
|
let name = std::str::from_utf8(r.name_bytes())?;
|
|
let name = git_ref_format::RefStr::try_from_str(name)?;
|
|
let name = name.qualified().ok_or_else(|| {
|
|
error::Category::NotQualified(name.to_ref_string())
|
|
})?;
|
|
let (_refs, category, c, cs) = name.non_empty_components();
|
|
Ok((category.to_ref_string(), refstr_join(c, cs)))
|
|
}));
|
|
},
|
|
None => self.current += 1,
|
|
},
|
|
None => break,
|
|
}
|
|
}
|
|
None
|
|
}
|
|
}
|
|
|
|
pub mod error {
|
|
use std::str;
|
|
|
|
use git_ref_format::RefString;
|
|
use thiserror::Error;
|
|
|
|
use crate::{branch, tag};
|
|
|
|
#[derive(Debug, Error)]
|
|
pub enum Branch {
|
|
#[error(transparent)]
|
|
Git(#[from] git2::Error),
|
|
#[error(transparent)]
|
|
Branch(#[from] branch::error::Branch),
|
|
}
|
|
|
|
#[derive(Debug, Error)]
|
|
pub enum Category {
|
|
#[error(transparent)]
|
|
Git(#[from] git2::Error),
|
|
#[error("the reference '{0}' was expected to be qualified, i.e. 'refs/<category>/<path>'")]
|
|
NotQualified(RefString),
|
|
#[error(transparent)]
|
|
RefFormat(#[from] git_ref_format::Error),
|
|
#[error(transparent)]
|
|
Utf8(#[from] str::Utf8Error),
|
|
}
|
|
|
|
#[derive(Debug, Error)]
|
|
pub enum Tag {
|
|
#[error(transparent)]
|
|
Git(#[from] git2::Error),
|
|
#[error(transparent)]
|
|
Tag(#[from] tag::error::FromReference),
|
|
}
|
|
}
|
|
|
|
pub(crate) fn refstr_join<'a>(c: Component<'a>, cs: Components<'a>) -> RefString {
|
|
std::iter::once(c).chain(cs).collect::<RefString>()
|
|
}
|