Skip to content

Commit

Permalink
StateVec iter and refactors
Browse files Browse the repository at this point in the history
  • Loading branch information
neysofu committed Aug 23, 2023
1 parent d2dfc1c commit adecd8b
Show file tree
Hide file tree
Showing 5 changed files with 132 additions and 161 deletions.
16 changes: 14 additions & 2 deletions module-system/sov-state/src/codec.rs
Original file line number Diff line number Diff line change
Expand Up @@ -112,9 +112,21 @@ where

/// A [`StateCodec`] that uses two different codecs under the hood, one for keys
/// and one for values.
#[derive(Debug, PartialEq, Eq, Clone)]
pub struct PairOfCodecs<KC, VC> {
pub key_codec: KC,
pub value_codec: VC,
key_codec: KC,
value_codec: VC,
}

impl<KC, VC> PairOfCodecs<KC, VC> {
/// Creates a new [`PairOfCodecs`] from a [`StateKeyCodec`] and a
/// [`StateValueCodec`].
pub fn new(key_codec: KC, value_codec: VC) -> Self {
Self {
key_codec,
value_codec,
}
}
}

impl<K, KC, VC> StateKeyCodec<K> for PairOfCodecs<KC, VC>
Expand Down
13 changes: 13 additions & 0 deletions module-system/sov-state/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,19 @@ impl Prefix {
pub fn is_empty(&self) -> bool {
self.prefix.is_empty()
}

pub fn extended(&self, bytes: &[u8]) -> Self {
let mut prefix = self.clone();
prefix.extend(bytes.iter().copied());
prefix
}
}

impl Extend<u8> for Prefix {
fn extend<T: IntoIterator<Item = u8>>(&mut self, iter: T) {
self.prefix
.extend(&AlignedVec::new(iter.into_iter().collect()))
}
}

/// A trait specifying the hash function and format of the witness used in
Expand Down
6 changes: 1 addition & 5 deletions module-system/sov-state/src/map.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,11 +37,7 @@ where
/// Creates a new [`StateMap`] with the given prefix and the default
/// [`StateCodec`] (i.e. [`BorshCodec`]).
pub fn new(prefix: Prefix) -> Self {
Self {
_phantom: (PhantomData, PhantomData),
codec: BorshCodec,
prefix,
}
Self::with_codec(prefix, BorshCodec)
}
}

Expand Down
78 changes: 18 additions & 60 deletions module-system/sov-state/src/value.rs
Original file line number Diff line number Diff line change
@@ -1,16 +1,15 @@
use std::marker::PhantomData;

use borsh::{BorshDeserialize, BorshSerialize};
use thiserror::Error;

use crate::codec::{BorshCodec, StateKeyCodec, StateValueCodec};
use crate::codec::{BorshCodec, PairOfCodecs, StateValueCodec};
use crate::{Prefix, Storage, WorkingSet};

/// Container for a single value.
#[derive(Debug, PartialEq, Eq, Clone, BorshDeserialize, BorshSerialize)]
#[derive(Debug, Clone)]
pub struct StateValue<V, C = BorshCodec> {
_phantom: PhantomData<V>,
codec: C,
value_codec: C,
prefix: Prefix,
}

Expand All @@ -26,25 +25,25 @@ where
BorshCodec: StateValueCodec<V>,
{
/// Crates a new [`StateValue`] with the given prefix and the default
/// [`StateCodec`] (i.e. [`BorshCodec`]).
/// [`StateValueCodec`] (i.e. [`BorshCodec`]).
pub fn new(prefix: Prefix) -> Self {
Self {
_phantom: PhantomData,
codec: BorshCodec,
value_codec: BorshCodec,
prefix,
}
}
}

