-
Notifications
You must be signed in to change notification settings - Fork 259
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat(collections): unstable new vector implementation #402
Merged
Merged
Changes from all commits
Commits
Show all changes
45 commits
Select commit
Hold shift + click to select a range
1e90139
add unstable feature
austinabell 1446ad0
feat: setup unstable vec collection and basic implementations
austinabell babd92e
setup framework for caching values (wip and unsafe)
austinabell c2e39b8
fmt and update pop impl
austinabell 6efbc64
Merge branch 'master' into unstable_vec
mikedotexe 13e0662
implement load methods
austinabell 63de2af
implement swap remove
austinabell b884f32
finish base implementation
austinabell e5e1ca8
implement iterator functionality
austinabell b35a49b
replace casting as potential panic
austinabell 4f360b8
implement index trait impls
austinabell 38cc873
port over existing tests
austinabell 486cd46
swap some tests to use new APIs to test
austinabell 5aed715
update debug
austinabell c0d088d
remove duplicate extend and fix modified match (oops)
austinabell 8fb7324
this is ugly but seems to solve unsoundness issue
austinabell e56b207
Merge branch 'master' of github.com:near/near-sdk-rs into unstable_vec
austinabell a6ba75b
migrate vec to store module
austinabell 75ffd20
Merge branch 'master' of github.com:near/near-sdk-rs into unstable_vec
austinabell 1335407
refactor storage load deserialization to fix bug and cleanup
austinabell b378bf4
add safety doc on load
austinabell 7a7de54
refactor: update cache interface to avoid unsafe usages
austinabell e67dc3f
update docs
austinabell c51b1ce
move stable map to utils
austinabell fffc91f
fmt
austinabell 39648fa
Merge branch 'master' into unstable_vec
austinabell 82eb8fa
test and fix iterator logic and panic message
austinabell 2f602b9
switch iterator range to use ops::Range
austinabell 7dc6049
update lifetime cast on iter mut function
austinabell 9e54bb6
reuse buffer for serialization on flush (thanks matklad)
austinabell f9b94f8
switch get mut inner to check index within bounds
austinabell e531d1c
combine debug impls
austinabell f6bc152
switch fmt function call to be more explicit
austinabell 4b0da03
remove into conversions
austinabell 032a968
update prefix to be boxed slice to minimize type size
austinabell a3d344f
Merge branch 'master' into unstable_vec
austinabell c0cb627
fmt
austinabell 29b0fdf
fix debug derives and iter exports
austinabell 6b89716
Merge branch 'master' of github.com:near/near-sdk-rs into unstable_vec
austinabell b8380c3
Merge branch 'master' into unstable_vec
austinabell 78875b8
Merge branch 'master' into unstable_vec
austinabell 2b5f8f5
switch to new panic sig
austinabell 00acbb6
rebuild wasm
austinabell 482ab02
Merge branch 'master' of github.com:near/near-sdk-rs into unstable_vec
austinabell 9e0f9ec
update docs
austinabell File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,4 +1,8 @@ | ||
mod lazy; | ||
mod lazy_option; | ||
pub use lazy::Lazy; | ||
|
||
mod lazy_option; | ||
pub use lazy_option::LazyOption; | ||
|
||
pub mod vec; | ||
pub use vec::Vector; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,72 @@ | ||
use borsh::{BorshDeserialize, BorshSerialize}; | ||
|
||
use super::iter::{Iter, IterMut}; | ||
use super::{Vector, ERR_INDEX_OUT_OF_BOUNDS}; | ||
use crate::env; | ||
|
||
impl<T> Drop for Vector<T> | ||
where | ||
T: BorshSerialize, | ||
{ | ||
fn drop(&mut self) { | ||
self.flush() | ||
} | ||
} | ||
|
||
impl<'a, T> IntoIterator for &'a Vector<T> | ||
where | ||
T: BorshSerialize + BorshDeserialize, | ||
{ | ||
type Item = &'a T; | ||
type IntoIter = Iter<'a, T>; | ||
|
||
fn into_iter(self) -> Self::IntoIter { | ||
self.iter() | ||
} | ||
} | ||
|
||
impl<'a, T> IntoIterator for &'a mut Vector<T> | ||
where | ||
T: BorshSerialize + BorshDeserialize, | ||
{ | ||
type Item = &'a mut T; | ||
type IntoIter = IterMut<'a, T>; | ||
|
||
fn into_iter(self) -> Self::IntoIter { | ||
self.iter_mut() | ||
} | ||
} | ||
|
||
impl<T> Extend<T> for Vector<T> | ||
where | ||
T: BorshSerialize + BorshDeserialize, | ||
{ | ||
fn extend<I>(&mut self, iter: I) | ||
where | ||
I: IntoIterator<Item = T>, | ||
{ | ||
for item in iter { | ||
self.push(item) | ||
} | ||
} | ||
} | ||
|
||
impl<T> core::ops::Index<u32> for Vector<T> | ||
where | ||
T: BorshSerialize + BorshDeserialize, | ||
{ | ||
type Output = T; | ||
|
||
fn index(&self, index: u32) -> &Self::Output { | ||
self.get(index).unwrap_or_else(|| env::panic_str(ERR_INDEX_OUT_OF_BOUNDS)) | ||
} | ||
} | ||
|
||
impl<T> core::ops::IndexMut<u32> for Vector<T> | ||
where | ||
T: BorshSerialize + BorshDeserialize, | ||
{ | ||
fn index_mut(&mut self, index: u32) -> &mut Self::Output { | ||
self.get_mut(index).unwrap_or_else(|| env::panic_str(ERR_INDEX_OUT_OF_BOUNDS)) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,158 @@ | ||
use borsh::{BorshDeserialize, BorshSerialize}; | ||
use core::{iter::FusedIterator, ops::Range}; | ||
|
||
use super::{Vector, ERR_INDEX_OUT_OF_BOUNDS}; | ||
use crate::env; | ||
|
||
/// An iterator over references to each element in the stored vector. | ||
#[derive(Debug)] | ||
pub struct Iter<'a, T> | ||
where | ||
T: BorshSerialize + BorshDeserialize, | ||
{ | ||
/// Underlying vector to iterate through | ||
vec: &'a Vector<T>, | ||
/// Range of indices to iterate. | ||
range: Range<u32>, | ||
} | ||
|
||
impl<'a, T> Iter<'a, T> | ||
where | ||
T: BorshSerialize + BorshDeserialize, | ||
{ | ||
pub(super) fn new(vec: &'a Vector<T>) -> Self { | ||
Self { vec, range: Range { start: 0, end: vec.len() } } | ||
} | ||
|
||
/// Returns number of elements left to iterate. | ||
fn remaining(&self) -> usize { | ||
self.range.len() | ||
} | ||
} | ||
|
||
impl<'a, T> Iterator for Iter<'a, T> | ||
where | ||
T: BorshSerialize + BorshDeserialize, | ||
{ | ||
type Item = &'a T; | ||
|
||
fn next(&mut self) -> Option<Self::Item> { | ||
<Self as Iterator>::nth(self, 0) | ||
} | ||
|
||
fn size_hint(&self) -> (usize, Option<usize>) { | ||
let remaining = self.remaining(); | ||
(remaining, Some(remaining)) | ||
} | ||
|
||
fn count(self) -> usize { | ||
self.remaining() | ||
} | ||
|
||
fn nth(&mut self, n: usize) -> Option<Self::Item> { | ||
let idx = self.range.nth(n)?; | ||
Some(self.vec.get(idx).unwrap_or_else(|| env::panic_str(ERR_INDEX_OUT_OF_BOUNDS))) | ||
} | ||
} | ||
|
||
impl<'a, T> ExactSizeIterator for Iter<'a, T> where T: BorshSerialize + BorshDeserialize {} | ||
impl<'a, T> FusedIterator for Iter<'a, T> where T: BorshSerialize + BorshDeserialize {} | ||
|
||
impl<'a, T> DoubleEndedIterator for Iter<'a, T> | ||
where | ||
T: BorshSerialize + BorshDeserialize, | ||
{ | ||
fn next_back(&mut self) -> Option<Self::Item> { | ||
<Self as DoubleEndedIterator>::nth_back(self, 0) | ||
} | ||
|
||
fn nth_back(&mut self, n: usize) -> Option<Self::Item> { | ||
let idx = self.range.nth_back(n)?; | ||
Some(self.vec.get(idx).unwrap_or_else(|| env::panic_str(ERR_INDEX_OUT_OF_BOUNDS))) | ||
} | ||
} | ||
|
||
/// An iterator over exclusive references to each element of a stored vector. | ||
#[derive(Debug)] | ||
pub struct IterMut<'a, T> | ||
where | ||
T: BorshSerialize + BorshDeserialize, | ||
{ | ||
/// Mutable reference to vector used to iterate through. | ||
vec: &'a mut Vector<T>, | ||
/// Range of indices to iterate. | ||
range: Range<u32>, | ||
} | ||
|
||
impl<'a, T> IterMut<'a, T> | ||
where | ||
T: BorshSerialize + BorshDeserialize, | ||
{ | ||
/// Creates a new iterator for the given storage vector. | ||
pub(crate) fn new(vec: &'a mut Vector<T>) -> Self { | ||
let end = vec.len(); | ||
Self { vec, range: Range { start: 0, end } } | ||
} | ||
|
||
/// Returns the amount of remaining elements to yield by the iterator. | ||
fn remaining(&self) -> usize { | ||
self.range.len() | ||
} | ||
} | ||
|
||
impl<'a, T> IterMut<'a, T> | ||
where | ||
T: BorshSerialize + BorshDeserialize, | ||
{ | ||
fn get_mut<'b>(&'b mut self, at: u32) -> Option<&'a mut T> { | ||
self.vec.get_mut(at).map(|value| { | ||
//* SAFETY: The lifetime can be swapped here because we can assert that the iterator | ||
//* will only give out one mutable reference for every individual item | ||
//* during the iteration, and there is no overlap. This must be checked | ||
//* that no element in this iterator is ever revisited during iteration. | ||
unsafe { &mut *(value as *mut T) } | ||
}) | ||
} | ||
} | ||
|
||
impl<'a, T> Iterator for IterMut<'a, T> | ||
where | ||
T: BorshSerialize + BorshDeserialize, | ||
{ | ||
type Item = &'a mut T; | ||
|
||
fn next(&mut self) -> Option<Self::Item> { | ||
<Self as Iterator>::nth(self, 0) | ||
} | ||
|
||
fn size_hint(&self) -> (usize, Option<usize>) { | ||
let remaining = self.remaining(); | ||
(remaining, Some(remaining)) | ||
} | ||
|
||
fn count(self) -> usize { | ||
self.remaining() | ||
} | ||
|
||
fn nth(&mut self, n: usize) -> Option<Self::Item> { | ||
let idx = self.range.nth(n)?; | ||
Some(self.get_mut(idx).unwrap_or_else(|| env::panic_str(ERR_INDEX_OUT_OF_BOUNDS))) | ||
} | ||
} | ||
|
||
impl<'a, T> ExactSizeIterator for IterMut<'a, T> where T: BorshSerialize + BorshDeserialize {} | ||
impl<'a, T> FusedIterator for IterMut<'a, T> where T: BorshSerialize + BorshDeserialize {} | ||
|
||
impl<'a, T> DoubleEndedIterator for IterMut<'a, T> | ||
where | ||
T: BorshSerialize + BorshDeserialize, | ||
{ | ||
fn next_back(&mut self) -> Option<Self::Item> { | ||
<Self as DoubleEndedIterator>::nth_back(self, 0) | ||
} | ||
|
||
fn nth_back(&mut self, n: usize) -> Option<Self::Item> { | ||
let idx = self.range.nth_back(n)?; | ||
Some(self.get_mut(idx).unwrap_or_else(|| env::panic_str(ERR_INDEX_OUT_OF_BOUNDS))) | ||
} | ||
} |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we want the
Debug
here? Genuinely don't know but saw this innear-sdk/src/collections/vector.rs
and thought I'd mentioned it, seeing if this is a good pattern to follow:#[cfg_attr(not(feature = "expensive-debug"), derive(Debug))]
near-sdk-rs/near-sdk/src/collections/vector.rs
Line 22 in 072b477
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Well, since derived, it would use this pattern for when the feature is enabled. There is nothing in the iterator that would be different here