diff --git a/book/src/SUMMARY.md b/book/src/SUMMARY.md index cd638040..437b7783 100644 --- a/book/src/SUMMARY.md +++ b/book/src/SUMMARY.md @@ -71,14 +71,14 @@ comparison to docs.sui.io - [Concepts](./concepts/README.md) - - [What is a Package](./concepts/packages.md) + - [Package](./concepts/packages.md) - [Manifest](./concepts/manifest.md) - - [Addresses](./concepts/address.md) - - [Module](./concepts/modules.md) - - [Interacting with a Package](./concepts/user-interaction.md) + - [Address](./concepts/address.md) - [Account](./concepts/what-is-an-account.md) - [Transaction](./concepts/what-is-a-transaction.md) - - [Fast Path](./concepts/fast-path.md) + + + - [Syntax Basics](./basic-syntax/README.md) - [Module](./basic-syntax/module.md) - [Comments](./basic-syntax/comments.md) @@ -112,7 +112,7 @@ comparison to docs.sui.io - [Fast Path & Consensus](./object/fast-path-and-consensus.md) - [Using Objects](./storage/README.md) - [Ability: Key](./storage/key-ability.md) - - [UID and ID]() + - [UID and ID](./storage/uid-and-id.md) - [Transfer Restrictions]() - [Ability: Store]() - [Shared State]() @@ -127,7 +127,6 @@ comparison to docs.sui.io - [Dynamic Fields](./programmability/dynamic-fields.md) - [Dynamic Object Fields](./programmability/dynamic-object-fields.md) - [Dynamic Collections](./programmability/dynamic-collections.md) - - [Package Upgrades]() - [Pattern: Witness]() - [One Time Witness](./programmability/one-time-witness.md) - [Publisher Authority](./programmability/publisher.md) @@ -138,18 +137,19 @@ comparison to docs.sui.io - [Pattern: Request]() - [Pattern: Hot Potato]() - [Pattern: Object Capability]() + - [Package Upgrades]() - [Transaction Blocks]() - [Authorization Patterns]() - [Cryptography and Hashing]() - [Randomness]() - - [BCS](./programmability/bcs.md) -- [Patterns (?)]() + - [BCS]() + - [Standards]() - [Balance]() - [Coin]() @@ -165,7 +165,7 @@ comparison to docs.sui.io - [Testing]() - [Debugging]() - [Coding Conventions]() -- [Appendix]() +# Appendix - [A - Glossary](./appendix/glossary.md) - [B - Publications](./appendix/publications.md) - [C - Contributing](./appendix/contributing.md) diff --git a/book/src/basic-syntax/module.md b/book/src/basic-syntax/module.md index c9dcd469..47d437d0 100644 --- a/book/src/basic-syntax/module.md +++ b/book/src/basic-syntax/module.md @@ -24,18 +24,17 @@ Usually, a single file in the `sources/` folder contains a single module. The fi {{#include ../../../packages/samples/sources/basic-syntax/module.move:module}} ``` -Structs, functions and constants, imports and friend declarations are all part of the module: +Structs, functions, constants and imports all part of the module: - [Structs](./struct.md) - [Functions](./function.md) - [Constants](./constants.md) - [Imports](./importing-modules.md) -- [Friend declarations]() -- [Method Aliases](./struct-methods.md) +- [Struct Methods](./struct-methods.md) ## Address / Named address -Module address can be specified as both: an address _literal_ (does not require the `@` prefix) or a named address specified in the [Package Manifest](../concepts/package-manifest.md). In the example below, both are identical because there's a `book = "0x0"` record in the `[addresses]` section of the `Move.toml`. +Module address can be specified as both: an address _literal_ (does not require the `@` prefix) or a named address specified in the [Package Manifest](../concepts/manifest.md). In the example below, both are identical because there's a `book = "0x0"` record in the `[addresses]` section of the `Move.toml`. ```Move {{#include ../../../packages/samples/sources/basic-syntax/module.move:address_literal}} @@ -56,18 +55,3 @@ Module members are declared inside the module body. To illustrate that, let's de ```Move {{#include ../../../packages/samples/sources/basic-syntax/module.move:members}} ``` - -## Address block - -Before the introduction of the `address::module_name` syntax, modules were organized into `address {}` blocks. This way of code organization is still available today, but is not used widely. Modern practices imply having a single module per file, so the `address {}` block is rather a redundant construct. - -> Module addresses can be omitted if modules are organized into `address {}` blocks. - -```Move -{{#include ../../../packages/samples/sources/basic-syntax/module.move:address_block}} -``` - -The modules defined in this code sample will be accessible as: - -- `book::another_module` -- `book::yet_another_module` diff --git a/book/src/before-we-begin/move-2024.md b/book/src/before-we-begin/move-2024.md index a60faacf..6fb7192c 100644 --- a/book/src/before-we-begin/move-2024.md +++ b/book/src/before-we-begin/move-2024.md @@ -1,5 +1,5 @@ # Move 2024 -Move 2024 is the new version of the Move language that is maintained by Mysten Labs. All of the examples in this book are written in Move 2024. If you're used to the pre-2024 version of Move, please, refer to the [Move 2024 Migration Guide](./../guides/2024-migration-guide.md) to learn about the differences between the two versions. +Move 2024 is the new edition of the Move language maintained by Mysten Labs. All of the examples in this book are written in Move 2024. If you're used to the pre-2024 version of Move, please, refer to the [Move 2024 Migration Guide](./../guides/2024-migration-guide.md) to learn about the changes and improvements in the new edition. diff --git a/book/src/concepts/address.md b/book/src/concepts/address.md index 72bfa460..cad61bfb 100644 --- a/book/src/concepts/address.md +++ b/book/src/concepts/address.md @@ -1,4 +1,4 @@ -# Addresses +# Address + ## Transaction Effects Transaction effects are the changes that a transaction makes to the blockchain state. More specifically, a transaction can change the state in the following ways: @@ -33,8 +59,9 @@ Transaction effects are the changes that a transaction makes to the blockchain s The result of the executed transaction consists of different parts: +- Tx Digest - the hash of the transaction which is used to identify the transaction; - Transaction Data - the inputs, commands and gas object used in the transaction; - Transaction Effects - the status and the "effects" of the transaction, more specifically: the status of the transaction, updates to objects and their new versions, the gas object used, the gas cost of the transaction, and the events emitted by the transaction; -- Events - the custom events emitted by the transaction; +- Events - the custom [events](./../programmability/events.md) emitted by the transaction; - Object Changes - the changes made to the objects, including the *change of ownership*; - Balance Changes - the changes made to the aggregate balances of the account involved in the transaction; diff --git a/book/src/programmability/collections.md b/book/src/programmability/collections.md index f59bcb87..27e1e301 100644 --- a/book/src/programmability/collections.md +++ b/book/src/programmability/collections.md @@ -1,17 +1,13 @@ # Collections -Collection types are a fundamental part of any programming language. They are used to store a collection of data, such as a list of items. The `vector` type has already been covered in the [vector section](./../basic-syntax/vector.md), and in this chapter we will cover the collection types offered by the [Sui Framework](./sui-framework.md). - -- [vector](#vector) -- [VecSet](#VecSet) -- [VecMap](#VecMap) +Collection types are a fundamental part of any programming language. They are used to store a collection of data, such as a list of items. The `vector` type has already been covered in the [vector section](./../basic-syntax/vector.md), and in this chapter we will cover the vector-based collection types offered by the [Sui Framework](./sui-framework.md). ## Vector While we have previously covered the `vector` type in the [vector section](./../basic-syntax/vector.md), it is worth going over it again in a new context. This time we will cover the usage of the `vector` type in objects and how it can be used in an application. ```move -// >insert collection vector code here< +{{#include ../../../packages/samples/sources/programmability/collections.move:vector}} ``` ## VecSet @@ -22,6 +18,8 @@ While we have previously covered the `vector` type in the [vector section](./../ {{#include ../../../packages/samples/sources/programmability/collections.move:vec_set}} ``` +VecSet will fail on attempt to insert a an item that already exists in the set. + ## VecMap `VecMap` is a collection type that stores a map of key-value pairs. It is similar to a `VecSet`, but it allows you to associate a value with each item in the set. This makes it useful for storing a collection of key-value pairs, such as a list of addresses and their balances, or a list of user IDs and their associated data. @@ -31,3 +29,18 @@ Keys in a `VecMap` are unique, and each key can only be associated with a single ```move {{#include ../../../packages/samples/sources/programmability/collections.move:vec_map}} ``` + +## Limitations + +Standard collection types are a great way to store typed data with guaranteed safety and consistency. However, they are limited by the type of data they can store - the type system won't allow you to store a wrong type in a collection; and they're limited in size - by the object size limit. They will work for relatively small-sized sets and lists, but for larger collections you may need to use a different approach. + +## Summary + +- Vector is a native type that allows storing a list of items. +- VecSet is built on top of vector and allows storing sets of unique items. +- VecMap is used to store key-value pairs in a map-like structure. +- Vector-based collections are strictly typed and limited by the object size limit and are best suited for small-sized sets and lists. + +## Next Steps + +In the next section we will cover [Dynamic Fields](./dynamic-fields.md) - an important primitive that allows for [Dynamic Collections](./dynamic-collections.md) - a way to store large collections of data in a more flexible, yet more expensive way. diff --git a/book/src/programmability/sui-framework.md b/book/src/programmability/sui-framework.md index 69e73010..93741177 100644 --- a/book/src/programmability/sui-framework.md +++ b/book/src/programmability/sui-framework.md @@ -2,6 +2,10 @@ Sui Framework is a default dependency set in the [Package Manifest](./../concepts/manifest.md). It depends on the [Standard Library](./../basic-syntax/standard-library.md) and provides Sui-specific features, including the interaction with the storage, and Sui-specific native types and modules. +_For convenience, we grouped the modules in the Sui Framework into multiple categories. But they're still part of the same framework._ + +## Core +
@@ -14,11 +18,25 @@ Sui Framework is a default dependency set in the [Package Manifest](./../concept | sui::clock | Defines the `Clock` type and its methods | [Epoch and Time](./epoch-and-time.md) | | sui::dynamic_field | Implements methods to add, use and remove dynamic fields | [Dynamic Fields](./dynamic-fields.md) | | sui::dynamic_object_field | Implements methods to add, use and remove dynamic object fields | [Dynamic Object Fields](./dynamic-object-fields.md) | -| sui::vec_map | Implements a map with vector keys | [Collections](./collections.md) | -| sui::vec_set | Implements a set type | [Collections](./collections.md) | | sui::event | Allows emitting events for off-chain listeners | [Events](./events.md) | | sui::package | Defines the `Publisher` type and package upgrade methods | [Publisher](./publisher.md), [Package Upgrades](./package-upgrades.md) | -| - | - | - | +| sui::display | Implements the `Display` object and ways to create and update it | [Display](./display.md) | + +
+ +## Collections + +
+ +| Module | Description | Chapter | +| ----------------- | ----------------------------------------------------------------- | ----------------------------------------------- | +| sui::vec_set | Implements a set type | [Collections](./collections.md) | +| sui::vec_map | Implements a map with vector keys | [Collections](./collections.md) | +| sui::table | Implements the `Table` type and methods to interact with it | [Dynamic Collections](./dynamic-collections.md) | +| sui::linked_table | Implements the `LinkedTable` type and methods to interact with it | [Dynamic Collections](./dynamic-collections.md) | +| sui::bag | Implements the `Bag` type and methods to interact with it | [Dynamic Collections](./dynamic-collections.md) | +| sui::object_table | Implements the `ObjectTable` type and methods to interact with it | [Dynamic Collections](./dynamic-collections.md) | +| sui::object_bag | Implements the `ObjectBag` type and methods to interact with it | [Dynamic Collections](./dynamic-collections.md) |
@@ -53,45 +71,38 @@ The source code of the Sui Framework is available in the [Sui repository](https: Modules: -+ sui::address -- sui::authenticator -- sui::bag -- sui::balance -- sui::bcs -- sui::borrow -+ sui::clock +Coins: +- sui::pay +- sui::sui - sui::coin +- sui::token +- sui::balance - sui::deny_list + +Commerce: +- sui::kiosk - sui::display -- sui::dynamic_field -- sui::dynamic_object_field -- sui::event +- sui::kiosk_extension +- sui::transfer_policy + + +- sui::bcs - sui::hex -- sui::linked_table - sui::math -- sui::object_bag -- sui::object_table -- sui::object -- sui::package -- sui::pay +- sui::types +- sui::borrow + + +- sui::authenticator + - sui::priority_queue -- sui::prover -- sui::random -- sui::sui - sui::table_vec -- sui::table -- sui::token -- sui::transfer -- sui::tx_context -- sui::types + - sui::url -- sui::vec_map -- sui::vec_set - sui::versioned -- sui::kiosk -- sui::kiosk_extension -- sui::transfer_policy +- sui::prover +- sui::random - sui::bls12381 - sui::ecdsa_k1 diff --git a/book/src/programmability/transaction-blocks.md b/book/src/programmability/transaction-blocks.md deleted file mode 100644 index c07d723a..00000000 --- a/book/src/programmability/transaction-blocks.md +++ /dev/null @@ -1 +0,0 @@ -# Transaction Blocks diff --git a/book/src/programmability/witness-and-abstract-implementation.md b/book/src/programmability/witness-and-abstract-implementation.md deleted file mode 100644 index 5a18b55e..00000000 --- a/book/src/programmability/witness-and-abstract-implementation.md +++ /dev/null @@ -1,41 +0,0 @@ -# Abstract Class - - - -Some of the language features combined together can create patterns that are similar to other programming languages. The simplest example would be "getters and setters" - functions that get and set the value of a field. This pattern is possible, because struct fields are private by default, and can only be accessed through functions. - -However, there are more advanced patterns, such as the abstract class. An abstract class is a class that cannot be instantiated, but can be inherited from. While Move does not have inheritance, it has generic structs, which can be instantiated with different types. This allows us to create a generic struct that can be used as an abstract class. Combined with a set of Witness-gated functions, this allows us to create a generic struct with a generic implementation. - -Some of the methods in this approach will be shared and available to all implementations, while others will be abstract and will need to be implemented by the concrete implementations. - -## Generic Struct - - - -## Common methods - - - -## Witness-gated Functions - - - -## Differences from OOP - -While this approach imitates the abstract class pattern well, it is not the same as the abstract class in OOP. The main difference is that the abstract class in OOP and its implementors have different type. In Move, the base type stays the same, and the implementors set a generic type parameter. Another notable difference is that due to lack of dynamic dispatch and interfaces, the implemented methods are not available through the base type and can even be missing. - -## Usage in Sui Framework - -The Sui Framework uses this pattern to implement the `Coin` type and the underlying `Balance`. Its variation is also used in the Closed Loop Token implementation, however, the latter is a bit more complex, because it uses the Request pattern to dynamically implement the interface. diff --git a/book/src/storage/README.md b/book/src/storage/README.md index acf1b769..46a65968 100644 --- a/book/src/storage/README.md +++ b/book/src/storage/README.md @@ -1 +1,4 @@ # Using Objects + +In the [Object Model](./../object) chapter we briefly explained the evolution of the Move language from an account-based model to an object-based model. In this chapter, we will dive deeper into the object model and explore how to use objects in your Sui applications. If you haven't read the [Object Model](./../object) chapter yet, we recommend you do so before continuing with this chapter. + diff --git a/book/src/storage/_README.md b/book/src/storage/_README.md index e4de99f8..299e6fcc 100644 --- a/book/src/storage/_README.md +++ b/book/src/storage/_README.md @@ -36,66 +36,32 @@ public fun new_object(ctx: &mut TxContext): Object { } ``` -# UID type - -The `UID` type is defined in the `sui::object` module and is a wrapper around an `ID` which, in turn, wraps the `address` type. The UIDs on Sui are guaranteed to be unique, and can't be reused. - -Fresh UID generation: - -- UID is derived from the `tx_hash` and an `index` which is incremented for each new UID. -- The `derive_id` function is implemented in the `sui::tx_context` module, and that is why TxContext is required for UID generation. -- Sui Verifier will not allow using a UID that wasn't created in the same function. That prevents UIDs from being pre-generated and reused after the object was unpacked. -New UID is created with the `object::new(ctx)` function. It takes a mutable reference to TxContext, and returns a new UID. -```move -let ctx = &mut tx_context::dummy(); -let uid = object::new(ctx); -``` - -On Sui, `UID` acts as a representation of an object, and allows defining behavious and features of an object. One of the key-features - [Dynamic Fields]() - is possible because of the `UID` type being explicit. Additionally, it allows the [Transfer To Object (TTO)]() which we will explain later in this chapter. - -## UID lifecycle - -The `UID` type is created with the `object::new(ctx)` function, and it is destroyed with the `object::delete(uid)` function. The `object::delete` consumes the UID _by value_, and it is impossible to delete it unless the value was unpacked from an Object. + -## fresh_object_address +# UID type -TxContext provides the `fresh_object_address` function which can be utilized to create unique addresses and `ID`s - it may be useful in some application that assign unique identifiers to user actions - for example, an order_id in a marketplace. +The `UID` type is defined in the `sui::object` module and is a wrapper around an `ID` which, in turn, wraps the `address` type. The UIDs on Sui are guaranteed to be unique, and can't be reused. -# Storage Model +Fresh UID generation: -Now that we introduced the `key` ability and the `UID` type, we can finally talk about storage in Sui. +- UID is derived from the `tx_hash` and an `index` which is incremented for each new UID. diff --git a/book/src/storage/key-ability.md b/book/src/storage/key-ability.md index b1211bdd..8ba36230 100644 --- a/book/src/storage/key-ability.md +++ b/book/src/storage/key-ability.md @@ -1,26 +1,38 @@ # The Key Ability -For the [Object Model](./../concepts/object-model.md) to work, the object has to have a formal definition. And for that Move offers the `key` ability. +In the [Basic Syntax](./../basic-syntax) chapter we already covered two out of four abilities - [Drop](./drop-ability.md) and [Copy](./copy-ability.md). They affect the behaviour of the value in a scope and are not directly related to storage. It is time to cover the `key` ability, which allows the struct to be stored. + +Historically, the `key` ability was created to mark the type as a *key in the storage*. A type with the `key` ability could be stored at top-level in the storage, and could be *directly owned* by an account or address. With the introduction of the [Object Model](./../object), the `key` ability naturally became the defining ability for the object. + + + +## Object Definition + +A struct with the `key` ability is considered an object and can be used in the storage functions. The Sui Verifier will require the first field of the struct to be named `id` and have the type `UID`. ```move -/// public struct Object has key { - id: UID + id: UID, // required + name: String, } -``` - -## UID type -... +/// Creates a new Object with a Unique ID +public fun new(name: String, ctx: &mut TxContext): Object { + Object { + id: object::new(ctx), // creates a new UID + name, + } +} +``` -## Creating an Object +A struct with the `key` ability is still a struct, and can have any number of fields and associated functions. There is no special handling or syntax for packing, accessing or unpacking the struct. -... +However, because the first field of an object struct must be of type `UID` - a non-copyable and non-droppable type, the struct transitively cannot have `drop` and `copy` abilities. Thus, the object is non-discardable by design. -## Deleting an Object +## Asset Definition -## UID freshness requirement +In the context of the [Object Model](./../object/digital-assets.md), an object with the `key` ability can be considered an asset. It is non-discardable, unique, and can be *owned*. -Sui Verifier will not allow using a UID that wasn't generated in the same function. In other words - reusing UID or passing it from another function won't work. +## Next Steps -## +In the next chapter, we will cover the [UID](./uid-and-id.md) - the most important type in the Sui storage model. diff --git a/book/src/storage/shared-state.md b/book/src/storage/shared-state.md deleted file mode 100644 index ae62d068..00000000 --- a/book/src/storage/shared-state.md +++ /dev/null @@ -1 +0,0 @@ -# Shared State diff --git a/book/src/storage/store-ability.md b/book/src/storage/store-ability.md deleted file mode 100644 index 2a5eda70..00000000 --- a/book/src/storage/store-ability.md +++ /dev/null @@ -1 +0,0 @@ -# Ability: Store diff --git a/book/src/storage/transfer-restrictions.md b/book/src/storage/transfer-restrictions.md deleted file mode 100644 index 7a2f5130..00000000 --- a/book/src/storage/transfer-restrictions.md +++ /dev/null @@ -1 +0,0 @@ -# Transfer Restrictions diff --git a/book/src/storage/transfer-to-object.md b/book/src/storage/transfer-to-object.md deleted file mode 100644 index 40f3dd87..00000000 --- a/book/src/storage/transfer-to-object.md +++ /dev/null @@ -1 +0,0 @@ -# Transfer to Object? diff --git a/book/src/storage/uid-and-id.md b/book/src/storage/uid-and-id.md new file mode 100644 index 00000000..4a0e51b4 --- /dev/null +++ b/book/src/storage/uid-and-id.md @@ -0,0 +1,61 @@ +# UID and ID + +The `UID` type is defined in the `sui::object` module and is a wrapper around an `ID` which, in turn, wraps the `address` type. The UIDs on Sui are guaranteed to be unique, and can't be reused. + + + +## Fresh UID generation: + +- UID is derived from the `tx_hash` and an `index` which is incremented for each new UID. +- The `derive_id` function is implemented in the `sui::tx_context` module, and that is why TxContext is required for UID generation. +- Sui Verifier will not allow using a UID that wasn't created in the same function. That prevents UIDs from being pre-generated and reused after the object was unpacked. + +New UID is created with the `object::new(ctx)` function. It takes a mutable reference to TxContext, and returns a new UID. + +```move +let ctx = &mut tx_context::dummy(); +let uid = object::new(ctx); +``` + +On Sui, `UID` acts as a representation of an object, and allows defining behavious and features of an object. One of the key-features - [Dynamic Fields]() - is possible because of the `UID` type being explicit. Additionally, it allows the [Transfer To Object (TTO)]() which we will explain later in this chapter. + +## UID lifecycle + +The `UID` type is created with the `object::new(ctx)` function, and it is destroyed with the `object::delete(uid)` function. The `object::delete` consumes the UID _by value_, and it is impossible to delete it unless the value was unpacked from an Object. + +```move +let ctx = &mut tx_context::dummy(); + +let char = Character { + id: object::new(ctx) +}; + +let Character { id } = char; +id.delete(); +``` + +## Keeping the UID + +The `UID` does not need to be deleted immediately after the object struct is unpacked. Sometimes it may carry [Dynamic Fields](./../programmability/dynamic-fields.md) or objects transferred to it via [Transfer To Object](./transfer-to-object.md). In such cases, the UID may be kept and stored in a separate object. + +## Proof of Deletion + +The ability to return the UID of an object may be utilized in pattern called _proof of deletion_. It is a rarely used technique, but it may be useful in some cases, for example, the creator or an application may incentivize the deletion of an object by exchanging the deleted IDs for some reward. + +In framework development this method could be used ignore / bypass certain restrictions on "taking" the object. If there's a container that enforces certain logic on transfers, like Kiosk does, there could be a special scenario of skipping the checks by providing a proof of deletion. + +This is one of the open topics for exploration and research, and it may be used in various ways. + +## ID + +When talking about `UID`s we should also mention the `ID` type. It is a wrapper around the `address` type, and is used to represent an address-pointer. Usually, `ID` is used to point at an object, however, there's no restriction, and no guarantee that the `ID` points to an existing object. + +> ID can be received as a transaction argument in a [Transaction Block](). Alternatively, ID can be created from an `address` value using `to_id()` function. + +```move + +``` + +## fresh_object_address + +TxContext provides the `fresh_object_address` function which can be utilized to create unique addresses and `ID`s - it may be useful in some application that assign unique identifiers to user actions - for example, an order_id in a marketplace. diff --git a/book/src/storage/what-is-an-object.md b/book/src/storage/what-is-an-object.md deleted file mode 100644 index f32aea57..00000000 --- a/book/src/storage/what-is-an-object.md +++ /dev/null @@ -1 +0,0 @@ -# What is an Object diff --git a/packages/samples/sources/basic-syntax/module.move b/packages/samples/sources/basic-syntax/module.move index 7a87a972..40d6506b 100644 --- a/packages/samples/sources/basic-syntax/module.move +++ b/packages/samples/sources/basic-syntax/module.move @@ -8,9 +8,8 @@ module book::my_module { // ANCHOR_END: module // ANCHOR: address_literal -module 0x0::address_literal_example { - // module body -} +module 0x0::address_literal { /* ... */ } +module book::named_address { /* ... */ } // ANCHOR_END: address_literal #[allow(unused_function, unused_const, unused_use)] diff --git a/packages/samples/sources/programmability/collections.move b/packages/samples/sources/programmability/collections.move index 2e21e318..d327b8a6 100644 --- a/packages/samples/sources/programmability/collections.move +++ b/packages/samples/sources/programmability/collections.move @@ -1,6 +1,25 @@ // Copyright (c) Mysten Labs, Inc. // SPDX-License-Identifier: Apache-2.0 +#[allow(unused_variable, unused_field)] +// ANCHOR: vector +module book::collections_vector { + /// The Book that can be sold by a `BookStore` + struct Book has key, store { + id: UID, + name: String + } + + /// The BookStore that sells `Book`s + public struct BookStore has key, store { + id: UID, + books: vector + } + + #[test] + +} + #[allow(unused_variable, unused_field)] // ANCHOR: vec_set module book::collections_vec_set {