use std::collections::BTreeMap;
use std::collections::btree_map::Entry;
use std::sync::Arc;
use std::time::SystemTime;
use sequoia_openpgp as openpgp;
use openpgp::Fingerprint;
use openpgp::KeyID;
use openpgp::KeyHandle;
use openpgp::Result;
use sequoia_cert_store as cert_store;
use cert_store::store::StoreError;
use crate::CertificationSet;
use crate::Certification;
use crate::CertSynopsis;
use crate::Depth;
use crate::store::Store;
use crate::TRACE;
pub struct SynopsisSlice<'a> {
certs: BTreeMap<KeyID, Vec<&'a CertSynopsis>>,
redges: BTreeMap<Fingerprint, Arc<Vec<CertificationSet>>>,
reference_time: SystemTime,
}
impl<'a> SynopsisSlice<'a> {
pub fn new(cert_synopses: &'a [CertSynopsis],
certifications: &'a [Certification],
reference_time: SystemTime)
-> Result<Self>
{
tracer!(TRACE, "SynopsisSlice::new");
let mut certs: BTreeMap<KeyID, Vec<&'a CertSynopsis>>
= BTreeMap::new();
let mut redges: BTreeMap<Fingerprint, Vec<CertificationSet>>
= BTreeMap::new();
let mut insert_cert = |cert: &'a CertSynopsis| {
let keyid = KeyID::from(&cert.fingerprint());
match certs.entry(keyid) {
Entry::Occupied(mut oe) => {
if oe.get().iter()
.find(|c| {
c.fingerprint() == cert.fingerprint()
})
.is_some()
{
} else {
oe.get_mut().push(cert);
}
}
e @ Entry::Vacant(_) => {
e.or_insert(vec![ cert ]);
}
}
};
for cert in cert_synopses.into_iter() {
insert_cert(cert);
}
for c in certifications.into_iter() {
let c: &Certification = c.into();
let issuer = c.issuer();
let target = c.target();
insert_cert(issuer);
insert_cert(target);
match redges.entry(target.fingerprint()) {
e @ Entry::Occupied(_) => {
e.and_modify(|e| {
e.push(CertificationSet::from_certification(
c.clone(), reference_time))
});
}
e @ Entry::Vacant(_) => {
e.or_insert(
vec![
CertificationSet::from_certification(
c.clone(), reference_time)
]);
}
}
}
t!("Merging certifications.");
for (_, cs) in redges.iter_mut() {
cs.sort_by(|a, b| {
a.issuer().fingerprint().cmp(&b.issuer().fingerprint())
});
*cs = cs.drain(..).fold(
Vec::new(),
|mut v: Vec<CertificationSet>, cs: CertificationSet|
-> Vec<CertificationSet>
{
let len = v.len();
if len > 0 {
let l = &mut v[len-1];
if l.issuer().fingerprint()
== cs.issuer().fingerprint()
{
l.merge(cs);
} else {
v.push(cs);
}
} else {
v.push(cs);
}
v
});
}
t!("Done.");
let n = SynopsisSlice {
certs,
redges: BTreeMap::from_iter(redges.into_iter().map(|(k, v)| {
(k, Arc::new(v))
})),
reference_time,
};
Ok(n)
}
}
impl<'a> Store for SynopsisSlice<'a> {
fn reference_time(&self) -> SystemTime {
self.reference_time
}
fn iter_fingerprints<'b>(&'b self) -> Box<dyn Iterator<Item=Fingerprint> + 'b> {
Box::new(
self.certs
.values()
.flat_map(|v| {
v.iter().map(|c| c.fingerprint())
}))
}
fn lookup_synopses(&self, kh: &KeyHandle) -> Result<Vec<CertSynopsis>>
{
let certs = self.certs.get(&KeyID::from(kh))
.ok_or(StoreError::NotFound(kh.clone()))?;
let certs = if let KeyHandle::Fingerprint(fpr) = kh {
certs
.into_iter()
.filter_map(|&c| {
if &c.fingerprint() == fpr {
Some(c.clone())
} else {
None
}
})
.collect()
} else {
certs
.into_iter()
.map(|&c| c.clone())
.collect()
};
Ok(certs)
}
fn certifications_of(&self, target: &Fingerprint, _min_depth: Depth)
-> Result<Arc<Vec<CertificationSet>>>
{
Ok(self.redges.get(target)
.map(|cs| Arc::clone(cs))
.ok_or(StoreError::NotFound(KeyHandle::from(target.clone())))?)
}
}