@@ -155,6 +155,8 @@ pub enum Cache {
155
155
idx : usize ,
156
156
/// The store of blocks.
157
157
blocks : Vec < Block > ,
158
+ /// The amount of data stored in one cycle, or all blocks
159
+ total_cycle_size : u64 ,
158
160
} ,
159
161
}
160
162
@@ -323,7 +325,17 @@ impl Cache {
323
325
construct_block_cache_inner ( rng, & pyld, maximum_block_bytes, total_bytes. get ( ) ) ?
324
326
}
325
327
} ;
326
- Ok ( Self :: Fixed { idx : 0 , blocks } )
328
+
329
+ let total_cycle_size = blocks
330
+ . iter ( )
331
+ . map ( |block| u64:: from ( block. total_bytes . get ( ) ) )
332
+ . sum ( ) ;
333
+
334
+ Ok ( Self :: Fixed {
335
+ idx : 0 ,
336
+ blocks,
337
+ total_cycle_size,
338
+ } )
327
339
}
328
340
329
341
/// Run `Cache` forward on the user-provided mpsc sender.
@@ -339,7 +351,9 @@ impl Cache {
339
351
#[ allow( clippy:: needless_pass_by_value) ]
340
352
pub fn spin ( self , snd : Sender < Block > ) -> Result < ( ) , SpinError > {
341
353
match self {
342
- Self :: Fixed { mut idx, blocks } => loop {
354
+ Self :: Fixed {
355
+ mut idx, blocks, ..
356
+ } => loop {
343
357
snd. blocking_send ( blocks[ idx] . clone ( ) ) ?;
344
358
idx = ( idx + 1 ) % blocks. len ( ) ;
345
359
} ,
@@ -354,7 +368,7 @@ impl Cache {
354
368
#[ must_use]
355
369
pub fn peek_next ( & self ) -> & Block {
356
370
match self {
357
- Self :: Fixed { idx, blocks } => & blocks[ * idx] ,
371
+ Self :: Fixed { idx, blocks, .. } => & blocks[ * idx] ,
358
372
}
359
373
}
360
374
@@ -367,13 +381,73 @@ impl Cache {
367
381
Self :: Fixed {
368
382
ref mut idx,
369
383
blocks,
384
+ ..
370
385
} => {
371
386
let block = & blocks[ * idx] ;
372
387
* idx = ( * idx + 1 ) % blocks. len ( ) ;
373
388
block
374
389
}
375
390
}
376
391
}
392
+
393
+ /// Read data starting from a given offset and up to the specified size.
394
+ ///
395
+ /// # Panics
396
+ ///
397
+ /// Function will panic if reads are larger than machine word bytes wide.
398
+ pub fn read_at ( & self , offset : u64 , size : usize ) -> Bytes {
399
+ let mut data = BytesMut :: with_capacity ( size) ;
400
+
401
+ let ( blocks, total_cycle_size) = match self {
402
+ Cache :: Fixed {
403
+ blocks,
404
+ total_cycle_size,
405
+ ..
406
+ } => (
407
+ blocks,
408
+ usize:: try_from ( * total_cycle_size)
409
+ . expect ( "cycle size larger than machine word bytes" ) ,
410
+ ) ,
411
+ } ;
412
+
413
+ let mut remaining = size;
414
+ let mut current_offset =
415
+ usize:: try_from ( offset) . expect ( "offset larger than machine word bytes" ) ;
416
+
417
+ while remaining > 0 {
418
+ // Compute offset within the cycle
419
+ let offset_within_cycle = current_offset % total_cycle_size;
420
+
421
+ // Find which block this offset falls into
422
+ let mut block_start = 0 ;
423
+ for block in blocks {
424
+ let block_size = block. total_bytes . get ( ) as usize ;
425
+ if offset_within_cycle < block_start + block_size {
426
+ // Offset is within this block
427
+ let block_offset = offset_within_cycle - block_start;
428
+ let bytes_in_block = ( block_size - block_offset) . min ( remaining) ;
429
+
430
+ data. extend_from_slice (
431
+ & block. bytes [ block_offset..block_offset + bytes_in_block] ,
432
+ ) ;
433
+
434
+ remaining -= bytes_in_block;
435
+ current_offset += bytes_in_block;
436
+ break ;
437
+ }
438
+ block_start += block_size;
439
+ }
440
+
441
+ // If we couldn't find a block this suggests something seriously
442
+ // wacky has happened.
443
+ if remaining > 0 && block_start >= total_cycle_size {
444
+ error ! ( "Offset exceeds total cycle size" ) ;
445
+ break ;
446
+ }
447
+ }
448
+
449
+ data. freeze ( )
450
+ }
377
451
}
378
452
379
453
/// Construct a new block cache of form defined by `serializer`.
0 commit comments