essential-memory-storage 0.3.0

In memory storage for the Essential server
Documentation
use std::{
    collections::{BTreeMap, HashMap},
    ops::Range,
    time::Duration,
};

use essential_types::{
    contract::Contract, predicate::Predicate, solution::Solution, ContentAddress,
};

use crate::ContractWithAddresses;

#[cfg(test)]
mod tests;

pub fn page_contract<'a>(
    contract_hashes: impl Iterator<Item = &'a ContentAddress>,
    contract: &HashMap<ContentAddress, ContractWithAddresses>,
    predicates: &HashMap<ContentAddress, Predicate>,
    page: usize,
    page_size: usize,
) -> Vec<Contract> {
    let start = page * page_size;
    contract_hashes
        .skip(start)
        .filter_map(|v| {
            let contract = contract.get(v)?;
            Some(Contract {
                predicates: contract.predicates_owned(predicates),
                salt: contract.salt,
            })
        })
        .filter(|v| !v.is_empty())
        .take(page_size)
        .collect()
}

pub fn page_contract_by_time(
    contract_times: &BTreeMap<Duration, Vec<ContentAddress>>,
    contract: &HashMap<ContentAddress, ContractWithAddresses>,
    predicates: &HashMap<ContentAddress, Predicate>,
    range: Range<Duration>,
    page: usize,
    page_size: usize,
) -> Vec<Contract> {
    let start = page * page_size;
    contract_times
        .range(range)
        .skip(start)
        .flat_map(|(_, v)| {
            v.iter().filter_map(|v| {
                let contract = contract.get(v)?;
                Some(Contract {
                    predicates: contract.predicates_owned(predicates),
                    salt: contract.salt,
                })
            })
        })
        .filter(|v| !v.is_empty())
        .take(page_size)
        .collect()
}

pub fn page_solutions<F, S, I>(
    solution_hashes: impl Iterator<Item = I>,
    f: F,
    page: usize,
    page_size: usize,
) -> Vec<S>
where
    F: FnMut(I) -> Option<S>,
{
    let start = page * page_size;
    solution_hashes
        .skip(start)
        .filter_map(f)
        .take(page_size)
        .collect()
}

pub fn page_blocks(
    blocks: &BTreeMap<Duration, super::Block>,
    solutions: &HashMap<essential_types::Hash, Solution>,
    block_number_index: &HashMap<u64, Duration>,
    range: Option<Range<Duration>>,
    block_number: Option<u64>,
    page: usize,
    page_size: usize,
) -> anyhow::Result<Vec<essential_types::Block>> {
    let start = page * page_size;
    let block_number = block_number.unwrap_or(0);
    let Some(block_number_time) = block_number_index.get(&block_number).copied() else {
        return Ok(Vec::new());
    };

    match range {
        Some(range) => {
            let range = range.start.max(block_number_time)..range.end;
            if range.is_empty() {
                return Ok(Vec::new());
            }
            blocks
                .range(range)
                .skip(start)
                .take(page_size)
                .map(|(_, v)| v)
                .map(|block| {
                    let super::Block {
                        number,
                        timestamp,
                        hashes,
                    } = block;
                    let solutions = hashes
                        .iter()
                        .map(|h| solutions.get(h).cloned())
                        .collect::<Option<Vec<_>>>()
                        .ok_or_else(|| anyhow::anyhow!("Missing solution"))?;
                    Ok(essential_types::Block {
                        number: *number,
                        timestamp: *timestamp,
                        solutions,
                    })
                })
                .collect()
        }
        None => blocks
            .range(block_number_time..)
            .skip(start)
            .take(page_size)
            .map(|(_, v)| v)
            .map(|block| {
                let super::Block {
                    number,
                    timestamp,
                    hashes,
                } = block;
                let solutions = hashes
                    .iter()
                    .map(|h| solutions.get(h).cloned())
                    .collect::<Option<Vec<_>>>()
                    .ok_or_else(|| anyhow::anyhow!("Missing solution"))?;
                Ok(essential_types::Block {
                    number: *number,
                    timestamp: *timestamp,
                    solutions,
                })
            })
            .collect(),
    }
}