impl<V, C> StateValue<V, C>
where
C: StateValueCodec<V>,
C: StateValueCodec<V> + Clone,
{
/// Creates a new [`StateValue`] with the given prefix and codec.
pub fn with_codec(prefix: Prefix, codec: C) -> Self {
Self {
_phantom: PhantomData,
codec,
value_codec: codec,
prefix,
}
}
Expand All @@ -55,17 +54,17 @@ where
}

fn internal_codec(&self) -> SingletonCodec<C> {
SingletonCodec::new(&self.codec)
SingletonCodec::new(BorshCodec, self.value_codec.clone())
}

/// Sets a value in the StateValue.
pub fn set<S: Storage>(&self, value: &V, working_set: &mut WorkingSet<S>) {
working_set.set_value(self.prefix(), &self.internal_codec(), &SingletonKey, value)
working_set.set_value(self.prefix(), &self.internal_codec(), &SINGLETON_KEY, value)
}

/// Gets a value from the StateValue or None if the value is absent.
pub fn get<S: Storage>(&self, working_set: &mut WorkingSet<S>) -> Option<V> {
working_set.get_value(self.prefix(), &self.internal_codec(), &SingletonKey)
working_set.get_value(self.prefix(), &self.internal_codec(), &SINGLETON_KEY)
}

/// Gets a value from the StateValue or Error if the value is absent.
Expand All @@ -76,7 +75,7 @@ where

/// Removes a value from the StateValue, returning the value (or None if the key is absent).
pub fn remove<S: Storage>(&self, working_set: &mut WorkingSet<S>) -> Option<V> {
working_set.remove_value(self.prefix(), &self.internal_codec(), &SingletonKey)
working_set.remove_value(self.prefix(), &self.internal_codec(), &SINGLETON_KEY)
}

/// Removes a value and from the StateValue, returning the value (or Error if the key is absent).
Expand All @@ -87,55 +86,14 @@ where

/// Deletes a value from the StateValue.
pub fn delete<S: Storage>(&self, working_set: &mut WorkingSet<S>) {
working_set.delete_value(self.prefix(), &self.internal_codec(), &SingletonKey);
working_set.delete_value(self.prefix(), &self.internal_codec(), &SINGLETON_KEY);
}
}

// SingletonKey is very similar to the unit type `()` i.e. it has only one value.
#[derive(Debug)]
struct SingletonKey;
// As a singleton key, we choose the unit type `()` because:
// 1. Is only has one legal value, i.e. it is a true singleton.
// 2. It is a zero-sized type (both in memory and in Borsh), so we're not
// wasting any space.
const SINGLETON_KEY: () = ();

/// Skips (de)serialization of keys and delegates values to another codec.
struct SingletonCodec<'a, VC> {
value_codec: &'a VC,
}

impl<'a, VC> SingletonCodec<'a, VC> {
pub fn new(value_codec: &'a VC) -> Self {
Self { value_codec }
}
}

impl<'a, VC> StateKeyCodec<SingletonKey> for SingletonCodec<'a, VC> {
type KeyError = std::io::Error;

fn encode_key(&self, _: &SingletonKey) -> Vec<u8> {
vec![]
}

fn try_decode_key(&self, bytes: &[u8]) -> Result<SingletonKey, Self::KeyError> {
if bytes.is_empty() {
Ok(SingletonKey)
} else {
Err(std::io::Error::new(
std::io::ErrorKind::InvalidData,
"SingletonKey must be empty",
))
}
}
}

impl<'a, V, VC> StateValueCodec<V> for SingletonCodec<'a, VC>
where
VC: StateValueCodec<V>,
{
type ValueError = VC::ValueError;

fn encode_value(&self, value: &V) -> Vec<u8> {
self.value_codec.encode_value(value)
}

fn try_decode_value(&self, bytes: &[u8]) -> Result<V, Self::ValueError> {
self.value_codec.try_decode_value(bytes)
}
}
type SingletonCodec<VC> = PairOfCodecs<BorshCodec, VC>;
Loading

0 comments on commit adecd8b

Please sign in to comment.