cido 0.2.0

Core traits and implementations for indexing with cido
Documentation
use core::cell::RefCell;
use core::fmt::{Debug, Display, Formatter};

mod array;
mod big_decimal;
mod big_int;
mod bytes;
mod hash;
mod unsigned;

pub use array::FixedArray;
pub use big_decimal::BigDecimal;
pub use big_int::{BigInt, Sign};
pub use bytes::Bytes;
pub use hash::H;
pub use unsigned::{ByteArray, U};
pub mod serde_util;

thread_local! {
  pub static TRANSIENT_STRING_SERIALIZER: RefCell<String> = const { RefCell::new(String::new()) };
  pub static TRANSIENT_BYTES_SERIALIZER: RefCell<Vec<u8>> = const { RefCell::new(Vec::new()) };
}

#[derive(Debug)]
pub enum DecodeHexError {
  WrongSize { expected: usize, actual: usize },
  WrongCharacter(char, char),
}

impl Display for DecodeHexError {
  fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
    match self {
      Self::WrongSize { expected, actual } => {
        write!(f, "Expected str of length {expected} got length {actual}")
      }
      Self::WrongCharacter(l, r) => write!(f, "Invalid character pair '{l}{r}'"),
    }
  }
}

impl std::error::Error for DecodeHexError {}

#[derive(Debug)]
pub enum ConversionError {
  WrongSize { expected: usize, actual: usize },
  Missing { field: &'static str },
}

impl ConversionError {
  pub const fn missing(field: &'static str) -> Self {
    Self::Missing { field }
  }
}

impl Display for ConversionError {
  fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
    match self {
      Self::WrongSize { expected, actual } => write!(
        f,
        "ConversionError: expected len {expected}, got len {actual}"
      ),
      Self::Missing { field } => write!(f, "Missing field '{field}'"),
    }
  }
}

impl std::error::Error for ConversionError {}

const fn byte_char_to_digit(c: u8) -> u8 {
  if c < b'0' {
    panic!("Invalid character");
  }
  let digit = c.wrapping_sub(b'0');
  if digit < 10 {
    digit
  } else {
    // Force the 6th bit to be set to ensure ascii is lower case.
    (c | 0b10_0000).wrapping_sub(b'a').saturating_add(10)
  }
}

#[doc(hidden)]
pub trait MissingField {
  type Return;
  fn missing(self, field: &'static str) -> Self::Return;
}

impl<T> MissingField for Option<T> {
  type Return = Result<T, ConversionError>;
  fn missing(self, field: &'static str) -> Self::Return {
    self.ok_or_else(|| ConversionError::missing(field))
  }
}