pub struct RecordSet<T> { /* private fields */ }Expand description
A container that lets callers organize records by identifier.
§Deduplication by identifier
The same EntryId appearing twice in one payload is legal: it can carry one version
of the entry per device. A merge can only apply one result, so which one is used has to
be fixed first: first-inserted wins, and whoever builds the payload is responsible for
putting the version it wants adopted first.
Last-inserted-wins is not used: that would make the order inside a payload a security-relevant property (the last record decides), while the peer controls that order.
§Genericity
Two places need a “record set deduplicated by identifier”, with different element types:
MergedRecord: the semantic record after decryption, used by the merge layer.crate::sync::Record: the wire-format record that is still encrypted, used by payload packing and parsing.
One generic container instead of two implementations is not just less code: the two deduplication rules must be identical (both are first-inserted wins), and two implementations would silently drift apart, showing up as a payload deduplicated on the sending side and not on the receiving side — a failure that reproduces only on the peer.
Implementations§
Source§impl<T: HasEntryId> RecordSet<T>
impl<T: HasEntryId> RecordSet<T>
Sourcepub fn insert(&mut self, record: T) -> bool
pub fn insert(&mut self, record: T) -> bool
Inserts a record; does not overwrite when the same ID already exists.
Returns whether the record was actually inserted (false means this ID is already
present).
Sourcepub fn iter(&self) -> impl Iterator<Item = (&EntryId, &T)>
pub fn iter(&self) -> impl Iterator<Item = (&EntryId, &T)>
Iterates in ID order.
A BTreeMap rather than a HashMap: the iteration order has to be deterministic,
otherwise the same payload would produce a different merge order on different
devices and the order of the conflict list would follow; for the wire format it
would also make two payloads with identical content produce different plaintext.
Trait Implementations§
Source§impl<'a, T> IntoIterator for &'a RecordSet<T>
impl<'a, T> IntoIterator for &'a RecordSet<T>
Source§fn into_iter(self) -> Self::IntoIter
fn into_iter(self) -> Self::IntoIter
Borrows every record in ID order.
Borrowing rather than a records() -> Vec<T>: the latter requires every record to
be copyable, and both element types deliberately have no Clone (they hold key
material). Borrowing lets merge_into take a &RecordSet directly, without
copying the key material of a whole payload just to pass it around — one sync would
copy hundreds of seeds for no reason at all.