use std::borrow::Borrow;
use sequoia_openpgp as openpgp;
use openpgp::Fingerprint;
use crate::Root;
#[derive(Debug, Clone)]
pub struct Roots {
roots: Vec<Root>,
}
impl Roots {
pub fn new<I>(roots: I) -> Self
where I: IntoIterator,
I::Item: Into<Root>,
{
let mut roots: Vec<Root>
= roots.into_iter().map(Into::into).collect();
if roots.len() > 1 {
roots.sort_by_key(|r| r.fingerprint().clone());
roots.dedup_by(|other, keep| {
if other.fingerprint() == keep.fingerprint() {
keep.set_amount(std::cmp::max(other.amount(), keep.amount()));
true
} else {
false
}
});
}
Self {
roots,
}
}
pub fn empty() -> Self {
Roots {
roots: Vec::new(),
}
}
pub fn is_empty(&self) -> bool {
self.roots.is_empty()
}
pub fn iter(&self) -> impl Iterator<Item=&Root> {
self.roots.iter()
}
pub fn is_root<F>(&self, fpr: F) -> bool
where F: Borrow<Fingerprint>
{
let fpr = fpr.borrow();
self.roots.binary_search_by_key(&fpr, |r| &r.fingerprint()).is_ok()
}
pub fn get<F>(&self, fpr: F) -> Option<&Root>
where F: Borrow<Fingerprint>
{
let fpr = fpr.borrow();
self.roots.binary_search_by_key(&fpr, |r| r.fingerprint())
.ok()
.map(|i| &self.roots[i])
}
pub fn retain<F>(&mut self, f: F)
where
F: FnMut(&Root) -> bool
{
self.roots.retain(f);
}
}
macro_rules! gen_from {
($t:ty) => {
impl From<$t> for Roots {
fn from(roots: $t) -> Self {
Roots::new(roots.iter().map(Root::from))
}
}
};
}
gen_from!(&[Fingerprint]);
gen_from!(&[Fingerprint; 0]);
gen_from!(&[Fingerprint; 1]);
gen_from!(&[Fingerprint; 2]);
gen_from!(&[Fingerprint; 3]);
gen_from!(&[Fingerprint; 4]);
gen_from!(&[Fingerprint; 5]);
gen_from!(&[Fingerprint; 6]);
gen_from!(&[Fingerprint; 7]);
gen_from!(&[Fingerprint; 8]);
gen_from!(&[Fingerprint; 9]);
gen_from!(&[Fingerprint; 10]);
gen_from!(&[Fingerprint; 11]);
gen_from!(&[Fingerprint; 12]);
gen_from!(&[Fingerprint; 13]);
gen_from!(&[Fingerprint; 14]);
gen_from!(&[Fingerprint; 15]);
gen_from!(&[Fingerprint; 16]);
gen_from!(&[(Fingerprint, usize)]);
gen_from!(&[(Fingerprint, usize); 0]);
gen_from!(&[(Fingerprint, usize); 1]);
gen_from!(&[(Fingerprint, usize); 2]);
gen_from!(&[(Fingerprint, usize); 3]);
gen_from!(&[(Fingerprint, usize); 4]);
gen_from!(&[(Fingerprint, usize); 5]);
gen_from!(&[(Fingerprint, usize); 6]);
gen_from!(&[(Fingerprint, usize); 7]);
gen_from!(&[(Fingerprint, usize); 8]);
gen_from!(&[(Fingerprint, usize); 9]);
gen_from!(&[(Fingerprint, usize); 10]);
gen_from!(&[(Fingerprint, usize); 11]);
gen_from!(&[(Fingerprint, usize); 12]);
gen_from!(&[(Fingerprint, usize); 13]);
gen_from!(&[(Fingerprint, usize); 14]);
gen_from!(&[(Fingerprint, usize); 15]);
gen_from!(&[(Fingerprint, usize); 16]);
#[cfg(test)]
mod tests {
use super::*;
use crate::FULLY_TRUSTED;
use crate::PARTIALLY_TRUSTED;
#[test]
fn roots() {
let fpr_a: Fingerprint =
"A7319A9B166AB530A5FBAC8AB43CA77F7C176AF4"
.parse().expect("valid fingerprint");
let fpr_b: Fingerprint =
"BFC5CA10FB55A4B790E2A1DBA5CFAB9A9E34E183"
.parse().expect("valid fingerprint");
let input = &[
(fpr_a.clone(), PARTIALLY_TRUSTED),
(fpr_a.clone(), FULLY_TRUSTED),
(fpr_b.clone(), FULLY_TRUSTED),
];
for i in 0..3 {
for j in 0..3 {
for k in 0..3 {
if i == j || i == k || j == k {
continue;
}
let r = Roots::new(&[
input[i].clone(),
input[j].clone(),
input[k].clone(),
]);
assert_eq!(
&[
(fpr_a.clone(), FULLY_TRUSTED),
(fpr_b.clone(), FULLY_TRUSTED),
][..],
&r.iter()
.map(|r| (r.fingerprint().clone(), r.amount()))
.collect::<Vec<_>>());
}
}
}
}
}