Skip to content

Commit deba3f7

Browse files
authored
Merge pull request #6 from alamgu/block-helpers
Add a bunch of helper functions for working with blocks
2 parents 0c0595b + 411ae27 commit deba3f7

File tree

1 file changed

+72
-14
lines changed

1 file changed

+72
-14
lines changed

src/lib.rs

Lines changed: 72 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@
6767
//!
6868
#![no_std]
6969
#![feature(type_alias_impl_trait)]
70+
#![feature(cell_filter_map)]
7071
#![feature(cfg_version)]
7172
#![cfg_attr(
7273
all(target_family = "bolos", not(version("1.64"))),
@@ -339,6 +340,35 @@ impl HostIO {
339340
}
340341
}
341342

343+
/// A block must be at least [HASH_LEN] bytes long.
344+
pub struct Block([u8]);
345+
346+
impl Block {
347+
pub fn as_raw_slice(&self) -> &[u8] {
348+
let block = self as *const Block as *const [u8];
349+
unsafe { &*block }
350+
}
351+
352+
pub fn from_raw_slice_opt(block: &[u8]) -> Option<&Self> {
353+
if block.len() >= HASH_LEN {
354+
let block2 = block as *const [u8] as *const Block;
355+
Some(unsafe { &*block2 })
356+
} else {
357+
None
358+
}
359+
}
360+
361+
/// Panics if block is illegally short
362+
pub fn next_block(&self) -> SHA256Sum {
363+
self.as_raw_slice()[..HASH_LEN].try_into().unwrap()
364+
}
365+
366+
/// Panics if block is illegally short
367+
pub fn data(&self) -> &[u8] {
368+
&self.as_raw_slice()[HASH_LEN..]
369+
}
370+
}
371+
342372
/// Concrete implementation of the interface defined by
343373
/// [ledger_parser_combinators::async_parser::Readable] for the block protocol.
344374
#[derive(Clone)]
@@ -348,28 +378,56 @@ pub struct ByteStream {
348378
current_offset: usize,
349379
}
350380

381+
impl ByteStream {
382+
/// Get the current block.
383+
fn get_current_block<'a>(&'a mut self) -> impl 'a + Future<Output = Ref<'static, Block>> {
384+
async move {
385+
if self.current_chunk == [0; 32] {
386+
let _: () = reject().await;
387+
}
388+
let chunk_res = self.host_io.get_chunk(self.current_chunk).await;
389+
match chunk_res {
390+
Ok(a) => match Ref::filter_map(a, Block::from_raw_slice_opt) {
391+
Ok(r) => r,
392+
Err(_) => reject().await,
393+
}
394+
Err(_) => reject().await,
395+
}
396+
}
397+
}
398+
399+
/// Get the rest of the current block that we have not already processed.
400+
///
401+
/// [block] must be the current block.
402+
fn slice_from_block<'a, 'b>(&'a mut self, block: &'b Block) -> &'b [u8] {
403+
&block.data()[self.current_offset..]
404+
}
405+
406+
/// Consume [consume] bytes from the current block.
407+
///
408+
/// [block] must be the current block. [consume] must be less than or equal
409+
/// to `self.slice_from_block(block).len()`.
410+
fn consume(&mut self, block: &Block, consume: usize) {
411+
self.current_offset += consume;
412+
debug_assert!(self.current_offset <= block.data().len());
413+
if self.current_offset == block.data().len() {
414+
self.current_chunk = block.next_block();
415+
self.current_offset = 0;
416+
}
417+
}
418+
}
419+
351420
impl Readable for ByteStream {
352421
type OutFut<'a, const N: usize> = impl 'a + core::future::Future<Output = [u8; N]>;
353422
fn read<'a: 'b, 'b, const N: usize>(&'a mut self) -> Self::OutFut<'b, N> {
354423
async move {
355424
let mut buffer = ArrayVec::<u8, N>::new();
356425
while !buffer.is_full() {
357-
if self.current_chunk == [0; 32] {
358-
let _: () = reject().await;
359-
}
360-
let chunk_res = self.host_io.get_chunk(self.current_chunk).await;
361-
let chunk = match chunk_res {
362-
Ok(a) => a,
363-
Err(_) => reject().await,
364-
};
365-
let avail = &chunk[self.current_offset + HASH_LEN..];
426+
let block = self.get_current_block().await;
427+
let avail = self.slice_from_block(&block);
366428
let consuming = core::cmp::min(avail.len(), buffer.remaining_capacity());
367429
buffer.try_extend_from_slice(&avail[0..consuming]).ok();
368-
self.current_offset += consuming;
369-
if self.current_offset + HASH_LEN == chunk.len() {
370-
self.current_chunk = chunk[0..HASH_LEN].try_into().unwrap();
371-
self.current_offset = 0;
372-
}
430+
self.consume(&*block, consuming);
373431
}
374432
buffer.into_inner().unwrap()
375433
}

0 commit comments

Comments
 (0)