From 8634e2ec2437eed88229f0a28a00c78016d6e3dc Mon Sep 17 00:00:00 2001 From: Julien Cretin Date: Wed, 20 Jan 2021 15:56:06 +0100 Subject: [PATCH] Make StoreUpdate generic over the byte slice ownership This permits to call it without having to create a Vec when possible. --- libraries/persistent_store/fuzz/src/store.rs | 2 +- libraries/persistent_store/src/format.rs | 17 ++++++++++++----- libraries/persistent_store/src/model.rs | 4 ++-- libraries/persistent_store/src/store.rs | 18 +++++++++++------- 4 files changed, 26 insertions(+), 15 deletions(-) diff --git a/libraries/persistent_store/fuzz/src/store.rs b/libraries/persistent_store/fuzz/src/store.rs index 3113f77..006532b 100644 --- a/libraries/persistent_store/fuzz/src/store.rs +++ b/libraries/persistent_store/fuzz/src/store.rs @@ -303,7 +303,7 @@ impl<'a> Fuzzer<'a> { } /// Generates a possibly invalid update. - fn update(&mut self) -> StoreUpdate { + fn update(&mut self) -> StoreUpdate> { match self.entropy.read_range(0, 1) { 0 => { let key = self.key(); diff --git a/libraries/persistent_store/src/format.rs b/libraries/persistent_store/src/format.rs index f575750..a70dcc4 100644 --- a/libraries/persistent_store/src/format.rs +++ b/libraries/persistent_store/src/format.rs @@ -20,6 +20,7 @@ use self::bitfield::Length; use self::bitfield::{count_zeros, num_bits, Bit, Checksum, ConstField, Field}; use crate::{usize_to_nat, Nat, Storage, StorageIndex, StoreError, StoreResult, StoreUpdate}; use alloc::vec::Vec; +use core::borrow::Borrow; use core::cmp::min; use core::convert::TryFrom; @@ -492,13 +493,16 @@ impl Format { } /// Returns the capacity required by a transaction. - pub fn transaction_capacity(&self, updates: &[StoreUpdate]) -> Nat { + pub fn transaction_capacity>( + &self, + updates: &[StoreUpdate], + ) -> Nat { match updates.len() { // An empty transaction doesn't consume anything. 0 => 0, // Transactions with a single update are optimized by avoiding a marker entry. 1 => match &updates[0] { - StoreUpdate::Insert { value, .. } => self.entry_size(value), + StoreUpdate::Insert { value, .. } => self.entry_size(value.borrow()), // Transactions with a single update which is a removal don't consume anything. StoreUpdate::Remove { .. } => 0, }, @@ -508,9 +512,9 @@ impl Format { } /// Returns the capacity of an update. - fn update_capacity(&self, update: &StoreUpdate) -> Nat { + fn update_capacity>(&self, update: &StoreUpdate) -> Nat { match update { - StoreUpdate::Insert { value, .. } => self.entry_size(value), + StoreUpdate::Insert { value, .. } => self.entry_size(value.borrow()), StoreUpdate::Remove { .. } => 1, } } @@ -523,7 +527,10 @@ impl Format { /// Checks if a transaction is valid and returns its sorted keys. /// /// Returns `None` if the transaction is invalid. - pub fn transaction_valid(&self, updates: &[StoreUpdate]) -> Option> { + pub fn transaction_valid>( + &self, + updates: &[StoreUpdate], + ) -> Option> { if usize_to_nat(updates.len()) > self.max_updates() { return None; } diff --git a/libraries/persistent_store/src/model.rs b/libraries/persistent_store/src/model.rs index c509b03..eebc329 100644 --- a/libraries/persistent_store/src/model.rs +++ b/libraries/persistent_store/src/model.rs @@ -34,7 +34,7 @@ pub enum StoreOperation { /// Applies a transaction. Transaction { /// The list of updates to be applied. - updates: Vec, + updates: Vec>>, }, /// Deletes all keys above a threshold. @@ -89,7 +89,7 @@ impl StoreModel { } /// Applies a transaction. - fn transaction(&mut self, updates: Vec) -> StoreResult<()> { + fn transaction(&mut self, updates: Vec>>) -> StoreResult<()> { // Fail if the transaction is invalid. if self.format.transaction_valid(&updates).is_none() { return Err(StoreError::InvalidArgument); diff --git a/libraries/persistent_store/src/store.rs b/libraries/persistent_store/src/store.rs index f707a89..224eeb9 100644 --- a/libraries/persistent_store/src/store.rs +++ b/libraries/persistent_store/src/store.rs @@ -25,6 +25,7 @@ pub use crate::{ }; use alloc::boxed::Box; use alloc::vec::Vec; +use core::borrow::Borrow; use core::cmp::{max, min, Ordering}; use core::convert::TryFrom; use core::option::NoneError; @@ -159,15 +160,15 @@ impl StoreHandle { /// Represents an update to the store as part of a transaction. #[derive(Clone, Debug)] -pub enum StoreUpdate { +pub enum StoreUpdate> { /// Inserts or replaces an entry in the store. - Insert { key: usize, value: Vec }, + Insert { key: usize, value: ByteSlice }, /// Removes an entry from the store. Remove { key: usize }, } -impl StoreUpdate { +impl> StoreUpdate { /// Returns the key affected by the update. pub fn key(&self) -> usize { match *self { @@ -179,7 +180,7 @@ impl StoreUpdate { /// Returns the value written by the update. pub fn value(&self) -> Option<&[u8]> { match self { - StoreUpdate::Insert { value, .. } => Some(value), + StoreUpdate::Insert { value, .. } => Some(value.borrow()), StoreUpdate::Remove { .. } => None, } } @@ -280,14 +281,17 @@ impl Store { /// - There are too many updates. /// - The updates overlap, i.e. their keys are not disjoint. /// - The updates are invalid, e.g. key out of bound or value too long. - pub fn transaction(&mut self, updates: &[StoreUpdate]) -> StoreResult<()> { + pub fn transaction>( + &mut self, + updates: &[StoreUpdate], + ) -> StoreResult<()> { let count = usize_to_nat(updates.len()); if count == 0 { return Ok(()); } if count == 1 { match updates[0] { - StoreUpdate::Insert { key, ref value } => return self.insert(key, value), + StoreUpdate::Insert { key, ref value } => return self.insert(key, value.borrow()), StoreUpdate::Remove { key } => return self.remove(key), } } @@ -310,7 +314,7 @@ impl Store { for update in updates { let length = match *update { StoreUpdate::Insert { key, ref value } => { - let entry = self.format.build_user(usize_to_nat(key), value)?; + let entry = self.format.build_user(usize_to_nat(key), value.borrow())?; let word_size = self.format.word_size(); let footer = usize_to_nat(entry.len()) / word_size - 1; self.write_slice(tail, &entry[..(footer * word_size) as usize])?;