0x1::Collection2
Provide a account based vector for save resource item. The resource in CollectionStore can borrowed by anyone, anyone can get immutable ref of item. and the owner of Collection can allow others to add item to Collection or get mut ref from Collection.git
Collection
CollectionStore
length
borrow
push_back
borrow_mut
pop_back
remove
append
append_all
exists_at
is_accept
accept
put
put_all
take
create_collection
length_of
borrow_collection
return_collection
destroy_collection
destroy_empty
use 0x1::Errors;
use 0x1::Option;
use 0x1::Signer;
use 0x1::Vector;
Collection
Collection in memory, can not drop & store.
struct Collection<T>
items: vector<T>
owner: address
can_put: bool
can_mut: bool
can_take: bool
CollectionStore
Collection in global store.
struct CollectionStore<T: store> has key
items: Option::Option<vector<T>>
anyone_can_put: bool
anyone_can_mut: bool
The operator require the collection owner or collection set anyone_can_put to true.
const ERR_COLLECTION_CAN_NOT_ADD: u64 = 102;
The operator require the collection owner or collection set anyone_can_mut to true.
const ERR_COLLECTION_CAN_NOT_MUT: u64 = 103;
The operator require the collection owner
const ERR_COLLECTION_CAN_NOT_TAKE: u64 = 104;
const ERR_COLLECTION_INVALID_BORROW_STATE: u64 = 105;
const ERR_COLLECTION_IS_NOT_EMPTY: u64 = 106;
const ERR_COLLECTION_NOT_EXIST: u64 = 101;
length
Return the length of the collection.
public fun length<T>(c: &Collection2::Collection<T>): u64
public fun length<T>(c: &Collection<T>): u64{
Vector::length(&c.items)
}
aborts_if false;
borrow
Acquire an immutable reference to the i
th element of the collection c
.
Aborts if i
is out of bounds.
public fun borrow<T>(c: &Collection2::Collection<T>, i: u64): &T
public fun borrow<T>(c: &Collection<T>, i: u64): &T{
Vector::borrow(&c.items, i)
}
push_back
Add item v
to the end of the collection c
.
require owner of Collection.
public fun push_back<T>(c: &mut Collection2::Collection<T>, t: T)
public fun push_back<T>(c: &mut Collection<T>, t: T){
assert!(c.can_put, Errors::requires_address(ERR_COLLECTION_CAN_NOT_ADD));
Vector::push_back<T>(&mut c.items, t);
}
borrow_mut
Return a mutable reference to the i
th item in the Collection c
.
Aborts if i
is out of bounds.
public fun borrow_mut<T>(c: &mut Collection2::Collection<T>, i: u64): &mut T
public fun borrow_mut<T>(c: &mut Collection<T>, i: u64): &mut T{
assert!(c.can_mut, Errors::requires_address(ERR_COLLECTION_CAN_NOT_MUT));
Vector::borrow_mut<T>(&mut c.items, i)
}
pop_back
Pop an element from the end of vector v
.
Aborts if v
is empty.
public fun pop_back<T>(c: &mut Collection2::Collection<T>): T
public fun pop_back<T>(c: &mut Collection<T>): T {
assert!(c.can_take, Errors::requires_address(ERR_COLLECTION_CAN_NOT_TAKE));
Vector::pop_back<T>(&mut c.items)
}
remove
public fun remove<T>(c: &mut Collection2::Collection<T>, i: u64): T
public fun remove<T>(c: &mut Collection<T>, i: u64): T{
assert!(c.can_take, Errors::requires_address(ERR_COLLECTION_CAN_NOT_TAKE));
Vector::remove<T>(&mut c.items, i)
}
append
public fun append<T>(c: &mut Collection2::Collection<T>, other: T)
public fun append<T>(c: &mut Collection<T>, other: T) {
assert!(c.can_put, Errors::requires_address(ERR_COLLECTION_CAN_NOT_ADD));
Vector::append<T>(&mut c.items, Vector::singleton(other))
}
append_all
public fun append_all<T>(c: &mut Collection2::Collection<T>, other: vector<T>)
public fun append_all<T>(c: &mut Collection<T>, other: vector<T>) {
assert!(c.can_put, Errors::requires_address(ERR_COLLECTION_CAN_NOT_ADD));
Vector::append<T>(&mut c.items, other)
}
exists_at
check the Collection exists in addr
public fun exists_at<T: store>(addr: address): bool
public fun exists_at<T: store>(addr: address): bool{
exists<CollectionStore<T>>(addr)
}
aborts_if false;
is_accept
check addr
is accept T and other can send T to addr
,
it means exists a Collection of T at addr
and anyone_can_put of the Collection is true
public fun is_accept<T: store>(addr: address): bool
public fun is_accept<T: store>(addr: address): bool acquires CollectionStore {
if (!exists<CollectionStore<T>>(addr)){
return false
};
let cs = borrow_global<CollectionStore<T>>(addr);
cs.anyone_can_put
}
accept
signer allow other send T to self create a Collection of T and set anyone_can_put to true if the Collection exists, just update anyone_can_put to true
public fun accept<T: store>(signer: &signer)
public fun accept<T: store>(signer: &signer) acquires CollectionStore {
let addr = Signer::address_of(signer);
if (!exists<CollectionStore<T>>(addr)){
Self::create_collection<T>(signer, true, false);
};
let cs = borrow_global_mut<CollectionStore<T>>(addr);
if (!cs.anyone_can_put) {
cs.anyone_can_put = true;
}
}
put
Put items to to_addr
’s Collection of T
put = borrow_collection
public fun put<T: store>(signer: &signer, owner: address, item: T)
public fun put<T: store>(signer: &signer, owner: address, item: T) acquires CollectionStore{
let c = Self::borrow_collection(signer, owner);
Self::append(&mut c, item);
Self::return_collection(c);
}
aborts_if false;
put_all
Put all items to owner’s collection of T.
public fun put_all<T: store>(signer: &signer, owner: address, items: vector<T>)
public fun put_all<T: store>(signer: &signer, owner: address, items: vector<T>) acquires CollectionStore{
let c = Self::borrow_collection(signer, owner);
Self::append_all(&mut c, items);
Self::return_collection(c);
}
aborts_if false;
take
Take last item from signer’s Collection of T.
public fun take<T: store>(signer: &signer): T
public fun take<T: store>(signer: &signer): T acquires CollectionStore{
let addr = Signer::address_of(signer);
let c = borrow_collection<T>(signer, addr);
let item = pop_back(&mut c);
return_collection(c);
item
}
aborts_if false;
create_collection
public fun create_collection<T: store>(signer: &signer, anyone_can_put: bool, anyone_can_mut: bool)
public fun create_collection<T:store>(signer: &signer, anyone_can_put: bool, anyone_can_mut: bool) {
move_to(signer, CollectionStore<T>{items: Option::some(Vector::empty<T>()), anyone_can_put, anyone_can_mut})
}
length_of
Return the length of Collectionowner
, if collection do not exist, return 0.
public fun length_of<T: store>(owner: address): u64
public fun length_of<T: store>(owner: address) : u64 acquires CollectionStore{
if (exists_at<T>(owner)){
let cs = borrow_global_mut<CollectionStore<T>>(owner);
//if items is None, indicate it is borrowed
assert!(!Option::is_none(&cs.items), Errors::invalid_state(ERR_COLLECTION_INVALID_BORROW_STATE));
let items = Option::borrow(&cs.items);
Vector::length(items)
}else{
0
}
}
borrow_collection
Borrow collection of T from owner , auto detected the collection’s can_put |
can_mut | can_take by the sender and Collection config. |
public fun borrow_collection<T: store>(sender: &signer, owner: address): Collection2::Collection<T>
public fun borrow_collection<T: store>(sender: &signer, owner: address): Collection<T> acquires CollectionStore{
assert!(exists_at<T>(owner), Errors::invalid_state(ERR_COLLECTION_NOT_EXIST));
let cs = borrow_global_mut<CollectionStore<T>>(owner);
//if items is None, indicate it is borrowed
assert!(!Option::is_none(&cs.items), Errors::invalid_state(ERR_COLLECTION_INVALID_BORROW_STATE));
let items = Option::extract(&mut cs.items);
let is_owner = owner == Signer::address_of(sender);
let can_put = cs.anyone_can_put || is_owner;
let can_mut = cs.anyone_can_mut || is_owner;
let can_take = is_owner;
Collection{
items,
owner,
can_put,
can_mut,
can_take,
}
}
aborts_if false;
return_collection
Return the Collection of T
public fun return_collection<T: store>(c: Collection2::Collection<T>)
public fun return_collection<T: store>(c: Collection<T>) acquires CollectionStore{
let Collection{ items, owner, can_put:_, can_mut:_, can_take:_ } = c;
let cs = borrow_global_mut<CollectionStore<T>>(owner);
assert!(Option::is_none(&cs.items), Errors::invalid_state(ERR_COLLECTION_INVALID_BORROW_STATE));
Option::fill(&mut cs.items, items);
}
aborts_if false;
destroy_collection
public fun destroy_collection<T: store>(signer: &signer)
public fun destroy_collection<T: store>(signer: &signer) acquires CollectionStore{
let c = move_from<CollectionStore<T>>(Signer::address_of(signer));
destroy_empty(c);
}
aborts_if false;
destroy_empty
fun destroy_empty<T: store>(c: Collection2::CollectionStore<T>)
fun destroy_empty<T: store>(c: CollectionStore<T>){
let CollectionStore{ items, anyone_can_put:_, anyone_can_mut:_,} = c;
if (Option::is_some(&items)) {
let item_vec = Option::extract(&mut items);
assert!(Vector::is_empty(&item_vec), Errors::invalid_state(ERR_COLLECTION_IS_NOT_EMPTY));
Vector::destroy_empty(item_vec);
Option::destroy_none(items);
}else{
Option::destroy_none(items);
}
}
aborts_if false;
pragma verify = false;
pragma aborts_if_is_strict = false;