summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNeal H. Walfield <neal@pep.foundation>2021-04-02 12:09:40 +0200
committerNeal H. Walfield <neal@pep.foundation>2021-04-02 12:09:40 +0200
commit2522962e2aa6fb30546ccf2fcd9aa14115962d1b (patch)
tree1964cb72d4b3889e1eb3d23568d31507084780ea
parente990add46c9acd1616ab3f03c6bd90f2dc5b541d (diff)
WIP: Add a smarter implementation of PartialEq for Cert.neal/cert-eq
- Don't derive PartialEq for Cert. Instead, use lightweight tests to detect differences faster. If the lightweight tests pass, then fallback to a byte comparison. - See https://gitlab.com/sequoia-pgp/sequoia-octopus-librnp/-/issues/25
-rw-r--r--openpgp/src/cert.rs77
1 files changed, 76 insertions, 1 deletions
diff --git a/openpgp/src/cert.rs b/openpgp/src/cert.rs
index ebdf06c2..46d3972d 100644
--- a/openpgp/src/cert.rs
+++ b/openpgp/src/cert.rs
@@ -701,7 +701,7 @@ pub trait Preferences<'a>: seal::Sealed {
/// # Ok(())
/// # }
/// ```
-#[derive(Debug, Clone, PartialEq)]
+#[derive(Debug, Clone)]
pub struct Cert {
primary: PrimaryKeyBundle<key::PublicParts>,
@@ -717,6 +717,81 @@ pub struct Cert {
}
assert_send_and_sync!(Cert);
+impl PartialEq for Cert {
+ fn eq(&self, other: &Self) -> bool {
+ // Quick compare.
+ if self.fingerprint() != other.fingerprint() {
+ return false;
+ }
+
+ // Quickly compare components.
+ let mut a_keys = self.keys().map(|k| {
+ (k.fingerprint(),
+ k.self_signatures.len(),
+ k.certifications.len(),
+ k.self_revocations.len(),
+ k.other_revocations.len())
+ });
+ let mut b_keys = other.keys().map(|k| {
+ (k.fingerprint(),
+ k.self_signatures.len(),
+ k.certifications.len(),
+ k.self_revocations.len(),
+ k.other_revocations.len())
+ });
+
+ loop {
+ let a = a_keys.next();
+ let b = b_keys.next();
+
+ if a != b {
+ return false;
+ }
+ if a.is_none() && b.is_none() {
+ break;
+ }
+ }
+
+ let mut a_uids = self.userids().map(|u| {
+ (u.userid(),
+ u.self_signatures.len(),
+ u.certifications.len(),
+ u.self_revocations.len(),
+ u.other_revocations.len())
+ });
+ let mut b_uids = other.userids().map(|u| {
+ (u.userid(),
+ u.self_signatures.len(),
+ u.certifications.len(),
+ u.self_revocations.len(),
+ u.other_revocations.len())
+ });
+
+ loop {
+ let a = a_uids.next();
+ let b = b_uids.next();
+
+ if a != b {
+ return false;
+ }
+ if a.is_none() && b.is_none() {
+ break;
+ }
+ }
+
+ // There's a chance that there equal. Try the expensive way.
+ use crate::serialize::Serialize;
+
+ let mut a = Vec::with_capacity(4096);
+ let mut b = Vec::with_capacity(4096);
+
+ self.serialize(&mut a).expect("test code");
+ other.serialize(&mut b).expect("test code");
+
+ a == b
+ }
+}
+
impl std::str::FromStr for Cert {
type Err = anyhow::Error;