Make StoreUpdate generic over the byte slice ownership
This permits to call it without having to create a Vec<u8> when possible.
This commit is contained in:
@@ -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<ByteSlice: Borrow<[u8]>>(
|
||||
&self,
|
||||
updates: &[StoreUpdate<ByteSlice>],
|
||||
) -> 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<ByteSlice: Borrow<[u8]>>(&self, update: &StoreUpdate<ByteSlice>) -> 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<Vec<Nat>> {
|
||||
pub fn transaction_valid<ByteSlice: Borrow<[u8]>>(
|
||||
&self,
|
||||
updates: &[StoreUpdate<ByteSlice>],
|
||||
) -> Option<Vec<Nat>> {
|
||||
if usize_to_nat(updates.len()) > self.max_updates() {
|
||||
return None;
|
||||
}
|
||||
|
||||
@@ -34,7 +34,7 @@ pub enum StoreOperation {
|
||||
/// Applies a transaction.
|
||||
Transaction {
|
||||
/// The list of updates to be applied.
|
||||
updates: Vec<StoreUpdate>,
|
||||
updates: Vec<StoreUpdate<Vec<u8>>>,
|
||||
},
|
||||
|
||||
/// Deletes all keys above a threshold.
|
||||
@@ -89,7 +89,7 @@ impl StoreModel {
|
||||
}
|
||||
|
||||
/// Applies a transaction.
|
||||
fn transaction(&mut self, updates: Vec<StoreUpdate>) -> StoreResult<()> {
|
||||
fn transaction(&mut self, updates: Vec<StoreUpdate<Vec<u8>>>) -> StoreResult<()> {
|
||||
// Fail if the transaction is invalid.
|
||||
if self.format.transaction_valid(&updates).is_none() {
|
||||
return Err(StoreError::InvalidArgument);
|
||||
|
||||
@@ -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<ByteSlice: Borrow<[u8]>> {
|
||||
/// Inserts or replaces an entry in the store.
|
||||
Insert { key: usize, value: Vec<u8> },
|
||||
Insert { key: usize, value: ByteSlice },
|
||||
|
||||
/// Removes an entry from the store.
|
||||
Remove { key: usize },
|
||||
}
|
||||
|
||||
impl StoreUpdate {
|
||||
impl<ByteSlice: Borrow<[u8]>> StoreUpdate<ByteSlice> {
|
||||
/// 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<S: Storage> Store<S> {
|
||||
/// - 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<ByteSlice: Borrow<[u8]>>(
|
||||
&mut self,
|
||||
updates: &[StoreUpdate<ByteSlice>],
|
||||
) -> 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<S: Storage> Store<S> {
|
||||
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])?;
|
||||
|
||||
Reference in New Issue
Block a user