Skip to content

Commit

Permalink
[ᚬframework] feat(framework/binding): add Iterator and impl FixedCode…
Browse files Browse the repository at this point in the history
…c for rust primitive type (nervosnetwork#72)

* feat(framework/binding): 1. add iterator for StoreMap and StoreArray \n 2. impl FixedCodec for u8,u32,u64,bool,String

* fix FixedCodecError

* rebase

* fix u64 for overflowing_add
  • Loading branch information
nolanxyg authored and yejiayu committed Dec 29, 2019
1 parent 50d54c1 commit 29bdbc1
Show file tree
Hide file tree
Showing 10 changed files with 246 additions and 127 deletions.
2 changes: 1 addition & 1 deletion built-in-services/asset/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@ impl<SDK: ServiceSDK> AssetService<SDK> {
.into());
}

let to_balance = self.sdk.get_account_value(&to, &asset_id)?.unwrap_or(0);
let to_balance: u64 = self.sdk.get_account_value(&to, &asset_id)?.unwrap_or(0);
let (v, overflow) = to_balance.overflowing_add(value);
if overflow {
return Err(ServiceError::U64Overflow.into());
Expand Down
66 changes: 39 additions & 27 deletions framework/src/binding/store/array.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,8 @@ impl<S: ServiceState, E: FixedCodec> DefaultStoreArray<S, E> {
}

impl<S: ServiceState, E: FixedCodec> StoreArray<E> for DefaultStoreArray<S, E> {
fn get(&self, index: usize) -> ProtocolResult<E> {
if let Some(k) = self.keys.inner.get(index) {
fn get(&self, index: u32) -> ProtocolResult<E> {
if let Some(k) = self.keys.inner.get(index as usize) {
self.state.borrow().get(k)?.map_or_else(
|| <_>::decode_fixed(Bytes::new()).map_err(|_| StoreError::DecodeError.into()),
Ok,
Expand All @@ -69,17 +69,17 @@ impl<S: ServiceState, E: FixedCodec> StoreArray<E> for DefaultStoreArray<S, E> {

// TODO(@zhounan): Atomicity of insert(k, v) and insert self.keys to
// ServiceState is not guaranteed for now That must be settled soon after.
fn remove(&mut self, index: usize) -> ProtocolResult<()> {
let key = self.keys.inner.remove(index);
fn remove(&mut self, index: u32) -> ProtocolResult<()> {
let key = self.keys.inner.remove(index as usize);
self.state
.borrow_mut()
.insert(self.var_name.clone(), self.keys.encode_fixed()?)?;

self.state.borrow_mut().insert(key, Bytes::new())
}

fn len(&self) -> ProtocolResult<usize> {
Ok(self.keys.inner.len())
fn len(&self) -> ProtocolResult<u32> {
Ok(self.keys.inner.len() as u32)
}

fn is_empty(&self) -> ProtocolResult<bool> {
Expand All @@ -90,28 +90,40 @@ impl<S: ServiceState, E: FixedCodec> StoreArray<E> for DefaultStoreArray<S, E> {
}
}

// TODO(@zhounan): If element was not changed by f, then it should not be
// inserted to ServiceState for performance reason
fn for_each<F>(&mut self, mut f: F) -> ProtocolResult<()>
where
Self: Sized,
F: FnMut(&mut E) -> ProtocolResult<()>,
{
for key in &self.keys.inner {
let mut elm: E = self
.state
.borrow()
.get(key)?
.map_or_else::<ProtocolResult<E>, _, _>(
|| <_>::decode_fixed(Bytes::new()).map_err(|_| StoreError::DecodeError.into()),
Ok,
)?;

f(&mut elm)?;

self.state.borrow_mut().insert(key.clone(), elm)?;
fn iter<'a>(&'a self) -> Box<dyn Iterator<Item = (u32, E)> + 'a> {
Box::new(ArrayIter::<E, Self>::new(0, self))
}
}

struct ArrayIter<'a, E: FixedCodec, A: StoreArray<E>> {
idx: u32,
array: &'a A,
phantom: PhantomData<E>,
}

impl<'a, E: FixedCodec, A: StoreArray<E>> ArrayIter<'a, E, A> {
pub fn new(idx: u32, array: &'a A) -> Self {
ArrayIter {
idx,
array,
phantom: PhantomData,
}
}
}

Ok(())
impl<'a, E: FixedCodec, A: StoreArray<E>> Iterator for ArrayIter<'a, E, A> {
type Item = (u32, E);

fn next(&mut self) -> Option<Self::Item> {
if self.idx < self.array.len().expect("get len should not fail") {
let ele = self
.array
.get(self.idx)
.expect("iter get element should not fail");
self.idx += 1;
Some((self.idx - 1, ele))
} else {
None
}
}
}
71 changes: 53 additions & 18 deletions framework/src/binding/store/map.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use std::cell::RefCell;
use std::iter::Iterator;
use std::marker::PhantomData;
use std::rc::Rc;

Expand Down Expand Up @@ -49,8 +50,8 @@ impl<S: ServiceState, K: FixedCodec + PartialEq, V: FixedCodec> DefaultStoreMap<
}
}

impl<S: ServiceState, K: FixedCodec + PartialEq, V: FixedCodec> StoreMap<K, V>
for DefaultStoreMap<S, K, V>
impl<S: 'static + ServiceState, K: 'static + FixedCodec + PartialEq, V: 'static + FixedCodec>
StoreMap<K, V> for DefaultStoreMap<S, K, V>
{
fn get(&self, key: &K) -> ProtocolResult<V> {
if self.keys.inner.contains(key) {
Expand Down Expand Up @@ -100,8 +101,8 @@ impl<S: ServiceState, K: FixedCodec + PartialEq, V: FixedCodec> StoreMap<K, V>
}
}

fn len(&self) -> ProtocolResult<usize> {
Ok(self.keys.inner.len())
fn len(&self) -> ProtocolResult<u32> {
Ok(self.keys.inner.len() as u32)
}

fn is_empty(&self) -> ProtocolResult<bool> {
Expand All @@ -112,20 +113,54 @@ impl<S: ServiceState, K: FixedCodec + PartialEq, V: FixedCodec> StoreMap<K, V>
}
}

// TODO(@zhounan): If value was not changed by f, then it should not be inserted
// to ServiceState for performance reason
fn for_each<F>(&mut self, mut f: F) -> ProtocolResult<()>
where
Self: Sized,
F: FnMut(&mut V) -> ProtocolResult<()>,
{
for k in &self.keys.inner {
let mut v = self.get(k)?;
f(&mut v)?;
let mk = self.get_map_key(k)?;
self.state.borrow_mut().insert(mk, v)?;
}
fn iter<'a>(&'a self) -> Box<dyn Iterator<Item = (&K, V)> + 'a> {
Box::new(MapIter::<S, K, V>::new(0, self))
}
}

pub struct MapIter<
'a,
S: 'static + ServiceState,
K: 'static + FixedCodec + PartialEq,
V: 'static + FixedCodec,
> {
idx: u32,
map: &'a DefaultStoreMap<S, K, V>,
}

impl<
'a,
S: 'static + ServiceState,
K: 'static + FixedCodec + PartialEq,
V: 'static + FixedCodec,
> MapIter<'a, S, K, V>
{
pub fn new(idx: u32, map: &'a DefaultStoreMap<S, K, V>) -> Self {
Self { idx, map }
}
}

Ok(())
impl<
'a,
S: 'static + ServiceState,
K: 'static + FixedCodec + PartialEq,
V: 'static + FixedCodec,
> Iterator for MapIter<'a, S, K, V>
{
type Item = (&'a K, V);

fn next(&mut self) -> Option<Self::Item> {
if self.idx < self.map.len().expect("get len should not fail") {
let key = self
.map
.keys
.inner
.get(self.idx as usize)
.expect("get key should not fail");
self.idx += 1;
Some((key, self.map.get(key).expect("get value should not fail")))
} else {
None
}
}
}
60 changes: 13 additions & 47 deletions framework/src/binding/store/primitive.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,30 +28,13 @@ impl<S: ServiceState> DefaultStoreBool<S> {

impl<S: ServiceState> StoreBool for DefaultStoreBool<S> {
fn get(&self) -> ProtocolResult<bool> {
let bs: Bytes = self
.state
.borrow()
.get(&self.key)?
.ok_or(StoreError::GetNone)?;

let mut rdr = Cursor::new(bs.to_vec());
let u = rdr.read_u8().expect("read u8 should not fail");
match u {
0 => Ok(false),
1 => Ok(true),
_ => Err(StoreError::DecodeError.into()),
}
let b: Option<bool> = self.state.borrow().get(&self.key)?;

b.ok_or(StoreError::GetNone.into())
}

fn set(&mut self, b: bool) -> ProtocolResult<()> {
let bs = if b {
[1u8; mem::size_of::<u8>()]
} else {
[0u8; mem::size_of::<u8>()]
};

let val = Bytes::from(bs.as_ref());
self.state.borrow_mut().insert(self.key.clone(), val)?;
self.state.borrow_mut().insert(self.key.clone(), b)?;
Ok(())
}
}
Expand All @@ -72,25 +55,12 @@ impl<S: ServiceState> DefaultStoreUint64<S> {

impl<S: ServiceState> StoreUint64 for DefaultStoreUint64<S> {
fn get(&self) -> ProtocolResult<u64> {
let bs: Bytes = self
.state
.borrow()
.get(&self.key)?
.ok_or(StoreError::GetNone)?;
let mut rdr = Cursor::new(bs.to_vec());
let u: Option<u64> = self.state.borrow().get(&self.key)?;

Ok(rdr
.read_u64::<LittleEndian>()
.expect("read u64 should not fail"))
u.ok_or(StoreError::GetNone.into())
}

fn set(&mut self, val: u64) -> ProtocolResult<()> {
let mut bs = [0u8; mem::size_of::<u64>()];
bs.as_mut()
.write_u64::<LittleEndian>(val)
.expect("write u64 should not fail");
let val = Bytes::from(bs.as_ref());

self.state.borrow_mut().insert(self.key.clone(), val)?;
Ok(())
}
Expand Down Expand Up @@ -181,24 +151,20 @@ impl<S: ServiceState> DefaultStoreString<S> {

impl<S: ServiceState> StoreString for DefaultStoreString<S> {
fn set(&mut self, val: &str) -> ProtocolResult<()> {
let val = Bytes::from(val);

self.state.borrow_mut().insert(self.key.clone(), val)?;
self.state
.borrow_mut()
.insert(self.key.clone(), val.to_string())?;
Ok(())
}

fn get(&self) -> ProtocolResult<String> {
let bs: Bytes = self
.state
.borrow()
.get(&self.key)?
.ok_or(StoreError::GetNone)?;
let s: Option<String> = self.state.borrow().get(&self.key)?;

Ok(String::from_utf8(bs.to_vec()).expect("get string should not fail"))
s.ok_or(StoreError::GetNone.into())
}

fn len(&self) -> ProtocolResult<usize> {
self.get().map(|s| s.len())
fn len(&self) -> ProtocolResult<u32> {
self.get().map(|s| s.len() as u32)
}

fn is_empty(&self) -> ProtocolResult<bool> {
Expand Down
13 changes: 12 additions & 1 deletion framework/src/binding/tests/sdk.rs
Original file line number Diff line number Diff line change
Expand Up @@ -57,17 +57,28 @@ fn test_service_sdk() {
Bytes::from("val_1")
);

let mut it = sdk_map.iter();
assert_eq!(
it.next().unwrap(),
(&Hash::digest(Bytes::from("key_1")), Bytes::from("val_1"))
);
assert_eq!(it.next().is_none(), true);

// test sdk array
let mut sdk_array = sdk.alloc_or_recover_array::<Hash>("test_array").unwrap();
assert_eq!(sdk_array.is_empty().unwrap(), true);

sdk_array.push(Hash::digest(Bytes::from("key_1"))).unwrap();

assert_eq!(
sdk_array.get(0usize).unwrap(),
sdk_array.get(0).unwrap(),
Hash::digest(Bytes::from("key_1"))
);

let mut it = sdk_array.iter();
assert_eq!(it.next().unwrap(), (0, Hash::digest(Bytes::from("key_1"))));
assert_eq!(it.next().is_none(), true);

// test get/set account value
sdk.set_account_value(&mock_address(), Bytes::from("ak"), Bytes::from("av"))
.unwrap();
Expand Down
36 changes: 28 additions & 8 deletions framework/src/binding/tests/store.rs
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ fn test_default_store_string() {

ss.set("ok").unwrap();
assert_eq!(ss.get().unwrap(), String::from("ok"));
assert_eq!(ss.len().unwrap(), 2usize);
assert_eq!(ss.len().unwrap(), 2u32);
}

#[test]
Expand All @@ -85,6 +85,19 @@ fn test_default_store_map() {
sm.insert(Hash::digest(Bytes::from("key_2")), Bytes::from("val_2"))
.unwrap();

{
let mut it = sm.iter();
assert_eq!(
it.next().unwrap(),
(&Hash::digest(Bytes::from("key_1")), Bytes::from("val_1"))
);
assert_eq!(
it.next().unwrap(),
(&Hash::digest(Bytes::from("key_2")), Bytes::from("val_2"))
);
assert_eq!(it.next().is_none(), true);
}

assert_eq!(
sm.get(&Hash::digest(Bytes::from("key_1"))).unwrap(),
Bytes::from("val_1")
Expand All @@ -100,7 +113,7 @@ fn test_default_store_map() {
sm.contains(&Hash::digest(Bytes::from("key_1"))).unwrap(),
false
);
assert_eq!(sm.len().unwrap(), 1usize)
assert_eq!(sm.len().unwrap(), 1u32)
}

#[test]
Expand All @@ -111,16 +124,23 @@ fn test_default_store_array() {

let mut sa = DefaultStoreArray::<_, Bytes>::new(Rc::clone(&rs), "test");

assert_eq!(sa.len().unwrap(), 0usize);
assert_eq!(sa.len().unwrap(), 0u32);

sa.push(Bytes::from("111")).unwrap();
sa.push(Bytes::from("222")).unwrap();

assert_eq!(sa.get(0usize).unwrap(), Bytes::from("111"));
assert_eq!(sa.get(1usize).unwrap(), Bytes::from("222"));
{
let mut it = sa.iter();
assert_eq!(it.next().unwrap(), (0u32, Bytes::from("111")));
assert_eq!(it.next().unwrap(), (1u32, Bytes::from("222")));
assert_eq!(it.next().is_none(), true);
}

assert_eq!(sa.get(0u32).unwrap(), Bytes::from("111"));
assert_eq!(sa.get(1u32).unwrap(), Bytes::from("222"));

sa.remove(0usize).unwrap();
sa.remove(0u32).unwrap();

assert_eq!(sa.len().unwrap(), 1usize);
assert_eq!(sa.get(0usize).unwrap(), Bytes::from("222"));
assert_eq!(sa.len().unwrap(), 1u32);
assert_eq!(sa.get(0u32).unwrap(), Bytes::from("222"));
}
Loading

0 comments on commit 29bdbc1

Please sign in to comment.