substrate_parser 0.7.1

parser for Substrate chain data
Documentation
//! [`Compact`] search and processing.
use external_memory_tools::{AddressableBuffer, BufferError, ExternalMemory};
use parity_scale_codec::{Compact, Decode, HasCompact};

use crate::error::ParserError;

/// Compact found in data.
#[derive(Debug)]
pub struct FoundCompact<T: HasCompact> {
    /// Compact found and decoded.
    pub compact: T,

    /// Position of first data element after the compact part.
    pub start_next_unit: usize,
}

/// Maximum possible encoded compact length, `Compact::compact_len(&u128::MAX)`.
///
/// Would not make sense to check slices of higher length for a compact.
pub const MAX_COMPACT_LEN: usize = 17;

/// Search bytes slice for compact at given position by brute force.
///
/// Tries to find shortest slice that could be decoded as a compact.
/// Does not shift current parser position.
pub fn find_compact<T, B, E>(
    data: &B,
    ext_memory: &mut E,
    position: usize,
) -> Result<FoundCompact<T>, ParserError<E>>
where
    B: AddressableBuffer<E>,
    E: ExternalMemory,
    T: HasCompact,
    Compact<T>: Decode,
{
    if data.total_len() < position {
        return Err(ParserError::Buffer(BufferError::OutOfRange {
            position,
            total_length: data.total_len(),
        }));
    }
    let mut out = None;
    for i in 0..(data.total_len() - position) {
        // checking if length exceeds maximum possible length for a compact
        if i > MAX_COMPACT_LEN {
            break;
        }

        let hippo = data.read_slice(ext_memory, position, i + 1)?;
        let unhippo = <Compact<T>>::decode(&mut hippo.as_ref());
        if let Ok(hurray) = unhippo {
            let start_next_unit = {
                if data.total_len() - position == i {
                    data.total_len()
                } else {
                    position + i + 1
                }
            };
            out = Some(FoundCompact {
                compact: hurray.0,
                start_next_unit,
            });
            break;
        }
    }
    match out {
        Some(c) => Ok(c),
        None => Err(ParserError::NoCompact { position }),
    }
}

/// Find compact and move current parser position accordingly.
pub fn get_compact<T, B, E>(
    data: &B,
    ext_memory: &mut E,
    position: &mut usize,
) -> Result<T, ParserError<E>>
where
    B: AddressableBuffer<E>,
    E: ExternalMemory,
    T: HasCompact,
    Compact<T>: Decode,
{
    let found_compact = find_compact::<T, B, E>(data, ext_memory, *position)?;
    *position = found_compact.start_next_unit;
    Ok(found_compact.compact)
}