///|
/// An immutable bitmap state identified by a monotonically increasing generation.
pub struct RoaringSnapshot {
generation : Int
bitmap : RoaringBitmap
}
///|
/// Errors at snapshot generation and frame boundaries.
pub(all) enum SnapshotError {
InvalidGeneration(Int)
GenerationOverflow(Int)
StaleGeneration(Int, Int)
Frame(FrameError)
}
///|
/// A transportable snapshot envelope with its self-checking bitmap frame.
pub(all) struct SnapshotEnvelope {
generation : Int
frame : BitmapFrame
}
///|
/// A checked patch between two exact snapshot generations.
pub(all) struct SnapshotPatchEnvelope {
base_generation : Int
target_generation : Int
additions : BitmapFrame
removals : BitmapFrame
}
///|
/// Create generation zero from a bitmap.
pub fn RoaringSnapshot::new(bitmap : RoaringBitmap) -> RoaringSnapshot {
{ generation: 0, bitmap }
}
///|
/// Create a snapshot at an explicit non-negative generation.
pub fn RoaringSnapshot::at(
generation : Int,
bitmap : RoaringBitmap,
) -> Result[RoaringSnapshot, SnapshotError] {
if generation < 0 {
Err(InvalidGeneration(generation))
} else {
Ok({ generation, bitmap })
}
}
///|
/// Return the snapshot generation.
pub fn RoaringSnapshot::generation(self : RoaringSnapshot) -> Int {
self.generation
}
///|
/// Return the immutable bitmap held by this snapshot.
pub fn RoaringSnapshot::bitmap(self : RoaringSnapshot) -> RoaringBitmap {
self.bitmap
}
///|
/// Apply a patch and advance exactly one generation.
pub fn RoaringSnapshot::advance(
self : RoaringSnapshot,
patch : RoaringPatch,
) -> Result[RoaringSnapshot, SnapshotError] {
if self.generation == 2_147_483_647 {
return Err(GenerationOverflow(self.generation))
}
Ok({ generation: self.generation + 1, bitmap: patch.apply(self.bitmap) })
}
///|
/// Produce the exact patch needed to reach another snapshot.
pub fn RoaringSnapshot::diff_to(
self : RoaringSnapshot,
target : RoaringSnapshot,
) -> RoaringPatch {
self.bitmap.diff_to(target.bitmap)
}
///|
/// Wrap this snapshot in an integrity-checked frame.
pub fn RoaringSnapshot::envelope(
self : RoaringSnapshot,
format : CodecFormat,
) -> Result[SnapshotEnvelope, CodecError] {
match self.bitmap.frame(format) {
Ok(frame) => Ok({ generation: self.generation, frame })
Err(error) => Err(error)
}
}
///|
/// Recover a snapshot after validating its transport frame.
pub fn SnapshotEnvelope::decode(
self : SnapshotEnvelope,
) -> Result[RoaringSnapshot, SnapshotError] {
if self.generation < 0 {
return Err(InvalidGeneration(self.generation))
}
match self.frame.decode() {
Ok(bitmap) => Ok({ generation: self.generation, bitmap })
Err(error) => Err(Frame(error))
}
}
///|
/// Return envelope generation without decoding its payload.
pub fn SnapshotEnvelope::generation(self : SnapshotEnvelope) -> Int {
self.generation
}
///|
/// Encode the exact delta from this snapshot to `target`.
pub fn RoaringSnapshot::patch_envelope(
self : RoaringSnapshot,
target : RoaringSnapshot,
format : CodecFormat,
) -> Result[SnapshotPatchEnvelope, CodecError] {
let patch = self.diff_to(target)
match patch.additions.frame(format) {
Err(error) => Err(error)
Ok(additions) =>
match patch.removals.frame(format) {
Err(error) => Err(error)
Ok(removals) =>
Ok({
base_generation: self.generation,
target_generation: target.generation,
additions,
removals,
})
}
}
}
///|
/// Apply a checked patch only when its base generation matches this snapshot.
pub fn RoaringSnapshot::apply_patch_envelope(
self : RoaringSnapshot,
envelope : SnapshotPatchEnvelope,
) -> Result[RoaringSnapshot, SnapshotError] {
if envelope.base_generation != self.generation {
return Err(StaleGeneration(self.generation, envelope.base_generation))
}
if envelope.target_generation < 0 {
return Err(InvalidGeneration(envelope.target_generation))
}
let additions = match envelope.additions.decode() {
Ok(bitmap) => bitmap
Err(error) => return Err(Frame(error))
}
let removals = match envelope.removals.decode() {
Ok(bitmap) => bitmap
Err(error) => return Err(Frame(error))
}
Ok({
generation: envelope.target_generation,
bitmap: self.bitmap.difference(removals).union(additions),
})
}
///|
pub fn SnapshotPatchEnvelope::base_generation(
self : SnapshotPatchEnvelope,
) -> Int {
self.base_generation
}
///|
pub fn SnapshotPatchEnvelope::target_generation(
self : SnapshotPatchEnvelope,
) -> Int {
self.target_generation
}