///|
/// Sequential decoder for objects whose frames are fetched stripe by stripe.
/// The caller groups each stripe's available frames and can write each
/// returned payload chunk directly to a destination.
pub struct ObjectDecoder {
codec : Codec
manifest : Manifest
mut next_stripe : Int
mut decoded_bytes : Int
mut repaired_shards : Int
}
///|
pub fn ObjectDecoder::new(
manifest : Manifest,
max_encoded_bytes? : Int = 16_777_216,
) -> ObjectDecoder raise ErasureError {
let codec = Codec::new(
manifest.data_count(),
manifest.parity_count(),
max_encoded_bytes~,
)
if manifest.stripe_payload_limit() >
codec.data_count() * codec.max_shard_bytes() {
raise ResourceLimit("codec budget cannot hold manifest stripe")
}
{ codec, manifest, next_stripe: 0, decoded_bytes: 0, repaired_shards: 0, }
}
///|
pub fn ObjectDecoder::next_stripe(self : ObjectDecoder) -> Int {
self.next_stripe
}
///|
pub fn ObjectDecoder::decoded_bytes(self : ObjectDecoder) -> Int {
self.decoded_bytes
}
///|
pub fn ObjectDecoder::repaired_shards(self : ObjectDecoder) -> Int {
self.repaired_shards
}
///|
/// Decode exactly the next manifest stripe. On failure, the cursor remains
/// unchanged so callers may fetch an alternative frame and retry.
pub fn ObjectDecoder::push_stripe(
self : ObjectDecoder,
frames : Array[ShardEnvelope],
) -> Bytes raise ErasureError {
if self.next_stripe >= self.manifest.stripe_count() {
raise InvalidManifest("decoder received extra stripe")
}
let recovery = recover_stripe(
self.codec,
frames,
self.manifest.set_id(),
self.next_stripe,
)
let payload = recovery.payload()
if payload.length() != self.manifest.stripe_length(self.next_stripe) {
raise InvalidManifest("decoded stripe length differs from manifest")
}
self.decoded_bytes = self.decoded_bytes + payload.length()
self.repaired_shards = self.repaired_shards +
recovery.missing_indices().length()
self.next_stripe = self.next_stripe + 1
payload
}
///|
/// Confirm that every stripe was consumed and the advertised byte count
/// matches. There is no hidden payload buffer in this decoder.
pub fn ObjectDecoder::finish(self : ObjectDecoder) -> Int raise ErasureError {
if self.next_stripe != self.manifest.stripe_count() ||
self.decoded_bytes != self.manifest.total_length() {
raise InvalidManifest("decoder ended before final stripe")
}
self.repaired_shards
}