Unverified Commit b66ab319 authored by Hero Bird's avatar Hero Bird Committed by GitHub
Browse files

Enhance Flush (#136)

* [core] Enhance Flush trait to make it work with SyncCell and SyncChunk

* apply rustfmt
parent 7948d23b
......@@ -27,13 +27,13 @@ use std::{
fs,
io::{
Cursor,
Read,
Seek,
SeekFrom,
Write,
},
path,
};
use std::io::Read;
/// Initializes a project structure for the `lang` abstraction layer.
fn initialize_for_lang(name: &str) -> Result<()> {
......
......@@ -17,8 +17,8 @@
use super::ContractEnvStorage;
use crate::{
env::{
EnvStorage as _,
traits::Env,
EnvStorage as _,
},
memory::vec::Vec,
storage::Key,
......
......@@ -24,6 +24,6 @@ pub use self::types::DefaultSrmlTypes;
#[cfg(not(feature = "test-env"))]
pub use self::srml_only::{
sys,
SrmlEnvStorage,
SrmlEnv,
SrmlEnvStorage,
};
......@@ -16,9 +16,7 @@
use crate::{
env::{
srml::{
sys,
},
srml::sys,
Env,
EnvStorage,
EnvTypes,
......@@ -26,9 +24,7 @@ use crate::{
memory::vec::Vec,
storage::Key,
};
use core::{
marker::PhantomData,
};
use core::marker::PhantomData;
use parity_codec::Decode;
/// Load the contents of the scratch buffer
......@@ -78,7 +74,7 @@ pub struct SrmlEnv<T>
where
T: EnvTypes,
{
marker: PhantomData<fn () -> T>,
marker: PhantomData<fn() -> T>,
}
impl<T> EnvTypes for SrmlEnv<T>
......@@ -123,10 +119,18 @@ where
(caller, ext_caller, <Self as EnvTypes>::AccountId),
(random_seed, ext_random_seed, <Self as EnvTypes>::Hash),
(now, ext_now, <Self as EnvTypes>::Moment),
(block_number, ext_block_number, <Self as EnvTypes>::BlockNumber),
(
block_number,
ext_block_number,
<Self as EnvTypes>::BlockNumber
),
(gas_price, ext_gas_price, <Self as EnvTypes>::Balance),
(gas_left, ext_gas_left, <Self as EnvTypes>::Balance),
(value_transferred, ext_value_transferred, <Self as EnvTypes>::Balance)
(
value_transferred,
ext_value_transferred,
<Self as EnvTypes>::Balance
)
);
unsafe fn r#return(data: &[u8]) -> ! {
......
......@@ -18,6 +18,6 @@ mod impls;
pub mod sys;
pub use self::impls::{
SrmlEnvStorage,
SrmlEnv,
SrmlEnvStorage,
};
......@@ -17,10 +17,10 @@
//! Public api to interact with the special testing environment.
use crate::env::{
traits::EnvTypes,
ContractEnv,
ContractEnvStorage,
};
use crate::env::traits::EnvTypes;
/// Returns the total number of reads to all storage entries.
pub fn total_reads() -> u64 {
......
......@@ -27,7 +27,10 @@ use core::cell::{
Cell,
RefCell,
};
use parity_codec::{Decode, Encode};
use parity_codec::{
Decode,
Encode,
};
use std::marker::PhantomData;
/// A wrapper for the generic bytearray used for data in contract events.
......@@ -410,7 +413,7 @@ thread_local! {
/// Test environment for testing SRML contract off-chain.
pub struct TestEnv<T> {
marker: PhantomData<fn () -> T>
marker: PhantomData<fn() -> T>,
}
macro_rules! impl_env_setters_for_test_env {
......@@ -423,7 +426,10 @@ macro_rules! impl_env_setters_for_test_env {
}
}
impl<T> TestEnv<T> where T: EnvTypes {
impl<T> TestEnv<T>
where
T: EnvTypes,
{
/// Resets the test environment as if no contract execution happened so far.
pub fn reset() {
TEST_ENV_DATA.with(|test_env| test_env.borrow_mut().reset())
......@@ -447,7 +453,8 @@ impl<T> TestEnv<T> where T: EnvTypes {
/// Sets the input data for the next contract invocation.
pub fn set_input(input_bytes: &[u8]) {
TEST_ENV_DATA.with(|test_env| test_env.borrow_mut().set_input(input_bytes.to_vec()))
TEST_ENV_DATA
.with(|test_env| test_env.borrow_mut().set_input(input_bytes.to_vec()))
}
impl_env_setters_for_test_env!(
......@@ -494,7 +501,9 @@ where
type BlockNumber = <T as EnvTypes>::BlockNumber;
}
impl<T> Env for TestEnv<T> where T: EnvTypes
impl<T> Env for TestEnv<T>
where
T: EnvTypes,
{
impl_env_getters_for_test_env!(
(address, T::AccountId),
......
......@@ -305,12 +305,15 @@ impl<T> parity_codec::Decode for SyncCell<T> {
impl<T> Flush for SyncCell<T>
where
T: parity_codec::Encode,
T: parity_codec::Encode + Flush,
{
fn flush(&mut self) {
if self.cache.is_dirty() {
match self.cache.get() {
Some(val) => self.cell.store(val),
match self.cache.get_mut() {
Some(val) => {
self.cell.store(val);
val.flush();
},
None => self.cell.clear(),
}
self.cache.mark_clean();
......
......@@ -47,12 +47,15 @@ pub struct SyncChunk<T> {
impl<T> Flush for SyncChunk<T>
where
T: parity_codec::Encode,
T: parity_codec::Encode + Flush,
{
fn flush(&mut self) {
for (n, dirty_val) in self.cache.iter_dirty() {
match dirty_val.get() {
Some(val) => self.chunk.store(n, val),
match dirty_val.get_mut() {
Some(val) => {
self.chunk.store(n, val);
val.flush();
}
None => self.chunk.clear(n),
}
dirty_val.mark_clean();
......
......@@ -19,6 +19,7 @@ use parity_codec::{
Decode,
Encode,
};
use crate::storage::Flush;
/// A block of 1024 bits.
#[derive(Debug, Copy, Clone, Encode, Decode)]
......@@ -27,6 +28,10 @@ pub struct BitBlock {
packs: [BitPack; Self::PACKS as usize],
}
impl Flush for BitBlock {
fn flush(&mut self) {}
}
/// Error indicating an invalid bit pack index.
#[derive(Debug, Copy, Clone)]
struct InvalidBitBlockIndex;
......
......@@ -77,6 +77,19 @@ pub enum Entry<K, V> {
Removed,
}
impl<K, V> Flush for Entry<K, V>
where
K: parity_codec::Encode + Flush,
V: parity_codec::Encode + Flush,
{
fn flush(&mut self) {
match self {
Entry::Occupied(occupied) => occupied.flush(),
Entry::Removed => (),
}
}
}
/// An occupied entry of a storage map.
#[derive(Debug, Clone, PartialEq, Eq, parity_codec::Encode, parity_codec::Decode)]
pub struct OccupiedEntry<K, V> {
......@@ -86,10 +99,21 @@ pub struct OccupiedEntry<K, V> {
val: V,
}
impl<K, V> Flush for OccupiedEntry<K, V>
where
K: parity_codec::Encode + Flush,
V: parity_codec::Encode + Flush,
{
fn flush(&mut self) {
self.key.flush();
self.val.flush();
}
}
impl<K, V> Flush for HashMap<K, V>
where
K: parity_codec::Encode,
V: parity_codec::Encode,
K: parity_codec::Encode + Flush,
V: parity_codec::Encode + Flush,
{
fn flush(&mut self) {
self.len.flush();
......
......@@ -82,6 +82,14 @@ struct StashHeader {
max_len: u32,
}
impl Flush for StashHeader {
fn flush(&mut self) {
self.next_vacant.flush();
self.len.flush();
self.max_len.flush();
}
}
/// Iterator over the values of a stash.
#[derive(Debug)]
pub struct Values<'a, T> {
......@@ -98,7 +106,7 @@ impl<'a, T> Values<'a, T> {
impl<T> Flush for Stash<T>
where
T: Encode,
T: Encode + Flush,
{
fn flush(&mut self) {
self.header.flush();
......@@ -222,6 +230,18 @@ enum Entry<T> {
Occupied(T),
}
impl<T> Flush for Entry<T>
where
T: Flush,
{
fn flush(&mut self) {
match self {
Entry::Vacant(_) => (),
Entry::Occupied(occupied) => occupied.flush(),
}
}
}
impl<T> Encode for Stash<T> {
fn encode_to<W: parity_codec::Output>(&self, dest: &mut W) {
self.header.encode_to(dest);
......
......@@ -76,7 +76,7 @@ impl<'a, T> Iter<'a, T> {
impl<T> Flush for Vec<T>
where
T: parity_codec::Encode,
T: parity_codec::Encode + Flush,
{
fn flush(&mut self) {
self.len.flush();
......
......@@ -25,7 +25,7 @@
///
/// # Implementation Hints
///
/// Caching types provided by pDSL are `SyncCell` for caching of a single data
/// Caching types provided by ink! are `SyncCell` for caching of a single data
/// and `SyncChunk` for caching an array of data.
///
/// All abstractions built upon them that do not have their own caching mechanism
......@@ -33,5 +33,190 @@
/// `storage::Vec` or `storage::Value`.
pub trait Flush {
/// Flushes the cached state back to the contract storage, if any.
///
/// # Note
///
/// Needs to take `self` by `&mut` since `SyncChunk` and `SyncCell`
/// and potentially other abstraction facilities are required to
/// write back their cached values which is a mutable operation.
fn flush(&mut self);
}
macro_rules! impl_empty_flush_for {
( $($ty:ty),* ) => {
$(
impl Flush for $ty {
fn flush(&mut self) {}
}
)*
};
}
impl_empty_flush_for! {
u8, u16, u32, u64, u128, usize,
i8, i16, i32, i64, i128, isize,
bool, char, str
}
macro_rules! impl_tuple_flush_for {
( $(($n:tt, $name:ident)),* ) => {
impl< $($name),* > Flush for ($($name,)*)
where
$(
$name: Flush,
)*
{
fn flush(&mut self) {
$(
self.$n.flush();
)*
}
}
}
}
impl_tuple_flush_for!();
impl_tuple_flush_for!((0, A));
impl_tuple_flush_for!((0, A), (1, B));
impl_tuple_flush_for!((0, A), (1, B), (2, C));
impl_tuple_flush_for!((0, A), (1, B), (2, C), (3, D));
impl_tuple_flush_for!((0, A), (1, B), (2, C), (3, D), (4, E));
impl_tuple_flush_for!((0, A), (1, B), (2, C), (3, D), (4, E), (5, F));
impl_tuple_flush_for!((0, A), (1, B), (2, C), (3, D), (4, E), (5, F), (6, G));
impl_tuple_flush_for!(
(0, A),
(1, B),
(2, C),
(3, D),
(4, E),
(5, F),
(6, G),
(7, H)
);
macro_rules! impl_array_flush_for {
( $($n:literal),* ) => {
$(
impl<T> Flush for [T; $n]
where
T: Flush,
{
fn flush(&mut self) {
for elem in &mut self[..] {
elem.flush()
}
}
}
)*
}
}
#[rustfmt::skip]
impl_array_flush_for!(
0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
10, 11, 12, 13, 14, 15, 16, 17, 18, 19,
20, 21, 22, 23, 24, 25, 26, 27, 28, 29,
30, 31, 32
);
impl<T> Flush for [T]
where
T: Flush,
{
fn flush(&mut self) {
for elem in self {
elem.flush()
}
}
}
impl<T> Flush for Option<T>
where
T: Flush,
{
fn flush(&mut self) {
match self {
Some(val) => val.flush(),
None => (),
}
}
}
impl<T, E> Flush for Result<T, E>
where
T: Flush,
E: Flush,
{
fn flush(&mut self) {
match self {
Ok(val) => val.flush(),
Err(err) => err.flush(),
}
}
}
impl<T> Flush for crate::memory::vec::Vec<T>
where
T: Flush,
{
fn flush(&mut self) {
for elem in self {
elem.flush()
}
}
}
impl Flush for crate::memory::string::String {
fn flush(&mut self) {
// Note: Strings contain only characters that need no flushing.
}
}
impl<K, V> Flush for crate::memory::collections::btree_map::BTreeMap<K, V>
where
V: Flush,
{
fn flush(&mut self) {
for (_key, val) in self {
// We do not need to write back keys since they are immutable.
val.flush();
}
}
}
impl<T> Flush for crate::memory::collections::btree_set::BTreeSet<T> {
fn flush(&mut self) {
// Note: Values within a `BTreeSet` are immutable and thus need not be flushed.
}
}
impl<T> Flush for crate::memory::collections::linked_list::LinkedList<T>
where
T: Flush,
{
fn flush(&mut self) {
for elem in self {
elem.flush()
}
}
}
impl<T> Flush for crate::memory::collections::vec_deque::VecDeque<T>
where
T: Flush,
{
fn flush(&mut self) {
for elem in self {
elem.flush()
}
}
}
impl<T> Flush for crate::memory::collections::binary_heap::BinaryHeap<T>
where
T: Flush,
{
fn flush(&mut self) {
// Note: Values within a `BinaryHeap` are immutable and thus need not be flushed.
}
}
......@@ -163,45 +163,39 @@ impl KeyDiff {
}
macro_rules! impl_add_sub_for_key {
( $prim:ty ) => {
impl core::ops::Add<$prim> for Key {
type Output = Self;
( $prim:ty ) => {
impl core::ops::Add<$prim> for Key {
type Output = Self;
fn add(self, rhs: $prim) -> Self::Output {
let mut result = self;
result += rhs;
result
}
}
fn add(self, rhs: $prim) -> Self::Output {
let mut result = self;
result += rhs;
result
}
}
impl core::ops::AddAssign<$prim> for Key {
fn add_assign(&mut self, rhs: $prim) {
byte_utils::bytes_add_bytes(
self.as_bytes_mut(),
&(rhs.to_be_bytes())
);
}
}
impl core::ops::AddAssign<$prim> for Key {
fn add_assign(&mut self, rhs: $prim) {
byte_utils::bytes_add_bytes(self.as_bytes_mut(), &(rhs.to_be_bytes()));
}
}
impl core::ops::Sub<$prim> for Key {
type Output = Self;
impl core::ops::Sub<$prim> for Key {
type Output = Self;
fn sub(self, rhs: $prim) -> Self::Output {
let mut result = self;
result -= rhs;
result
}
}
fn sub(self, rhs: $prim) -> Self::Output {
let mut result = self;
result -= rhs;
result
}
}
impl core::ops::SubAssign<$prim> for Key {
fn sub_assign(&mut self, rhs: $prim) {
byte_utils::bytes_sub_bytes(
self.as_bytes_mut(),
&rhs.to_be_bytes()
);
}
}
};
impl core::ops::SubAssign<$prim> for Key {
fn sub_assign(&mut self, rhs: $prim) {
byte_utils::bytes_sub_bytes(self.as_bytes_mut(), &rhs.to_be_bytes());
}
}
};
}
impl_add_sub_for_key!(u32);
......
......@@ -160,7 +160,7 @@ where
impl<T> Flush for Value<T>
where
T: Encode,
T: Encode + Flush,
{
fn flush(&mut self) {
self.cell.flush()
......
......@@ -22,8 +22,11 @@ use serde::{
Deserialize,
Serialize,
};
use syn::{self, Result};
use std::convert::TryFrom;
use syn::{
self,
Result,
};
/// Describes a message parameter or return type.