blockfrost 1.3.0

A Rust SDK for Blockfrost.io API
Documentation
use crate::{DEFAULT_ORDER, DEFAULT_PAGINATION_PAGE_COUNT, DEFAULT_PAGINATION_PAGE_ITEMS_COUNT};
use std::fmt;
use std::num::ParseIntError;
use std::str::FromStr;

#[derive(Clone, Copy)]
pub struct Pagination {
    pub fetch_all: bool,
    pub count: usize,
    pub page: usize,
    pub order: Order,
    pub from: Option<BlockCursor>,
    pub to: Option<BlockCursor>,
}

impl Default for Pagination {
    fn default() -> Self {
        Pagination {
            fetch_all: false,
            count: DEFAULT_PAGINATION_PAGE_ITEMS_COUNT,
            page: DEFAULT_PAGINATION_PAGE_COUNT,
            order: DEFAULT_ORDER,
            from: None,
            to: None,
        }
    }
}

impl Pagination {
    pub fn new(order: Order, page: usize, count: usize) -> Self {
        Pagination {
            fetch_all: false,
            order,
            page,
            count,
            from: None,
            to: None,
        }
    }

    pub fn all() -> Self {
        Pagination {
            fetch_all: true,
            ..Default::default()
        }
    }

    pub fn with_from(mut self, from: impl Into<BlockCursor>) -> Self {
        self.from = Some(from.into());
        self
    }

    pub fn with_to(mut self, to: impl Into<BlockCursor>) -> Self {
        self.to = Some(to.into());
        self
    }

    pub fn with_range(self, from: impl Into<BlockCursor>, to: impl Into<BlockCursor>) -> Self {
        self.with_from(from).with_to(to)
    }

    pub fn order_to_string(&self) -> String {
        match self.order {
            Order::Asc => "asc".to_string(),
            Order::Desc => "desc".to_string(),
        }
    }
}

#[derive(Clone, Copy)]
pub enum Order {
    Asc,
    Desc,
}

#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct BlockCursor {
    pub block_height: u64,
    pub tx_index: Option<u32>,
}

impl BlockCursor {
    pub fn block(block_height: u64) -> Self {
        Self {
            block_height,
            tx_index: None,
        }
    }

    pub fn tx(block_height: u64, tx_index: u32) -> Self {
        Self {
            block_height,
            tx_index: Some(tx_index),
        }
    }
}

impl fmt::Display for BlockCursor {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self.tx_index {
            Some(tx_index) => write!(f, "{}:{}", self.block_height, tx_index),
            None => write!(f, "{}", self.block_height),
        }
    }
}

impl From<u64> for BlockCursor {
    fn from(block_height: u64) -> Self {
        Self::block(block_height)
    }
}

impl From<(u64, u32)> for BlockCursor {
    fn from((block_height, tx_index): (u64, u32)) -> Self {
        Self::tx(block_height, tx_index)
    }
}

impl FromStr for BlockCursor {
    type Err = ParseIntError;

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        match s.split_once(':') {
            Some((block_height, tx_index)) => {
                Ok(Self::tx(block_height.parse()?, tx_index.parse()?))
            }
            None => Ok(Self::block(s.parse()?)),
        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn pagination_builds_cursor_range() {
        let pagination = Pagination::default().with_range(8929261, (9999269, 10));

        assert_eq!(pagination.from, Some(BlockCursor::block(8929261)));
        assert_eq!(pagination.to, Some(BlockCursor::tx(9999269, 10)));
        assert_eq!(pagination.page, DEFAULT_PAGINATION_PAGE_COUNT);
        assert_eq!(pagination.count, DEFAULT_PAGINATION_PAGE_ITEMS_COUNT);
    }

    #[test]
    fn pagination_stays_copy() {
        let pagination = Pagination::default().with_from(8929261);
        let copied = pagination;

        assert_eq!(pagination.from, copied.from);
    }

    #[test]
    fn block_cursor_display() {
        assert_eq!(BlockCursor::block(8929261).to_string(), "8929261");
        assert_eq!(BlockCursor::tx(9999269, 10).to_string(), "9999269:10");
    }

    #[test]
    fn block_cursor_from_str() {
        assert_eq!("8929261".parse(), Ok(BlockCursor::block(8929261)));
        assert_eq!("9999269:10".parse(), Ok(BlockCursor::tx(9999269, 10)));
        assert!("nope".parse::<BlockCursor>().is_err());
    }
}