use crate::{AsHashTree, Hash, HashTree};
use candid::types::Type;
use candid::CandidType;
use serde::{Deserialize, Deserializer, Serialize, Serializer};
use sha2::{Digest, Sha256};
use std::borrow::Borrow;
use std::iter::FromIterator;
use std::ops::Index;
use std::slice::{Iter, SliceIndex};
#[derive(Default, Eq, PartialEq, Clone, Debug)]
pub struct Seq<T> {
hash: Hash,
items: Vec<T>,
}
impl<T> Seq<T> {
#[inline]
pub const fn new() -> Self {
Self {
items: Vec::new(),
hash: [0; 32],
}
}
#[inline]
pub fn with_capacity(capacity: usize) -> Self {
Self {
items: Vec::with_capacity(capacity),
hash: [0; 32],
}
}
}
impl<T: AsHashTree> Seq<T> {
pub fn append(&mut self, item: T) {
let mut h = Sha256::new();
h.update(&self.hash);
h.update(item.root_hash());
self.hash = h.finalize().into();
self.items.push(item);
}
#[inline]
pub fn clear(&mut self) {
self.hash = [0; 32];
self.items.clear();
}
#[inline]
pub fn shrink_to_fit(&mut self) {
self.items.shrink_to_fit();
}
#[inline]
pub fn reserve(&mut self, additional: usize) {
self.items.reserve(additional)
}
#[inline]
pub fn reserve_exact(&mut self, additional: usize) {
self.items.reserve_exact(additional)
}
#[inline]
pub fn as_vec(&self) -> &Vec<T> {
&self.items
}
#[inline]
pub fn is_empty(&self) -> bool {
self.items.len() == 0
}
#[inline]
pub fn len(&self) -> usize {
self.items.len()
}
#[inline]
pub fn capacity(&self) -> usize {
self.items.capacity()
}
#[inline]
pub fn iter(&self) -> Iter<'_, T> {
self.items.iter()
}
#[inline]
fn recompute_hash(&mut self, prev_len: usize) {
let mut hash = self.hash;
for item in &self.items[prev_len..] {
let mut h = Sha256::new();
h.update(&hash);
h.update(item.root_hash());
hash = h.finalize().into();
}
self.hash = hash;
}
}
impl<T: AsHashTree> AsHashTree for Seq<T> {
#[inline]
fn root_hash(&self) -> Hash {
self.hash
}
#[inline]
fn as_hash_tree(&self) -> HashTree<'_> {
HashTree::Pruned(self.hash)
}
}
impl<T: AsHashTree> From<Vec<T>> for Seq<T> {
#[inline]
fn from(items: Vec<T>) -> Self {
let mut seq = Seq {
items,
hash: [0; 32],
};
seq.recompute_hash(0);
seq
}
}
impl<T: AsHashTree> FromIterator<T> for Seq<T> {
#[inline]
fn from_iter<I: IntoIterator<Item = T>>(iter: I) -> Self {
let mut seq = Seq {
items: iter.into_iter().collect(),
hash: [0; 32],
};
seq.recompute_hash(0);
seq
}
}
impl<T: AsHashTree> From<Seq<T>> for Vec<T> {
#[inline]
fn from(seq: Seq<T>) -> Self {
seq.items
}
}
impl<T: AsHashTree> AsRef<[T]> for Seq<T> {
#[inline]
fn as_ref(&self) -> &[T] {
self.items.as_ref()
}
}
impl<T: AsHashTree> Borrow<[T]> for Seq<T> {
#[inline]
fn borrow(&self) -> &[T] {
self.items.borrow()
}
}
impl<'a, T: AsHashTree + Copy + 'a> Extend<&'a T> for Seq<T> {
#[inline]
fn extend<I: IntoIterator<Item = &'a T>>(&mut self, iter: I) {
let prev_len = self.items.len();
self.items.extend(iter);
self.recompute_hash(prev_len)
}
}
impl<T: AsHashTree> Extend<T> for Seq<T> {
#[inline]
fn extend<I: IntoIterator<Item = T>>(&mut self, iter: I) {
let prev_len = self.items.len();
self.items.extend(iter);
self.recompute_hash(prev_len)
}
}
impl<'a, T: AsHashTree + Clone> From<&'a [T]> for Seq<T> {
#[inline]
fn from(items: &'a [T]) -> Self {
let mut seq = Seq {
items: items.into(),
hash: [0; 32],
};
seq.recompute_hash(0);
seq
}
}
impl<'a, T: AsHashTree + Clone> From<&'a mut [T]> for Seq<T> {
#[inline]
fn from(items: &'a mut [T]) -> Self {
let mut seq = Seq {
items: items.into(),
hash: [0; 32],
};
seq.recompute_hash(0);
seq
}
}
impl<T: AsHashTree, I: SliceIndex<[T]>> Index<I> for Seq<T> {
type Output = I::Output;
#[inline]
fn index(&self, index: I) -> &Self::Output {
self.items.index(index)
}
}
impl<T: Serialize + AsHashTree> Serialize for Seq<T> {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
self.items.serialize(serializer)
}
}
impl<'de, T: AsHashTree + Deserialize<'de>> Deserialize<'de> for Seq<T> {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
let mut seq = Seq {
items: <Vec<T>>::deserialize(deserializer)?,
hash: [0; 32],
};
seq.recompute_hash(0);
Ok(seq)
}
}
impl<T: CandidType> CandidType for Seq<T> {
fn _ty() -> Type {
<Vec<T>>::_ty()
}
fn idl_serialize<S>(&self, serializer: S) -> Result<(), S::Error>
where
S: candid::types::Serializer,
{
self.items.idl_serialize(serializer)
}
}
#[cfg(test)]
mod tests {
use super::*;
use candid::{decode_one, encode_one};
#[test]
fn append() {
let mut seq = Seq::<usize>::with_capacity(1000);
let mut hash = seq.root_hash();
assert_eq!(seq.is_empty(), true);
for i in 0..1000 {
seq.append(i);
assert_eq!(seq.len(), i + 1);
let new_hash = seq.root_hash();
assert_ne!(hash, new_hash);
hash = new_hash;
}
assert_eq!(seq.is_empty(), false);
seq.clear();
assert_eq!(seq.len(), 0);
assert_eq!(seq.is_empty(), true);
assert_eq!(seq.root_hash(), Seq::<usize>::new().root_hash());
for i in 0..1000 {
seq.append(i);
}
assert_eq!(hash, seq.root_hash());
}
#[test]
fn extend() {
let manual = {
let mut seq = Seq::<usize>::with_capacity(100);
for i in 0..100 {
seq.append(i);
}
seq
};
{
let mut seq = Seq::<usize>::new();
seq.extend(0..100);
assert_eq!(manual.len(), seq.len());
assert_eq!(manual.root_hash(), seq.root_hash());
}
{
let mut seq = Seq::<usize>::new();
seq.extend(0..50);
seq.extend(50..100);
assert_eq!(manual.len(), seq.len());
assert_eq!(manual.root_hash(), seq.root_hash());
}
{
let mut seq = Seq::<usize>::new();
seq.extend(0..50);
seq.append(50);
seq.extend(51..100);
assert_eq!(manual.len(), seq.len());
assert_eq!(manual.root_hash(), seq.root_hash());
}
}
#[test]
fn index() {
let seq = (0..100).collect::<Seq<_>>();
for i in 0..100 {
assert_eq!(seq[i], i);
}
}
#[test]
#[should_panic]
fn index_out_of_range() {
let seq = Seq::<u8>::new();
seq[0];
}
#[test]
fn serde_cbor() {
let seq = (0..10).collect::<Seq<_>>();
let serialized = serde_cbor::to_vec(&seq).unwrap();
let actual: Seq<i32> = serde_cbor::from_slice(&serialized).unwrap();
assert_eq!(actual.len(), 10);
assert_eq!(actual.hash, seq.hash);
assert_eq!(actual, seq);
let expected = (0..10).collect::<Vec<_>>();
let deserialized_as_vec: Vec<i32> = serde_cbor::from_slice(&serialized).unwrap();
assert_eq!(deserialized_as_vec, expected);
}
#[test]
fn candid() {
let seq = (0..10).collect::<Seq<_>>();
let encoded = encode_one(&seq).unwrap();
let decoded: Seq<i32> = decode_one(&encoded).unwrap();
assert_eq!(seq, decoded);
}
}