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:
@@ -303,7 +303,7 @@ impl<'a> Fuzzer<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Generates a possibly invalid update.
|
/// Generates a possibly invalid update.
|
||||||
fn update(&mut self) -> StoreUpdate {
|
fn update(&mut self) -> StoreUpdate<Vec<u8>> {
|
||||||
match self.entropy.read_range(0, 1) {
|
match self.entropy.read_range(0, 1) {
|
||||||
0 => {
|
0 => {
|
||||||
let key = self.key();
|
let key = self.key();
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ use self::bitfield::Length;
|
|||||||
use self::bitfield::{count_zeros, num_bits, Bit, Checksum, ConstField, Field};
|
use self::bitfield::{count_zeros, num_bits, Bit, Checksum, ConstField, Field};
|
||||||
use crate::{usize_to_nat, Nat, Storage, StorageIndex, StoreError, StoreResult, StoreUpdate};
|
use crate::{usize_to_nat, Nat, Storage, StorageIndex, StoreError, StoreResult, StoreUpdate};
|
||||||
use alloc::vec::Vec;
|
use alloc::vec::Vec;
|
||||||
|
use core::borrow::Borrow;
|
||||||
use core::cmp::min;
|
use core::cmp::min;
|
||||||
use core::convert::TryFrom;
|
use core::convert::TryFrom;
|
||||||
|
|
||||||
@@ -492,13 +493,16 @@ impl Format {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the capacity required by a transaction.
|
/// 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() {
|
match updates.len() {
|
||||||
// An empty transaction doesn't consume anything.
|
// An empty transaction doesn't consume anything.
|
||||||
0 => 0,
|
0 => 0,
|
||||||
// Transactions with a single update are optimized by avoiding a marker entry.
|
// Transactions with a single update are optimized by avoiding a marker entry.
|
||||||
1 => match &updates[0] {
|
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.
|
// Transactions with a single update which is a removal don't consume anything.
|
||||||
StoreUpdate::Remove { .. } => 0,
|
StoreUpdate::Remove { .. } => 0,
|
||||||
},
|
},
|
||||||
@@ -508,9 +512,9 @@ impl Format {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the capacity of an update.
|
/// 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 {
|
match update {
|
||||||
StoreUpdate::Insert { value, .. } => self.entry_size(value),
|
StoreUpdate::Insert { value, .. } => self.entry_size(value.borrow()),
|
||||||
StoreUpdate::Remove { .. } => 1,
|
StoreUpdate::Remove { .. } => 1,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -523,7 +527,10 @@ impl Format {
|
|||||||
/// Checks if a transaction is valid and returns its sorted keys.
|
/// Checks if a transaction is valid and returns its sorted keys.
|
||||||
///
|
///
|
||||||
/// Returns `None` if the transaction is invalid.
|
/// 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() {
|
if usize_to_nat(updates.len()) > self.max_updates() {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -34,7 +34,7 @@ pub enum StoreOperation {
|
|||||||
/// Applies a transaction.
|
/// Applies a transaction.
|
||||||
Transaction {
|
Transaction {
|
||||||
/// The list of updates to be applied.
|
/// The list of updates to be applied.
|
||||||
updates: Vec<StoreUpdate>,
|
updates: Vec<StoreUpdate<Vec<u8>>>,
|
||||||
},
|
},
|
||||||
|
|
||||||
/// Deletes all keys above a threshold.
|
/// Deletes all keys above a threshold.
|
||||||
@@ -89,7 +89,7 @@ impl StoreModel {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Applies a transaction.
|
/// 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.
|
// Fail if the transaction is invalid.
|
||||||
if self.format.transaction_valid(&updates).is_none() {
|
if self.format.transaction_valid(&updates).is_none() {
|
||||||
return Err(StoreError::InvalidArgument);
|
return Err(StoreError::InvalidArgument);
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ pub use crate::{
|
|||||||
};
|
};
|
||||||
use alloc::boxed::Box;
|
use alloc::boxed::Box;
|
||||||
use alloc::vec::Vec;
|
use alloc::vec::Vec;
|
||||||
|
use core::borrow::Borrow;
|
||||||
use core::cmp::{max, min, Ordering};
|
use core::cmp::{max, min, Ordering};
|
||||||
use core::convert::TryFrom;
|
use core::convert::TryFrom;
|
||||||
use core::option::NoneError;
|
use core::option::NoneError;
|
||||||
@@ -159,15 +160,15 @@ impl StoreHandle {
|
|||||||
|
|
||||||
/// Represents an update to the store as part of a transaction.
|
/// Represents an update to the store as part of a transaction.
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub enum StoreUpdate {
|
pub enum StoreUpdate<ByteSlice: Borrow<[u8]>> {
|
||||||
/// Inserts or replaces an entry in the store.
|
/// 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.
|
/// Removes an entry from the store.
|
||||||
Remove { key: usize },
|
Remove { key: usize },
|
||||||
}
|
}
|
||||||
|
|
||||||
impl StoreUpdate {
|
impl<ByteSlice: Borrow<[u8]>> StoreUpdate<ByteSlice> {
|
||||||
/// Returns the key affected by the update.
|
/// Returns the key affected by the update.
|
||||||
pub fn key(&self) -> usize {
|
pub fn key(&self) -> usize {
|
||||||
match *self {
|
match *self {
|
||||||
@@ -179,7 +180,7 @@ impl StoreUpdate {
|
|||||||
/// Returns the value written by the update.
|
/// Returns the value written by the update.
|
||||||
pub fn value(&self) -> Option<&[u8]> {
|
pub fn value(&self) -> Option<&[u8]> {
|
||||||
match self {
|
match self {
|
||||||
StoreUpdate::Insert { value, .. } => Some(value),
|
StoreUpdate::Insert { value, .. } => Some(value.borrow()),
|
||||||
StoreUpdate::Remove { .. } => None,
|
StoreUpdate::Remove { .. } => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -280,14 +281,17 @@ impl<S: Storage> Store<S> {
|
|||||||
/// - There are too many updates.
|
/// - There are too many updates.
|
||||||
/// - The updates overlap, i.e. their keys are not disjoint.
|
/// - The updates overlap, i.e. their keys are not disjoint.
|
||||||
/// - The updates are invalid, e.g. key out of bound or value too long.
|
/// - 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());
|
let count = usize_to_nat(updates.len());
|
||||||
if count == 0 {
|
if count == 0 {
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
if count == 1 {
|
if count == 1 {
|
||||||
match updates[0] {
|
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),
|
StoreUpdate::Remove { key } => return self.remove(key),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -310,7 +314,7 @@ impl<S: Storage> Store<S> {
|
|||||||
for update in updates {
|
for update in updates {
|
||||||
let length = match *update {
|
let length = match *update {
|
||||||
StoreUpdate::Insert { key, ref value } => {
|
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 word_size = self.format.word_size();
|
||||||
let footer = usize_to_nat(entry.len()) / word_size - 1;
|
let footer = usize_to_nat(entry.len()) / word_size - 1;
|
||||||
self.write_slice(tail, &entry[..(footer * word_size) as usize])?;
|
self.write_slice(tail, &entry[..(footer * word_size) as usize])?;
|
||||||
|
|||||||
Reference in New Issue
Block a user