cido 0.2.0

Core traits and implementations for indexing with cido
Documentation
use crate::stable_hash::{self, FieldAddress};
use crate::types::*;

/// Used in proof of indexing to add a hash for the type of field that is used
///
/// This may be removed in the future depending on how useful it proves to be
#[repr(u8)]
pub enum ValueVariant {
  String = 1,     // AsString
  Int = 2,        // i32
  BigDecimal = 3, // BigDecimal
  Bool = 4,       // bool
  List = 5,       // Vec<T: ValueVariant != List>
  Bytes = 6,      // AsBytes<T: AsRef<[u8]>>
  BigInt = 7,     // BigInt
  Int8 = 8,       // i64
}

impl From<ValueVariant> for u8 {
  #[inline(always)]
  fn from(value: ValueVariant) -> Self {
    value as u8
  }
}

pub struct ValueTypeHasher<T: Hashable> {
  pub field: &'static str,
  pub data: T,
}

impl<T> stable_hash::StableHash for ValueTypeHasher<T>
where
  T: Hashable,
{
  fn stable_hash<H: stable_hash::StableHasher>(&self, field_address: H::Addr, state: &mut H) {
    self.field.stable_hash(field_address.child(0), state);
    <T as Hashable>::with_new(&self.data, field_address.child(1), state);
  }
}

/// This is the trait actually used in the implementation on entities and events and it hashes the
/// value along with its data type
pub trait Hashable: stable_hash::StableHash {
  fn with_new<H: stable_hash::StableHasher>(&self, field_address: H::Addr, state: &mut H) {
    <Self as stable_hash::StableHash>::stable_hash(self, field_address.child(0), state);
    state.write(field_address, &[Self::variant_numeric()]);
  }

  fn variant() -> ValueVariant;

  #[inline(always)]
  fn variant_numeric() -> u8 {
    Self::variant() as u8
  }
}

impl<'a, T: Hashable> Hashable for &'a T {
  #[inline(always)]
  fn variant() -> ValueVariant {
    <T as Hashable>::variant()
  }
}

impl<T: Hashable> Hashable for Vec<T> {
  #[inline(always)]
  fn variant() -> ValueVariant {
    ValueVariant::List
  }
}

impl<T: Hashable> Hashable for Option<T> {
  #[inline(always)]
  fn variant() -> ValueVariant {
    <T as Hashable>::variant()
  }

  fn with_new<H: stable_hash::StableHasher>(&self, field_address: H::Addr, state: &mut H) {
    if let Some(val) = self {
      <T as Hashable>::with_new(val, field_address, state)
    }
  }
}

/// String like implementations, the stable_hash implementations for this types
/// requires the types to be encoded as strings first.
mod string_like {
  use super::*;

  impl Hashable for String {
    #[inline(always)]
    fn variant() -> ValueVariant {
      ValueVariant::String
    }
  }

  impl<'a> Hashable for &'a str {
    #[inline(always)]
    fn variant() -> ValueVariant {
      <String as Hashable>::variant()
    }
  }
}

// treat it as an i32
impl Hashable for i16 {
  #[inline(always)]
  fn variant() -> ValueVariant {
    ValueVariant::Int
  }
}

impl Hashable for i32 {
  #[inline(always)]
  fn variant() -> ValueVariant {
    ValueVariant::Int
  }
}

impl Hashable for BigDecimal {
  #[inline(always)]
  fn variant() -> ValueVariant {
    ValueVariant::BigDecimal
  }
}

impl Hashable for bool {
  #[inline(always)]
  fn variant() -> ValueVariant {
    ValueVariant::Bool
  }
}

// todo: should be using AsBytes<&Vec<u8>> to hash Vec<u8> preferably
impl Hashable for Vec<u8> {
  #[inline(always)]
  fn variant() -> ValueVariant {
    ValueVariant::Bytes
  }
}

impl Hashable for crate::types::Bytes {
  #[inline(always)]
  fn variant() -> ValueVariant {
    ValueVariant::String
  }
}

impl Hashable for BigInt {
  #[inline(always)]
  fn variant() -> ValueVariant {
    ValueVariant::BigInt
  }
}

impl Hashable for i64 {
  #[inline(always)]
  fn variant() -> ValueVariant {
    ValueVariant::Int8
  }
}

impl<const N: usize> Hashable for H<N> {
  #[inline(always)]
  fn variant() -> ValueVariant {
    ValueVariant::Bytes
  }
}

impl<const N: usize> Hashable for U<N>
where
  U<N>: crate::types::ByteArray,
  <U<N> as crate::types::ByteArray>::Array: AsRef<[u8]>,
{
  #[inline(always)]
  fn variant() -> ValueVariant {
    ValueVariant::Bytes
  }
}