#![allow(dead_code)]
use bytemuck::cast_slice;
use derive_getters::Dissolve;
use rayon::prelude::*;
use std::ops::Range;
pub type Token = u32;
pub type Salt = Vec<u8>;
pub type SaltHash = u64;
pub type BlockHash = u64;
pub type SequenceHash = u64;
pub fn compute_hash_v2(data: &[u8], seed: u64) -> u64 {
xxhash_rust::xxh3::xxh3_64_with_seed(data, seed)
}
#[derive(Debug, Clone, Dissolve, Default, Eq)]
pub struct Tokens(Vec<Token>);
impl AsRef<[Token]> for Tokens {
fn as_ref(&self) -> &[Token] {
&self.0
}
}
impl std::ops::Deref for Tokens {
type Target = [Token];
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl std::borrow::Borrow<[Token]> for Tokens {
fn borrow(&self) -> &[Token] {
&self.0
}
}
impl From<Vec<Token>> for Tokens {
fn from(tokens: Vec<Token>) -> Self {
Tokens(tokens)
}
}
impl From<&[Token]> for Tokens {
fn from(tokens: &[Token]) -> Self {
Tokens(tokens.to_vec())
}
}
impl From<Vec<i32>> for Tokens {
fn from(tokens: Vec<i32>) -> Self {
Tokens(tokens.into_iter().map(|t| t as u32).collect())
}
}
impl From<&[i32]> for Tokens {
fn from(tokens: &[i32]) -> Self {
Tokens(tokens.iter().map(|&t| t as u32).collect())
}
}
impl From<Tokens> for Vec<Token> {
fn from(tokens: Tokens) -> Self {
tokens.0
}
}
impl PartialEq<Vec<Token>> for Tokens {
fn eq(&self, other: &Vec<Token>) -> bool {
self.0 == *other
}
}
impl PartialEq<Tokens> for Vec<Token> {
fn eq(&self, other: &Tokens) -> bool {
*self == other.0
}
}
impl PartialEq<[Token]> for Tokens {
fn eq(&self, other: &[Token]) -> bool {
self.0.as_slice() == other
}
}
impl PartialEq<Tokens> for &[Token] {
fn eq(&self, other: &Tokens) -> bool {
*self == other.0.as_slice()
}
}
impl PartialEq for Tokens {
fn eq(&self, other: &Self) -> bool {
self.0 == other.0
}
}
impl PartialEq<&[Token]> for Tokens {
fn eq(&self, other: &&[Token]) -> bool {
self.0.as_slice() == *other
}
}
impl Tokens {
pub fn into_sequence(
self,
block_size: usize,
salt_hash: Option<SaltHash>,
) -> TokenBlockSequence {
TokenBlockSequence::new(self, block_size, salt_hash)
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, thiserror::Error)]
pub enum TokenBlockError {
#[error("TokenBlock is full")]
Full,
#[error("TokenBlock is incomplete")]
Incomplete,
#[error("TokenBlock is empty")]
Empty,
#[error("TokenBlock has insufficient tokens")]
InsufficientTokens,
}
#[derive(Debug)] pub struct PartialTokenBlock {
tokens: Tokens,
block_size: usize,
salt_hash: SaltHash,
parent_sequence_hash: Option<SequenceHash>,
}
impl PartialTokenBlock {
pub(crate) fn create_sequence_root(block_size: usize, salt_hash: SaltHash) -> Self {
Self {
tokens: Tokens::default(),
block_size,
salt_hash,
parent_sequence_hash: None, }
}
pub(crate) fn push_token(&mut self, token: Token) -> Result<(), TokenBlockError> {
if self.tokens.0.len() >= self.block_size {
return Err(TokenBlockError::Full);
}
self.tokens.0.push(token);
Ok(())
}
pub(crate) fn push_tokens(&mut self, tokens: Tokens) -> Tokens {
let remaining_space = self.remaining();
if remaining_space == 0 {
return tokens; }
if tokens.0.len() <= remaining_space {
self.tokens.0.extend(tokens.0);
Tokens::default() } else {
let (to_add, remaining) = tokens.0.split_at(remaining_space);
self.tokens.0.extend_from_slice(to_add);
Tokens(remaining.to_vec()) }
}
pub(crate) fn pop_token(&mut self) -> Result<(), TokenBlockError> {
if self.tokens.0.is_empty() {
return Err(TokenBlockError::Empty);
}
self.tokens.0.pop();
Ok(())
}
pub(crate) fn pop_tokens(&mut self, count: usize) -> Result<(), TokenBlockError> {
if self.tokens.0.len() < count {
return Err(TokenBlockError::InsufficientTokens);
}
self.tokens.0.truncate(self.tokens.0.len() - count);
Ok(())
}
pub(crate) fn commit(&mut self) -> Result<TokenBlock, TokenBlockError> {
if self.tokens.0.len() != self.block_size {
return Err(TokenBlockError::Incomplete);
}
let tokens = std::mem::take(&mut self.tokens);
let chunk = TokenBlockChunk::new(tokens, self.salt_hash);
let block = TokenBlock::from_chunk(chunk, self.parent_sequence_hash);
self.parent_sequence_hash = Some(block.sequence_hash());
Ok(block)
}
pub fn remaining(&self) -> usize {
self.block_size.saturating_sub(self.tokens.0.len())
}
pub fn len(&self) -> usize {
self.tokens.0.len()
}
pub fn is_empty(&self) -> bool {
self.tokens.0.is_empty()
}
pub fn tokens(&self) -> &Tokens {
&self.tokens
}
}
impl std::ops::Deref for PartialTokenBlock {
type Target = Tokens;
fn deref(&self) -> &Self::Target {
&self.tokens
}
}
#[derive(Debug)] struct TokenBlockChunk {
tokens: Tokens,
salt_hash: SaltHash,
block_hash: BlockHash,
}
impl TokenBlockChunk {
fn new(tokens: Tokens, salt_hash: SaltHash) -> Self {
let block_hash = compute_hash_v2(cast_slice(&tokens), salt_hash);
Self {
tokens,
salt_hash,
block_hash,
}
}
fn from_tokens(tokens: &[Token], salt_hash: SaltHash) -> Self {
let block_hash = compute_hash_v2(cast_slice(tokens), salt_hash);
Self {
tokens: tokens.into(), salt_hash,
block_hash,
}
}
}
#[derive(Debug, Clone, Default, PartialEq)] pub struct TokenBlock {
tokens: Tokens,
salt_hash: SaltHash,
block_hash: BlockHash,
sequence_hash: SequenceHash,
parent_sequence_hash: Option<SequenceHash>,
}
impl TokenBlock {
pub fn next_block(&self) -> PartialTokenBlock {
PartialTokenBlock {
tokens: Tokens::default(),
block_size: self.tokens.len(), salt_hash: self.salt_hash,
parent_sequence_hash: Some(self.sequence_hash), }
}
fn from_chunk(chunk: TokenBlockChunk, parent_sequence_hash: Option<SequenceHash>) -> Self {
let sequence_hash = match parent_sequence_hash {
Some(parent) => {
compute_hash_v2(cast_slice(&[parent, chunk.block_hash]), chunk.salt_hash)
}
None => {
chunk.block_hash
}
};
Self {
tokens: chunk.tokens,
salt_hash: chunk.salt_hash,
block_hash: chunk.block_hash,
sequence_hash,
parent_sequence_hash,
}
}
pub fn tokens(&self) -> &Tokens {
&self.tokens
}
pub fn salt_hash(&self) -> SaltHash {
self.salt_hash
}
pub fn block_hash(&self) -> BlockHash {
self.block_hash
}
pub fn sequence_hash(&self) -> SequenceHash {
self.sequence_hash
}
pub fn parent_sequence_hash(&self) -> Option<SequenceHash> {
self.parent_sequence_hash
}
}
#[derive(Debug)]
pub struct TokenBlockSequence {
blocks: Vec<TokenBlock>,
current_block: PartialTokenBlock,
salt_hash: SaltHash,
}
impl TokenBlockSequence {
pub fn new(tokens: Tokens, block_size: usize, salt_hash: Option<SaltHash>) -> Self {
assert!(block_size > 0, "block_size must be greater than 0");
let salt_hash = salt_hash.unwrap_or(0);
let (blocks, current_block) = Self::split_tokens(&tokens, block_size, salt_hash);
Self {
blocks,
current_block,
salt_hash,
}
}
pub fn extend(&mut self, tokens: Tokens) -> Result<Option<Range<usize>>, TokenBlockError> {
let start_block_index = self.blocks.len();
let mut tokens_to_append = tokens;
while !tokens_to_append.is_empty() {
let remaining_in_current = self.current_block.remaining();
if remaining_in_current == 0 {
let new_block = self.current_block.commit()?;
self.blocks.push(new_block);
}
let available_tokens = tokens_to_append;
tokens_to_append = self.current_block.push_tokens(available_tokens);
if self.current_block.remaining() == 0 && !tokens_to_append.is_empty() {
let new_block = self.current_block.commit()?;
self.blocks.push(new_block);
}
}
let end_block_index = self.blocks.len();
if start_block_index == end_block_index {
Ok(None) } else {
Ok(Some(start_block_index..end_block_index))
}
}
pub fn append(&mut self, token: Token) -> Result<Option<usize>, TokenBlockError> {
let tokens = Tokens::from(vec![token]);
let range_option = self.extend(tokens)?;
match range_option {
None => Ok(None),
Some(range) => {
assert_eq!(range.len(), 1, "Appending a single token completed more than one block, which should be impossible.");
Ok(Some(range.start))
}
}
}
pub fn truncate(&mut self, len: usize) -> Result<(), TokenBlockError> {
let current_total_len = self.total_tokens();
if len >= current_total_len {
return Ok(()); }
let n = current_total_len - len;
{
let current_len = self.current_block.len();
let block_size = self.current_block.block_size.max(1);
if n <= current_len {
self.current_block.pop_tokens(n)?;
} else {
let tokens_to_pop_from_blocks = n - current_len;
let num_blocks_to_affect = tokens_to_pop_from_blocks.div_ceil(block_size);
if num_blocks_to_affect > self.blocks.len() {
debug_assert!(
false,
"Truncate calculation error: trying to pop too many blocks."
);
return Err(TokenBlockError::InsufficientTokens);
}
let source_block_index = self.blocks.len() - num_blocks_to_affect;
let num_full_blocks_completely_popped = num_blocks_to_affect - 1;
let num_tokens_to_pop_from_source_block =
tokens_to_pop_from_blocks - num_full_blocks_completely_popped * block_size;
let num_tokens_to_keep_in_new_partial =
block_size.saturating_sub(num_tokens_to_pop_from_source_block);
let new_partial_tokens = if num_tokens_to_keep_in_new_partial > 0 {
self.blocks[source_block_index].tokens().as_ref()
[..num_tokens_to_keep_in_new_partial]
.to_vec()
} else {
Vec::new()
};
self.blocks.truncate(source_block_index);
self.current_block.tokens = Tokens(new_partial_tokens);
self.current_block.parent_sequence_hash =
self.blocks.last().map(|b| b.sequence_hash());
}
}
Ok(())
}
pub fn unwind(&mut self, count: usize) -> Result<(), TokenBlockError> {
let current_total_len = self.total_tokens();
if count > current_total_len {
return Err(TokenBlockError::InsufficientTokens);
}
let len = current_total_len - count;
self.truncate(len)
}
pub fn pop(&mut self) -> Option<Token> {
let current_total_len = self.total_tokens();
if current_total_len == 0 {
return None;
}
let last_token = if !self.current_block.tokens.is_empty() {
*self
.current_block
.tokens
.last()
.expect("Current block checked for non-empty")
} else {
let last_block = self
.blocks
.last()
.expect("Sequence is not empty but has no blocks and empty current block?");
*last_block
.tokens()
.last()
.expect("Last block cannot be empty")
};
match self.truncate(current_total_len - 1) {
Ok(_) => Some(last_token),
Err(_) => {
debug_assert!(
false,
"truncate failed unexpectedly after checking length in pop"
);
None
}
}
}
pub fn blocks(&self) -> &[TokenBlock] {
&self.blocks
}
pub fn last_complete_block(&self) -> Option<&TokenBlock> {
self.blocks.last()
}
pub fn current_block(&self) -> &PartialTokenBlock {
&self.current_block
}
pub fn into_parts(self) -> (Vec<TokenBlock>, PartialTokenBlock) {
(self.blocks, self.current_block)
}
pub fn salt_hash(&self) -> SaltHash {
self.salt_hash
}
pub fn total_tokens(&self) -> usize {
let block_size = self.current_block.block_size;
(self.blocks.len() * block_size) + self.current_block.len()
}
pub fn split_tokens(
tokens: &[Token],
block_size: usize,
salt_hash: u64,
) -> (Vec<TokenBlock>, PartialTokenBlock) {
assert!(block_size > 0, "block_size must be greater than 0");
let chunks: Vec<TokenBlockChunk> = tokens
.as_ref()
.par_chunks_exact(block_size)
.map(|chunk| TokenBlockChunk::from_tokens(chunk, salt_hash))
.collect();
let mut result_blocks = Vec::with_capacity(chunks.len());
let mut last_sequence_hash: Option<SequenceHash> = None;
for chunk in chunks {
let new_block = TokenBlock::from_chunk(chunk, last_sequence_hash);
last_sequence_hash = Some(new_block.sequence_hash());
result_blocks.push(new_block);
}
let remainder = tokens.as_ref().chunks_exact(block_size).remainder();
let current_block = PartialTokenBlock {
tokens: remainder.into(),
block_size,
salt_hash,
parent_sequence_hash: last_sequence_hash,
};
(result_blocks, current_block)
}
}
#[cfg(test)]
mod tests {
use super::*;
use bytemuck::cast_slice;
fn create_test_sequence(
initial_tokens: &[Token],
block_size: usize,
salt_hash: Option<SaltHash>,
) -> TokenBlockSequence {
TokenBlockSequence::new(Tokens::from(initial_tokens), block_size, salt_hash)
}
const TEST_SALT_HASH: SaltHash = 1337;
const HASH_1_4: BlockHash = 14643705804678351452; const SEQ_HASH_1_4: SequenceHash = HASH_1_4;
const HASH_5_8: BlockHash = 16777012769546811212; const SEQ_HASH_5_8: SequenceHash = 4945711292740353085; const HASH_9_12: BlockHash = 483935686894639516; const SEQ_HASH_9_12: SequenceHash = 12583592247330656132;
#[test]
fn test_validate_hash_constants() {
let salt = TEST_SALT_HASH;
let tokens_1_4 = &[1u32, 2, 3, 4];
let computed_hash_1_4 = compute_hash_v2(cast_slice(tokens_1_4), salt);
assert_eq!(computed_hash_1_4, HASH_1_4, "Mismatch for HASH_1_4");
assert_eq!(computed_hash_1_4, SEQ_HASH_1_4, "Mismatch for SEQ_HASH_1_4");
let tokens_5_8 = &[5u32, 6, 7, 8];
let computed_hash_5_8 = compute_hash_v2(cast_slice(tokens_5_8), salt);
assert_eq!(computed_hash_5_8, HASH_5_8, "Mismatch for HASH_5_8");
let computed_seq_hash_5_8 = compute_hash_v2(cast_slice(&[SEQ_HASH_1_4, HASH_5_8]), salt);
assert_eq!(
computed_seq_hash_5_8, SEQ_HASH_5_8,
"Mismatch for SEQ_HASH_5_8"
);
let tokens_9_12 = &[9u32, 10, 11, 12];
let computed_hash_9_12 = compute_hash_v2(cast_slice(tokens_9_12), salt);
assert_eq!(computed_hash_9_12, HASH_9_12, "Mismatch for HASH_9_12");
let computed_seq_hash_9_12 = compute_hash_v2(cast_slice(&[SEQ_HASH_5_8, HASH_9_12]), salt);
assert_eq!(
computed_seq_hash_9_12, SEQ_HASH_9_12,
"Mismatch for SEQ_HASH_9_12"
);
}
#[test]
fn test_tokens_from() {
let vec_u32: Vec<u32> = vec![1, 2, 3];
let tokens_u32: Tokens = vec_u32.clone().into();
assert_eq!(tokens_u32.0, vec_u32);
let slice_u32: &[u32] = &[4, 5];
let tokens_slice_u32: Tokens = slice_u32.into();
assert_eq!(tokens_slice_u32.0, vec![4, 5]);
let vec_i32: Vec<i32> = vec![-1, 0, 1]; let tokens_i32: Tokens = vec_i32.into();
assert_eq!(tokens_i32.0, vec![u32::MAX, 0, 1]);
let slice_i32: &[i32] = &[100, 200];
let tokens_slice_i32: Tokens = slice_i32.into();
assert_eq!(tokens_slice_i32.0, vec![100, 200]);
let into_vec: Vec<u32> = tokens_slice_i32.into();
assert_eq!(into_vec, vec![100, 200]);
}
#[test]
fn test_tokens_equality() {
let tokens = Tokens::from(vec![1, 2, 3]);
assert_eq!(tokens, vec![1, 2, 3]);
assert_eq!(vec![1, 2, 3], tokens);
assert_eq!(tokens, &[1, 2, 3][..]);
assert_eq!(&[1, 2, 3][..], tokens);
assert_eq!(tokens, Tokens::from(vec![1, 2, 3]));
assert_ne!(tokens, Tokens::from(vec![1, 2, 4]));
}
#[test]
fn test_tokens_deref_asref() {
let tokens = Tokens::from(vec![10, 20, 30]);
assert_eq!(tokens.len(), 3);
assert_eq!(tokens[1], 20);
let slice: &[Token] = &tokens;
assert_eq!(slice, &[10, 20, 30]);
let as_ref_slice: &[Token] = tokens.as_ref();
assert_eq!(as_ref_slice, &[10, 20, 30]);
let borrowed_slice: &[Token] = std::borrow::Borrow::borrow(&tokens);
assert_eq!(borrowed_slice, &[10, 20, 30]);
}
#[test]
fn test_tokens_into_sequence() {
let tokens = Tokens::from(vec![1, 2, 3, 4, 5]);
let seq = tokens.into_sequence(3, Some(TEST_SALT_HASH));
assert_eq!(seq.blocks().len(), 1);
assert_eq!(seq.blocks[0].tokens().as_ref(), &[1, 2, 3]);
assert_eq!(seq.current_block().tokens().as_ref(), &[4, 5]);
assert_eq!(seq.salt_hash(), TEST_SALT_HASH);
}
#[test]
fn test_partial_block_ops() {
let mut partial = PartialTokenBlock::create_sequence_root(3, TEST_SALT_HASH);
assert_eq!(partial.len(), 0);
assert_eq!(partial.remaining(), 3);
assert!(partial.is_empty());
assert!(partial.push_token(1).is_ok());
assert_eq!(partial.len(), 1);
assert_eq!(partial.remaining(), 2);
let remaining = partial.push_tokens(Tokens::from(vec![2, 3, 4]));
assert_eq!(partial.len(), 3);
assert_eq!(partial.remaining(), 0);
assert_eq!(remaining.as_ref(), &[4]); assert_eq!(partial.tokens().as_ref(), &[1, 2, 3]);
assert_eq!(partial.push_token(5), Err(TokenBlockError::Full));
let remaining_full = partial.push_tokens(Tokens::from(vec![5]));
assert_eq!(remaining_full.as_ref(), &[5]);
assert!(partial.pop_token().is_ok());
assert_eq!(partial.len(), 2);
assert_eq!(partial.tokens().as_ref(), &[1, 2]);
assert!(partial.pop_tokens(2).is_ok());
assert!(partial.is_empty());
assert_eq!(partial.pop_token(), Err(TokenBlockError::Empty));
assert_eq!(
partial.pop_tokens(1),
Err(TokenBlockError::InsufficientTokens)
);
assert!(partial.push_token(10).is_ok());
assert_eq!(partial.commit(), Err(TokenBlockError::Incomplete));
assert!(partial.push_token(11).is_ok());
assert!(partial.push_token(12).is_ok());
assert_eq!(partial.len(), 3);
let commit_result = partial.commit();
assert!(commit_result.is_ok());
let committed_block = commit_result.unwrap();
assert_eq!(committed_block.tokens().as_ref(), &[10, 11, 12]);
assert!(partial.is_empty());
assert_eq!(
partial.parent_sequence_hash,
Some(committed_block.sequence_hash())
);
assert_eq!(partial.block_size, 3);
}
#[test]
fn test_token_block_creation_and_hashes() {
let salt = TEST_SALT_HASH;
let tokens1 = Tokens::from(vec![1, 2, 3, 4]);
let chunk1 = TokenBlockChunk::new(tokens1.clone(), salt);
let block1 = TokenBlock::from_chunk(chunk1, None);
assert_eq!(block1.tokens(), &tokens1);
assert_eq!(block1.salt_hash(), salt);
assert_eq!(block1.parent_sequence_hash(), None);
assert_eq!(block1.block_hash(), HASH_1_4);
assert_eq!(block1.sequence_hash(), SEQ_HASH_1_4);
let tokens2 = Tokens::from(vec![5, 6, 7, 8]);
let chunk2 = TokenBlockChunk::new(tokens2.clone(), salt);
let block2 = TokenBlock::from_chunk(chunk2, block1.parent_sequence_hash()); assert_ne!(block2.sequence_hash(), SEQ_HASH_5_8);
let chunk2_correct = TokenBlockChunk::new(tokens2.clone(), salt);
let block2_correct = TokenBlock::from_chunk(chunk2_correct, Some(block1.sequence_hash()));
assert_eq!(block2_correct.tokens(), &tokens2);
assert_eq!(block2_correct.salt_hash(), salt);
assert_eq!(
block2_correct.parent_sequence_hash(),
Some(block1.sequence_hash())
);
assert_eq!(block2_correct.block_hash(), HASH_5_8);
assert_eq!(block2_correct.sequence_hash(), SEQ_HASH_5_8);
}
#[test]
fn test_new_sequence() {
let seq_empty = create_test_sequence(&[], 4, Some(TEST_SALT_HASH));
assert!(seq_empty.blocks().is_empty());
assert!(seq_empty.current_block().is_empty());
assert_eq!(seq_empty.total_tokens(), 0);
assert_eq!(seq_empty.salt_hash(), TEST_SALT_HASH);
assert_eq!(seq_empty.current_block().parent_sequence_hash, None);
let seq_partial = create_test_sequence(&[1, 2], 4, Some(TEST_SALT_HASH));
assert!(seq_partial.blocks().is_empty());
assert_eq!(seq_partial.current_block().tokens().as_ref(), &[1, 2]);
assert_eq!(seq_partial.total_tokens(), 2);
assert_eq!(seq_partial.current_block().parent_sequence_hash, None);
let seq_one_block = create_test_sequence(&[1, 2, 3, 4], 4, Some(TEST_SALT_HASH));
assert_eq!(seq_one_block.blocks().len(), 1);
assert!(seq_one_block.current_block().is_empty());
assert_eq!(seq_one_block.total_tokens(), 4);
assert_eq!(seq_one_block.blocks[0].tokens().as_ref(), &[1, 2, 3, 4]);
assert_eq!(seq_one_block.blocks[0].sequence_hash(), SEQ_HASH_1_4);
assert_eq!(
seq_one_block.current_block().parent_sequence_hash,
Some(SEQ_HASH_1_4)
);
let seq_multi = create_test_sequence(&[1, 2, 3, 4, 5, 6, 7, 8, 9], 4, Some(TEST_SALT_HASH));
assert_eq!(seq_multi.blocks().len(), 2);
assert_eq!(seq_multi.current_block().tokens().as_ref(), &[9]);
assert_eq!(seq_multi.total_tokens(), 9);
assert_eq!(seq_multi.blocks[0].sequence_hash(), SEQ_HASH_1_4);
assert_eq!(seq_multi.blocks[1].sequence_hash(), SEQ_HASH_5_8);
assert_eq!(
seq_multi.current_block().parent_sequence_hash,
Some(SEQ_HASH_5_8)
);
let seq_no_salt = create_test_sequence(&[1, 2, 3, 4, 5], 4, None);
assert_eq!(seq_no_salt.salt_hash(), 0);
assert_eq!(seq_no_salt.blocks().len(), 1);
assert_ne!(seq_no_salt.blocks[0].block_hash(), HASH_1_4); assert_eq!(seq_no_salt.current_block().tokens().as_ref(), &[5]);
}
#[test]
#[should_panic]
fn test_new_sequence_zero_block_size() {
let _ = create_test_sequence(&[1], 0, None);
}
#[test]
fn test_append_single_token() {
let mut sequence =
create_test_sequence(&[1, 2, 3, 4, 5, 6, 7, 8, 9, 10], 4, Some(TEST_SALT_HASH));
assert_eq!(sequence.blocks().len(), 2);
assert_eq!(sequence.current_block().tokens.len(), 2);
assert_eq!(sequence.current_block().tokens, vec![9, 10]);
assert_eq!(
sequence.current_block().parent_sequence_hash,
Some(SEQ_HASH_5_8)
);
let completed_idx = sequence.append(11).unwrap();
assert_eq!(completed_idx, None);
assert_eq!(sequence.blocks().len(), 2);
assert_eq!(sequence.current_block().tokens.as_ref(), &[9, 10, 11]);
let completed_idx = sequence.append(12).unwrap();
assert_eq!(completed_idx, None); assert_eq!(sequence.blocks().len(), 2); assert_eq!(sequence.current_block.tokens.as_ref(), &[9, 10, 11, 12]); assert_eq!(sequence.current_block.remaining(), 0);
assert_eq!(
sequence.current_block().parent_sequence_hash,
Some(SEQ_HASH_5_8)
);
let completed_idx_13 = sequence.append(13).unwrap();
assert_eq!(completed_idx_13, Some(2)); assert_eq!(sequence.blocks.len(), 3); assert_eq!(sequence.blocks[2].tokens().as_ref(), &[9, 10, 11, 12]); assert_eq!(sequence.blocks[2].sequence_hash(), SEQ_HASH_9_12);
assert_eq!(sequence.current_block.tokens.as_ref(), &[13]); assert_eq!(sequence.current_block.remaining(), 3);
assert_eq!(
sequence.current_block.parent_sequence_hash,
Some(SEQ_HASH_9_12)
); }
#[test]
fn test_extend() {
let block_size = 4;
let salt_hash = Some(TEST_SALT_HASH);
let mut seq1 = create_test_sequence(&[], block_size, salt_hash);
let tokens1 = Tokens::from(vec![1, 2]);
let completed1 = seq1.extend(tokens1).unwrap();
assert_eq!(completed1, None); assert_eq!(seq1.blocks.len(), 0);
assert_eq!(seq1.current_block.tokens.as_ref(), &[1, 2]);
assert_eq!(seq1.current_block.remaining(), 2);
let mut seq2 = create_test_sequence(&[], block_size, salt_hash);
let tokens2 = Tokens::from(vec![1, 2, 3, 4]);
let completed2 = seq2.extend(tokens2).unwrap();
assert_eq!(completed2, None); assert_eq!(seq2.blocks.len(), 0); assert_eq!(seq2.current_block.tokens.as_ref(), &[1, 2, 3, 4]); assert_eq!(seq2.current_block.remaining(), 0);
assert_eq!(seq2.current_block.parent_sequence_hash, None);
let mut seq3 = create_test_sequence(&[], block_size, salt_hash);
let tokens3 = Tokens::from(vec![1, 2, 3, 4, 5, 6]);
let completed3 = seq3.extend(tokens3).unwrap();
assert_eq!(completed3, Some(0..1)); assert_eq!(seq3.blocks.len(), 1);
assert_eq!(seq3.current_block.tokens.as_ref(), &[5, 6]); assert_eq!(seq3.blocks[0].tokens().as_ref(), &[1, 2, 3, 4]);
assert_eq!(seq3.current_block.parent_sequence_hash, Some(SEQ_HASH_1_4));
assert_eq!(seq3.current_block.remaining(), 2);
let mut seq4 = create_test_sequence(&[], block_size, salt_hash);
let tokens4 = Tokens::from(vec![1, 2, 3, 4, 5, 6, 7, 8]);
let completed4 = seq4.extend(tokens4).unwrap();
assert_eq!(completed4, Some(0..1)); assert_eq!(seq4.blocks.len(), 1); assert_eq!(seq4.current_block.tokens.as_ref(), &[5, 6, 7, 8]); assert_eq!(seq4.current_block.remaining(), 0); assert_eq!(seq4.blocks[0].tokens().as_ref(), &[1, 2, 3, 4]);
assert_eq!(seq4.blocks[0].sequence_hash(), SEQ_HASH_1_4);
assert_eq!(seq4.current_block.parent_sequence_hash, Some(SEQ_HASH_1_4));
let mut seq5 = create_test_sequence(&[], block_size, salt_hash);
let tokens5a = Tokens::from(vec![1, 2]);
let completed5a = seq5.extend(tokens5a).unwrap();
assert_eq!(completed5a, None);
assert_eq!(seq5.blocks.len(), 0);
assert_eq!(seq5.current_block.tokens.as_ref(), &[1, 2]);
let tokens5b = Tokens::from(vec![3, 4, 5]);
let completed5b = seq5.extend(tokens5b).unwrap();
assert_eq!(completed5b, Some(0..1)); assert_eq!(seq5.blocks.len(), 1);
assert_eq!(seq5.current_block.tokens.as_ref(), &[5]);
assert_eq!(seq5.blocks[0].tokens().as_ref(), &[1, 2, 3, 4]);
assert_eq!(seq5.current_block.parent_sequence_hash, Some(SEQ_HASH_1_4));
assert_eq!(seq5.current_block.remaining(), 3);
let tokens5c = Tokens::from(vec![6, 7, 8, 9, 10]);
let completed5c = seq5.extend(tokens5c).unwrap();
assert_eq!(completed5c, Some(1..2)); assert_eq!(seq5.blocks.len(), 2);
assert_eq!(seq5.current_block.tokens.as_ref(), &[9, 10]);
assert_eq!(seq5.blocks[1].tokens().as_ref(), &[5, 6, 7, 8]);
assert_eq!(seq5.current_block.parent_sequence_hash, Some(SEQ_HASH_5_8));
assert_eq!(seq5.current_block.remaining(), 2);
let mut seq6 = create_test_sequence(&[1], block_size, salt_hash);
let completed6 = seq6.extend(Tokens::default()).unwrap();
assert_eq!(completed6, None);
assert_eq!(seq6.blocks.len(), 0);
assert_eq!(seq6.current_block.tokens.as_ref(), &[1]);
assert_eq!(seq6.total_tokens(), 1);
let mut seq7 = create_test_sequence(&[1, 2], block_size, salt_hash);
let tokens7 = Tokens::from(vec![3, 4]);
let completed7 = seq7.extend(tokens7).unwrap();
assert_eq!(completed7, None); assert_eq!(seq7.blocks.len(), 0);
assert_eq!(seq7.current_block.tokens.as_ref(), &[1, 2, 3, 4]); assert_eq!(seq7.current_block.remaining(), 0);
assert_eq!(seq7.total_tokens(), 4);
assert_eq!(seq7.current_block.parent_sequence_hash, None); }
#[test]
fn test_truncate() {
let block_size = 4;
let salt_hash = Some(TEST_SALT_HASH);
let initial_tokens = &[1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
let mut seq1 = create_test_sequence(initial_tokens, block_size, salt_hash);
assert!(seq1.truncate(9).is_ok());
assert_eq!(seq1.total_tokens(), 9);
assert_eq!(seq1.blocks().len(), 2);
assert_eq!(seq1.current_block().tokens.as_ref(), &[9]);
assert_eq!(
seq1.current_block().parent_sequence_hash,
Some(SEQ_HASH_5_8)
);
let mut seq2 = create_test_sequence(initial_tokens, block_size, salt_hash);
assert!(seq2.truncate(8).is_ok());
assert_eq!(seq2.total_tokens(), 8);
assert_eq!(seq2.blocks().len(), 2);
assert!(seq2.current_block().tokens.is_empty());
assert_eq!(
seq2.current_block().parent_sequence_hash,
Some(SEQ_HASH_5_8)
);
let mut seq3 = create_test_sequence(initial_tokens, block_size, salt_hash);
assert!(seq3.truncate(7).is_ok());
assert_eq!(seq3.total_tokens(), 7);
assert_eq!(seq3.blocks().len(), 1); assert_eq!(seq3.current_block().tokens.as_ref(), &[5, 6, 7]); assert_eq!(
seq3.current_block().parent_sequence_hash,
Some(SEQ_HASH_1_4)
); assert_eq!(seq3.blocks()[0].tokens().as_ref(), &[1, 2, 3, 4]);
let mut seq4 = create_test_sequence(initial_tokens, block_size, salt_hash);
assert!(seq4.truncate(4).is_ok());
assert_eq!(seq4.total_tokens(), 4);
assert_eq!(seq4.blocks().len(), 1); assert!(seq4.current_block().tokens.is_empty()); assert_eq!(
seq4.current_block().parent_sequence_hash,
Some(SEQ_HASH_1_4)
);
assert_eq!(seq4.blocks()[0].tokens().as_ref(), &[1, 2, 3, 4]);
let mut seq5 = create_test_sequence(initial_tokens, block_size, salt_hash);
assert!(seq5.truncate(3).is_ok());
assert_eq!(seq5.total_tokens(), 3);
assert!(seq5.blocks().is_empty()); assert_eq!(seq5.current_block().tokens.as_ref(), &[1, 2, 3]); assert_eq!(seq5.current_block().parent_sequence_hash, None);
let mut seq6 = create_test_sequence(initial_tokens, block_size, salt_hash);
assert!(seq6.truncate(0).is_ok());
assert_eq!(seq6.total_tokens(), 0);
assert!(seq6.blocks().is_empty());
assert!(seq6.current_block().tokens.is_empty());
assert_eq!(seq6.current_block().parent_sequence_hash, None);
let mut seq7 = create_test_sequence(initial_tokens, block_size, salt_hash);
let original_state = (seq7.blocks.clone(), seq7.current_block.tokens.clone()); assert!(seq7.truncate(11).is_ok()); assert_eq!(seq7.total_tokens(), 10);
assert_eq!(seq7.blocks, original_state.0);
assert_eq!(seq7.current_block.tokens, original_state.1);
let mut seq8 = create_test_sequence(initial_tokens, block_size, salt_hash);
let original_state = (seq8.blocks.clone(), seq8.current_block.tokens.clone());
assert!(seq8.truncate(10).is_ok());
assert_eq!(seq8.total_tokens(), 10);
assert_eq!(seq8.blocks, original_state.0);
assert_eq!(seq8.current_block.tokens, original_state.1);
let mut seq9 = create_test_sequence(&[], block_size, salt_hash);
assert!(seq9.truncate(0).is_ok());
assert_eq!(seq9.total_tokens(), 0);
assert!(seq9.blocks().is_empty());
assert!(seq9.current_block().tokens.is_empty());
let tokens10 = &[1, 2, 3, 4, 5, 6, 7, 8]; let mut seq10 = create_test_sequence(tokens10, block_size, salt_hash);
assert_eq!(seq10.total_tokens(), 8);
assert!(seq10.current_block().is_empty());
assert!(seq10.truncate(4).is_ok()); assert_eq!(seq10.total_tokens(), 4);
assert_eq!(seq10.blocks().len(), 1);
assert!(seq10.current_block().tokens.is_empty());
assert_eq!(
seq10.current_block().parent_sequence_hash,
Some(SEQ_HASH_1_4)
);
let tokens11 = &[1, 2, 3, 4, 5, 6, 7, 8]; let mut seq11 = create_test_sequence(tokens11, block_size, salt_hash);
assert!(seq11.truncate(3).is_ok()); assert_eq!(seq11.total_tokens(), 3);
assert!(seq11.blocks().is_empty());
assert_eq!(seq11.current_block().tokens.as_ref(), &[1, 2, 3]); assert_eq!(seq11.current_block().parent_sequence_hash, None);
}
#[test]
fn test_unwind() {
let block_size = 4;
let salt_hash = Some(TEST_SALT_HASH);
let initial_tokens = &[1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
let mut seq = create_test_sequence(initial_tokens, block_size, salt_hash);
assert!(seq.unwind(0).is_ok());
assert_eq!(seq.total_tokens(), 10);
let mut seq = create_test_sequence(initial_tokens, block_size, salt_hash);
assert!(seq.unwind(1).is_ok());
assert_eq!(seq.total_tokens(), 9);
assert_eq!(seq.current_block.tokens.as_ref(), &[9]);
let mut seq = create_test_sequence(initial_tokens, block_size, salt_hash);
assert!(seq.unwind(3).is_ok());
assert_eq!(seq.total_tokens(), 7);
assert_eq!(seq.blocks.len(), 1);
assert_eq!(seq.current_block.tokens.as_ref(), &[5, 6, 7]);
let mut seq = create_test_sequence(initial_tokens, block_size, salt_hash);
assert!(seq.unwind(10).is_ok());
assert_eq!(seq.total_tokens(), 0);
assert!(seq.blocks.is_empty());
assert!(seq.current_block.is_empty());
let mut seq = create_test_sequence(initial_tokens, block_size, salt_hash);
assert_eq!(seq.unwind(11), Err(TokenBlockError::InsufficientTokens));
assert_eq!(seq.total_tokens(), 10);
let mut seq_empty = create_test_sequence(&[], block_size, salt_hash);
assert_eq!(
seq_empty.unwind(1),
Err(TokenBlockError::InsufficientTokens)
);
}
#[test]
fn test_pop() {
let block_size = 4;
let salt_hash = Some(TEST_SALT_HASH);
let initial_tokens = &[1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
let mut seq = create_test_sequence(initial_tokens, block_size, salt_hash);
assert_eq!(seq.pop(), Some(10));
assert_eq!(seq.total_tokens(), 9);
assert_eq!(seq.current_block.tokens.as_ref(), &[9]);
assert_eq!(seq.blocks.len(), 2);
assert_eq!(seq.pop(), Some(9));
assert_eq!(seq.total_tokens(), 8);
assert!(seq.current_block.is_empty());
assert_eq!(seq.blocks.len(), 2);
assert_eq!(seq.current_block.parent_sequence_hash, Some(SEQ_HASH_5_8));
assert_eq!(seq.pop(), Some(8));
assert_eq!(seq.total_tokens(), 7);
assert_eq!(seq.current_block.tokens.as_ref(), &[5, 6, 7]);
assert_eq!(seq.blocks.len(), 1);
assert_eq!(seq.current_block.parent_sequence_hash, Some(SEQ_HASH_1_4));
assert_eq!(seq.pop(), Some(7));
assert_eq!(seq.pop(), Some(6));
assert_eq!(seq.pop(), Some(5));
assert_eq!(seq.total_tokens(), 4);
assert!(seq.current_block.is_empty());
assert_eq!(seq.blocks.len(), 1);
assert_eq!(seq.current_block.parent_sequence_hash, Some(SEQ_HASH_1_4));
assert_eq!(seq.pop(), Some(4));
assert_eq!(seq.total_tokens(), 3);
assert_eq!(seq.current_block.tokens.as_ref(), &[1, 2, 3]);
assert!(seq.blocks.is_empty());
assert_eq!(seq.current_block.parent_sequence_hash, None);
assert_eq!(seq.pop(), Some(3));
assert_eq!(seq.pop(), Some(2));
assert_eq!(seq.pop(), Some(1));
assert_eq!(seq.total_tokens(), 0);
assert!(seq.current_block.is_empty());
assert!(seq.blocks.is_empty());
assert_eq!(seq.pop(), None);
assert_eq!(seq.total_tokens(), 0);
}
#[test]
fn test_total_tokens() {
let block_size = 3;
let salt_hash = Some(TEST_SALT_HASH);
let mut seq = create_test_sequence(&[], block_size, salt_hash);
assert_eq!(seq.total_tokens(), 0);
seq.extend(Tokens::from(vec![1, 2])).unwrap();
assert_eq!(seq.total_tokens(), 2);
seq.append(3).unwrap(); assert_eq!(seq.total_tokens(), 3);
seq.extend(Tokens::from(vec![4, 5, 6, 7])).unwrap(); assert_eq!(seq.total_tokens(), 7);
seq.pop().unwrap(); assert_eq!(seq.total_tokens(), 6);
seq.truncate(4).unwrap(); assert_eq!(seq.total_tokens(), 4);
seq.unwind(2).unwrap(); assert_eq!(seq.total_tokens(), 2);
}
#[test]
fn test_push_tokens_partial_block() {
let mut partial = PartialTokenBlock::create_sequence_root(4, 1337);
let tokens = Tokens(vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10]);
let remaining = partial.push_tokens(tokens);
assert_eq!(partial.tokens.len(), 4);
assert_eq!(remaining.len(), 6);
}
}