From db007fdaa1ef11382227732e06cf6fdc021db9d9 Mon Sep 17 00:00:00 2001 From: Damir Shamanaev Date: Mon, 21 Oct 2024 18:04:07 +0300 Subject: [PATCH 1/2] adds module label everywhere --- packages/hello_world/sources/hello_world.move | 14 +- .../hello_world/tests/hello_world_tests.move | 12 +- .../samples/sources/move-basics/address.move | 6 +- .../sources/move-basics/assert-and-abort.move | 3 +- .../sources/move-basics/comments-block.move | 20 ++ .../sources/move-basics/comments-doc.move | 21 ++ .../sources/move-basics/comments-line.move | 15 + .../samples/sources/move-basics/comments.move | 62 ---- .../sources/move-basics/constants-config.move | 17 ++ .../sources/move-basics/constants-naming.move | 13 + .../move-basics/constants-shop-price.move | 25 ++ .../sources/move-basics/constants.move | 67 +---- .../sources/move-basics/control-flow.move | 270 +++++++++--------- .../sources/move-basics/copy-ability.move | 3 +- .../sources/move-basics/drop-ability.move | 33 ++- .../samples/sources/move-basics/function.move | 46 +-- .../sources/move-basics/function_use.move | 14 + .../samples/sources/move-basics/generics.move | 21 +- .../move-basics/importing-module-members.move | 15 + ...importing-modules-conflict-resolution.move | 15 + .../importing-modules-external.move | 10 + .../importing-modules-grouped.move | 16 ++ .../move-basics/importing-modules-self.move | 15 + .../move-basics/importing-modules-two.move | 14 + .../move-basics/importing-modules.move | 85 +----- .../sources/move-basics/module-label.move | 9 + .../sources/move-basics/module-members.move | 22 ++ .../samples/sources/move-basics/module.move | 14 +- .../samples/sources/move-basics/option.move | 40 ++- .../sources/move-basics/references.move | 113 ++++---- .../sources/move-basics/string-custom.move | 2 + .../samples/sources/move-basics/string.move | 56 ++-- .../sources/move-basics/struct-methods-2.move | 44 +++ .../sources/move-basics/struct-methods-3.move | 28 ++ .../sources/move-basics/struct-methods.move | 118 ++------ .../samples/sources/move-basics/struct.move | 8 +- .../sources/move-basics/type-reflection.move | 44 +-- .../samples/sources/move-basics/vector.move | 24 +- .../sources/programmability/capability-2.move | 19 ++ .../sources/programmability/capability-3.move | 21 ++ .../sources/programmability/capability-4.move | 17 ++ .../sources/programmability/capability.move | 111 ++----- .../programmability/collections-2.move | 29 ++ .../programmability/collections-3.move | 28 ++ .../programmability/collections-4.move | 22 ++ .../sources/programmability/collections.move | 94 +----- .../sources/programmability/display.move | 114 ++++---- .../programmability/dynamic-fields.move | 114 ++++---- .../dynamic-object-fields.move | 66 ++--- .../sources/programmability/events.move | 46 +-- .../programmability/module-initializer-2.move | 18 ++ .../programmability/module-initializer.move | 57 ++-- .../programmability/one-time-witness.move | 18 +- .../sources/programmability/publisher.move | 46 ++- .../programmability/transaction-context.move | 4 +- .../programmability/witness-pattern.move | 6 +- packages/todo_list/sources/todo_list.move | 78 ++--- 57 files changed, 1127 insertions(+), 1135 deletions(-) create mode 100644 packages/samples/sources/move-basics/comments-block.move create mode 100644 packages/samples/sources/move-basics/comments-doc.move create mode 100644 packages/samples/sources/move-basics/comments-line.move delete mode 100644 packages/samples/sources/move-basics/comments.move create mode 100644 packages/samples/sources/move-basics/constants-config.move create mode 100644 packages/samples/sources/move-basics/constants-naming.move create mode 100644 packages/samples/sources/move-basics/constants-shop-price.move create mode 100644 packages/samples/sources/move-basics/function_use.move create mode 100644 packages/samples/sources/move-basics/importing-module-members.move create mode 100644 packages/samples/sources/move-basics/importing-modules-conflict-resolution.move create mode 100644 packages/samples/sources/move-basics/importing-modules-external.move create mode 100644 packages/samples/sources/move-basics/importing-modules-grouped.move create mode 100644 packages/samples/sources/move-basics/importing-modules-self.move create mode 100644 packages/samples/sources/move-basics/importing-modules-two.move create mode 100644 packages/samples/sources/move-basics/module-label.move create mode 100644 packages/samples/sources/move-basics/module-members.move create mode 100644 packages/samples/sources/move-basics/string-custom.move create mode 100644 packages/samples/sources/move-basics/struct-methods-2.move create mode 100644 packages/samples/sources/move-basics/struct-methods-3.move create mode 100644 packages/samples/sources/programmability/capability-2.move create mode 100644 packages/samples/sources/programmability/capability-3.move create mode 100644 packages/samples/sources/programmability/capability-4.move create mode 100644 packages/samples/sources/programmability/collections-2.move create mode 100644 packages/samples/sources/programmability/collections-3.move create mode 100644 packages/samples/sources/programmability/collections-4.move create mode 100644 packages/samples/sources/programmability/module-initializer-2.move diff --git a/packages/hello_world/sources/hello_world.move b/packages/hello_world/sources/hello_world.move index a3e3fb05..2bbbee7d 100644 --- a/packages/hello_world/sources/hello_world.move +++ b/packages/hello_world/sources/hello_world.move @@ -1,11 +1,11 @@ /// The module `hello_world` under named address `hello_world`. /// The named address is set in the `Move.toml`. -module hello_world::hello_world { - // Imports the `String` type from the Standard Library - use std::string::String; +module hello_world::hello_world; - /// Returns the "Hello World!" as a `String`. - public fun hello_world(): String { - b"Hello, World!".to_string() - } +// Imports the `String` type from the Standard Library +use std::string::String; + +/// Returns the "Hello World!" as a `String`. +public fun hello_world(): String { + b"Hello, World!".to_string() } diff --git a/packages/hello_world/tests/hello_world_tests.move b/packages/hello_world/tests/hello_world_tests.move index 4285814a..582c5b06 100644 --- a/packages/hello_world/tests/hello_world_tests.move +++ b/packages/hello_world/tests/hello_world_tests.move @@ -1,9 +1,9 @@ #[test_only] -module hello_world::hello_world_tests { - use hello_world::hello_world; +module hello_world::hello_world_tests; - #[test] - fun test_hello_world() { - assert!(hello_world::hello_world() == b"Hello, World!".to_string(), 0); - } +use hello_world::hello_world; + +#[test] +fun test_hello_world() { + assert!(hello_world::hello_world() == b"Hello, World!".to_string(), 0); } diff --git a/packages/samples/sources/move-basics/address.move b/packages/samples/sources/move-basics/address.move index 16212e12..4a65781d 100644 --- a/packages/samples/sources/move-basics/address.move +++ b/packages/samples/sources/move-basics/address.move @@ -2,7 +2,7 @@ // SPDX-License-Identifier: Apache-2.0 #[allow(unused_variable)] -module book::address { +module book::address; #[test] fun address_literal() { @@ -24,7 +24,6 @@ use sui::address; let addr_as_u256: u256 = address::to_u256(@0x1); let addr = address::from_u256(addr_as_u256); // ANCHOR_END: to_u256 - } #[test] fun address_string() { @@ -35,7 +34,6 @@ use std::string::String; let addr_as_string: String = address::to_string(@0x1); // ANCHOR_END: to_string - } #[test] fun address_bytes() { @@ -46,6 +44,4 @@ use sui::address; let addr_as_u8: vector = address::to_bytes(@0x1); let addr = address::from_bytes(addr_as_u8); // ANCHOR_END: to_bytes - -} } diff --git a/packages/samples/sources/move-basics/assert-and-abort.move b/packages/samples/sources/move-basics/assert-and-abort.move index a388bb7d..885e51f8 100644 --- a/packages/samples/sources/move-basics/assert-and-abort.move +++ b/packages/samples/sources/move-basics/assert-and-abort.move @@ -1,7 +1,7 @@ // Copyright (c) Mysten Labs, Inc. // SPDX-License-Identifier: Apache-2.0 -module book::assert_abort { +module book::assert_abort; #[test, expected_failure(abort_code = 1, location=Self)] fun test_abort() { @@ -50,4 +50,3 @@ public fun update_record(/* ... , */ user_has_access: bool, field_exists: bool) /* ... */ } // ANCHOR_END: error_const -} diff --git a/packages/samples/sources/move-basics/comments-block.move b/packages/samples/sources/move-basics/comments-block.move new file mode 100644 index 00000000..b5a658f8 --- /dev/null +++ b/packages/samples/sources/move-basics/comments-block.move @@ -0,0 +1,20 @@ +// Copyright (c) Mysten Labs, Inc. +// SPDX-License-Identifier: Apache-2.0 + +#[allow(unused_function)] +// ANCHOR: main +module book::comments_block; + +fun /* you can comment everywhere */ go_wild() { + /* here + there + everywhere */ let a = 10; + let b = /* even here */ 10; /* and again */ + a + b; +} +/* you can use it to remove certain expressions or definitions +fun empty_commented_out() { + +} +*/ +// ANCHOR_END: main diff --git a/packages/samples/sources/move-basics/comments-doc.move b/packages/samples/sources/move-basics/comments-doc.move new file mode 100644 index 00000000..b97d08bd --- /dev/null +++ b/packages/samples/sources/move-basics/comments-doc.move @@ -0,0 +1,21 @@ +// Copyright (c) Mysten Labs, Inc. +// SPDX-License-Identifier: Apache-2.0 + +#[allow(unused_function, unused_const, unused_variable, unused_field)] +// ANCHOR: main +/// Module has documentation! +module book::comments_doc; + +/// This is a 0x0 address constant! +const AN_ADDRESS: address = @0x0; + +/// This is a struct! +public struct AStruct { + /// This is a field of a struct! + a_field: u8, +} + +/// This function does something! +/// And it's documented! +fun do_something() {} +// ANCHOR_END: main diff --git a/packages/samples/sources/move-basics/comments-line.move b/packages/samples/sources/move-basics/comments-line.move new file mode 100644 index 00000000..8a2a4d9b --- /dev/null +++ b/packages/samples/sources/move-basics/comments-line.move @@ -0,0 +1,15 @@ +// Copyright (c) Mysten Labs, Inc. +// SPDX-License-Identifier: Apache-2.0 + +#[allow(unused_function, unused_variable)] +// ANCHOR: main +module book::comments_line; + +// let's add a note to everything! +fun some_function_with_numbers() { + let a = 10; + // let b = 10 this line is commented and won't be executed + let b = 5; // here comment is placed after code + a + b; // result is 15, not 10! +} +// ANCHOR_END: main diff --git a/packages/samples/sources/move-basics/comments.move b/packages/samples/sources/move-basics/comments.move deleted file mode 100644 index 8675fa4b..00000000 --- a/packages/samples/sources/move-basics/comments.move +++ /dev/null @@ -1,62 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -#[allow(unused_function)] -// ANCHOR: block -module book::comments_block { - fun /* you can comment everywhere */ go_wild() { - /* here - there - everywhere */ let a = 10; - let b = /* even here */ 10; /* and again */ - a + b; - } - /* you can use it to remove certain expressions or definitions - fun empty_commented_out() { - - } - */ -} -// ANCHOR_END: block - -#[allow(unused_function, unused_const, unused_variable, unused_field)] -// ANCHOR: doc -/// Module has documentation! -module book::comments_doc { - - /// This is a 0x0 address constant! - const AN_ADDRESS: address = @0x0; - - /// This is a struct! - public struct AStruct { - /// This is a field of a struct! - a_field: u8, - } - - /// This function does something! - /// And it's documented! - fun do_something() {} -} -// ANCHOR_END: doc - -#[allow(unused_function, unused_variable)] -// ANCHOR: line_2 -module book::comments_line_2 { - // let's add a note to everything! - fun some_function_with_numbers() { - let a = 10; - // let b = 10 this line is commented and won't be executed - let b = 5; // here comment is placed after code - a + b; // result is 15, not 10! - } -} -// ANCHOR_END: line_2 - -#[allow(unused_function)] -// ANCHOR: line -module book::comments_line { - fun some_function() { - // this is a comment line - } -} -// ANCHOR_END: line diff --git a/packages/samples/sources/move-basics/constants-config.move b/packages/samples/sources/move-basics/constants-config.move new file mode 100644 index 00000000..f6bfbab9 --- /dev/null +++ b/packages/samples/sources/move-basics/constants-config.move @@ -0,0 +1,17 @@ +// Copyright (c) Mysten Labs, Inc. +// SPDX-License-Identifier: Apache-2.0 + +// ANCHOR: config +module book::config; + +const ITEM_PRICE: u64 = 100; +const TAX_RATE: u64 = 10; +const SHIPPING_COST: u64 = 5; + +/// Returns the price of an item. +public fun item_price(): u64 { ITEM_PRICE } +/// Returns the tax rate. +public fun tax_rate(): u64 { TAX_RATE } +/// Returns the shipping cost. +public fun shipping_cost(): u64 { SHIPPING_COST } +// ANCHOR_END: config diff --git a/packages/samples/sources/move-basics/constants-naming.move b/packages/samples/sources/move-basics/constants-naming.move new file mode 100644 index 00000000..38a94c9e --- /dev/null +++ b/packages/samples/sources/move-basics/constants-naming.move @@ -0,0 +1,13 @@ +// Copyright (c) Mysten Labs, Inc. +// SPDX-License-Identifier: Apache-2.0 + +#[allow(unused_const)] +module book::naming; + +// ANCHOR: naming +/// Price of the item used at the shop. +const ITEM_PRICE: u64 = 100; + +/// Error constant. +const EItemNotFound: u64 = 1; +// ANCHOR_END: naming diff --git a/packages/samples/sources/move-basics/constants-shop-price.move b/packages/samples/sources/move-basics/constants-shop-price.move new file mode 100644 index 00000000..1092bccb --- /dev/null +++ b/packages/samples/sources/move-basics/constants-shop-price.move @@ -0,0 +1,25 @@ +// Copyright (c) Mysten Labs, Inc. +// SPDX-License-Identifier: Apache-2.0 + +// ANCHOR: shop_price +module book::shop_price; + +use sui::{coin::Coin, sui::SUI}; + +/// The price of an item in the shop. +const ITEM_PRICE: u64 = 100; +/// The owner of the shop, an address. +const SHOP_OWNER: address = @0xa11ce; + +/// An item sold in the shop. +public struct Item {} + +/// Purchase an item from the shop. +public fun purchase(coin: Coin): Item { + assert!(coin.value() == ITEM_PRICE, 0); + + transfer::public_transfer(coin, SHOP_OWNER); + + Item {} +} +// ANCHOR_END: shop_price diff --git a/packages/samples/sources/move-basics/constants.move b/packages/samples/sources/move-basics/constants.move index 3556f72b..36d5300e 100644 --- a/packages/samples/sources/move-basics/constants.move +++ b/packages/samples/sources/move-basics/constants.move @@ -1,67 +1,16 @@ // Copyright (c) Mysten Labs, Inc. // SPDX-License-Identifier: Apache-2.0 -module book::constants { - const MAX: u64 = 100; +module book::constants; - // however you can pass constant outside using a function - public fun max(): u64 { - MAX - } +const MAX: u64 = 100; - // or using - public fun is_max(num: u64): bool { - num == MAX - } +// however you can pass constant outside using a function +public fun max(): u64 { + MAX } -// ANCHOR: shop_price -module book::shop_price { - use sui::coin::Coin; - use sui::sui::SUI; - - /// The price of an item in the shop. - const ITEM_PRICE: u64 = 100; - /// The owner of the shop, an address. - const SHOP_OWNER: address = @0xa11ce; - - /// An item sold in the shop. - public struct Item { /* ... */ } - - /// Purchase an item from the shop. - public fun purchase(coin: Coin): Item { - assert!(coin.value() == ITEM_PRICE, 0); - - transfer::public_transfer(coin, SHOP_OWNER); - - Item { /* ... */ } - } -} -// ANCHOR_END: shop_price -#[allow(unused_const)] -module book::naming { - -// ANCHOR: naming -/// Price of the item used at the shop. -const ITEM_PRICE: u64 = 100; - -/// Error constant. -const EItemNotFound: u64 = 1; -// ANCHOR_END: naming - -} - -// ANCHOR: config -module book::config { - const ITEM_PRICE: u64 = 100; - const TAX_RATE: u64 = 10; - const SHIPPING_COST: u64 = 5; - - /// Returns the price of an item. - public fun item_price(): u64 { ITEM_PRICE } - /// Returns the tax rate. - public fun tax_rate(): u64 { TAX_RATE } - /// Returns the shipping cost. - public fun shipping_cost(): u64 { SHIPPING_COST } +// or using +public fun is_max(num: u64): bool { + num == MAX } -// ANCHOR_END: config diff --git a/packages/samples/sources/move-basics/control-flow.move b/packages/samples/sources/move-basics/control-flow.move index a583a0ee..c34e5e33 100644 --- a/packages/samples/sources/move-basics/control-flow.move +++ b/packages/samples/sources/move-basics/control-flow.move @@ -2,152 +2,150 @@ // SPDX-License-Identifier: Apache-2.0 // ANCHOR: module -module book::control_flow { +module book::control_flow; // ANCHOR_END: module - // ANCHOR: if_condition - #[test] - fun test_if() { - let x = 5; +// ANCHOR: if_condition +#[test] +fun test_if() { + let x = 5; - // `x > 0` is a boolean expression. - if (x > 0) { - std::debug::print(&b"X is bigger than 0".to_string()) - }; - } - // ANCHOR_END: if_condition - // ANCHOR: if_else - #[test] - fun test_if_else() { - let x = 5; - let y = if (x > 0) { - 1 - } else { - 0 - }; - - assert!(y == 1, 0); - } - // ANCHOR_END: if_else - // ANCHOR: while_loop - // This function iterates over the `x` variable until it reaches 10, the - // return value is the number of iterations it took to reach 10. - // - // If `x` is 0, then the function will return 10. - // If `x` is 5, then the function will return 5. - fun while_loop(mut x: u8): u8 { - let mut y = 0; - - // This will loop until `x` is 10. - // And will never run if `x` is 10 or more. - while (x < 10) { - y = y + 1; - x = x + 1; - }; - - y - } - - #[test] - fun test_while() { - assert!(while_loop(0) == 10, 0); // 10 times - assert!(while_loop(5) == 5, 0); // 5 times - assert!(while_loop(10) == 0, 0); // loop never executed - } - // ANCHOR_END: while_loop - // ANCHOR: infinite_while - #[test, expected_failure(out_of_gas, location=Self)] - fun test_infinite_while() { - let mut x = 0; - - // This will loop forever. - while (true) { - x = x + 1; - }; - - // This line will never be executed. - assert!(x == 5, 0); - } - // ANCHOR_END: infinite_while - #[allow(dead_code)] - // ANCHOR: infinite_loop - #[test, expected_failure(out_of_gas, location=Self)] - fun test_infinite_loop() { - let mut x = 0; - - // This will loop forever. - loop { - x = x + 1; - }; + // `x > 0` is a boolean expression. + if (x > 0) { + std::debug::print(&b"X is bigger than 0".to_string()) + }; +} +// ANCHOR_END: if_condition +// ANCHOR: if_else +#[test] +fun test_if_else() { + let x = 5; + let y = if (x > 0) { + 1 + } else { + 0 + }; + + assert!(y == 1, 0); +} +// ANCHOR_END: if_else +// ANCHOR: while_loop +// This function iterates over the `x` variable until it reaches 10, the +// return value is the number of iterations it took to reach 10. +// +// If `x` is 0, then the function will return 10. +// If `x` is 5, then the function will return 5. +fun while_loop(mut x: u8): u8 { + let mut y = 0; + + // This will loop until `x` is 10. + // And will never run if `x` is 10 or more. + while (x < 10) { + y = y + 1; + x = x + 1; + }; + + y +} - // This line will never be executed. - assert!(x == 5, 0); - } - // ANCHOR_END: infinite_loop - // ANCHOR: break_loop - #[test] - fun test_break_loop() { - let mut x = 0; - - // This will loop until `x` is 5. - loop { - x = x + 1; - - // If `x` is 5, then exit the loop. - if (x == 5) { - break // Exit the loop. - } - }; +#[test] +fun test_while() { + assert!(while_loop(0) == 10, 0); // 10 times + assert!(while_loop(5) == 5, 0); // 5 times + assert!(while_loop(10) == 0, 0); // loop never executed +} +// ANCHOR_END: while_loop +// ANCHOR: infinite_while +#[test, expected_failure(out_of_gas, location=Self)] +fun test_infinite_while() { + let mut x = 0; + + // This will loop forever. + while (true) { + x = x + 1; + }; + + // This line will never be executed. + assert!(x == 5, 0); +} +// ANCHOR_END: infinite_while +#[allow(dead_code)] +// ANCHOR: infinite_loop +#[test, expected_failure(out_of_gas, location=Self)] +fun test_infinite_loop() { + let mut x = 0; + + // This will loop forever. + loop { + x = x + 1; + }; + + // This line will never be executed. + assert!(x == 5, 0); +} +// ANCHOR_END: infinite_loop +// ANCHOR: break_loop +#[test] +fun test_break_loop() { + let mut x = 0; - assert!(x == 5, 0); - } - // ANCHOR_END: break_loop - // ANCHOR: continue_loop - #[test] - fun test_continue_loop() { - let mut x = 0; - - // This will loop until `x` is 10. - loop { - x = x + 1; - - // If `x` is odd, then skip the rest of the iteration. - if (x % 2 == 1) { - continue // Skip the rest of the iteration. - }; - - std::debug::print(&x); - - // If `x` is 10, then exit the loop. - if (x == 10) { - break // Exit the loop. - } - }; + // This will loop until `x` is 5. + loop { + x = x + 1; - assert!(x == 10, 0); // 10 - } - // ANCHOR_END: continue_loop - // ANCHOR: return_statement - /// This function returns `true` if `x` is greater than 0 and not 5, - /// otherwise it returns `false`. - fun is_positive(x: u8): bool { + // If `x` is 5, then exit the loop. if (x == 5) { - return false - }; + break // Exit the loop. + } + }; - if (x > 0) { - return true + assert!(x == 5, 0); +} +// ANCHOR_END: break_loop +// ANCHOR: continue_loop +#[test] +fun test_continue_loop() { + let mut x = 0; + + // This will loop until `x` is 10. + loop { + x = x + 1; + + // If `x` is odd, then skip the rest of the iteration. + if (x % 2 == 1) { + continue // Skip the rest of the iteration. }; - false - } + std::debug::print(&x); + + // If `x` is 10, then exit the loop. + if (x == 10) { + break // Exit the loop. + } + }; - #[test] - fun test_return() { - assert!(is_positive(5) == false, 0); - assert!(is_positive(0) == false, 0); - assert!(is_positive(1) == true, 0); - } - // ANCHOR_END: return_statement + assert!(x == 10, 0); // 10 +} +// ANCHOR_END: continue_loop +// ANCHOR: return_statement +/// This function returns `true` if `x` is greater than 0 and not 5, +/// otherwise it returns `false`. +fun is_positive(x: u8): bool { + if (x == 5) { + return false + }; + + if (x > 0) { + return true + }; + + false +} +#[test] +fun test_return() { + assert!(is_positive(5) == false, 0); + assert!(is_positive(0) == false, 0); + assert!(is_positive(1) == true, 0); } +// ANCHOR_END: return_statement diff --git a/packages/samples/sources/move-basics/copy-ability.move b/packages/samples/sources/move-basics/copy-ability.move index c76c748b..148532d1 100644 --- a/packages/samples/sources/move-basics/copy-ability.move +++ b/packages/samples/sources/move-basics/copy-ability.move @@ -2,7 +2,7 @@ // SPDX-License-Identifier: Apache-2.0 #[allow(unused_variable)] -module book::copy_ability { +module book::copy_ability; // ANCHOR: copyable public struct Copyable has copy {} @@ -24,4 +24,3 @@ let Copyable {} = c; // doesn't have `drop` // ANCHOR: copy_drop public struct Value has copy, drop {} // ANCHOR_END: copy_drop -} diff --git a/packages/samples/sources/move-basics/drop-ability.move b/packages/samples/sources/move-basics/drop-ability.move index 5e313dfc..1397e8b9 100644 --- a/packages/samples/sources/move-basics/drop-ability.move +++ b/packages/samples/sources/move-basics/drop-ability.move @@ -2,26 +2,25 @@ // SPDX-License-Identifier: Apache-2.0 // ANCHOR: main -module book::drop_ability { +module book::drop_ability; - /// This struct has the `drop` ability. - public struct IgnoreMe has drop { - a: u8, - b: u8, - } +/// This struct has the `drop` ability. +public struct IgnoreMe has drop { + a: u8, + b: u8, +} - /// This struct does not have the `drop` ability. - public struct NoDrop {} +/// This struct does not have the `drop` ability. +public struct NoDrop {} - #[test] - // Create an instance of the `IgnoreMe` struct and ignore it. - // Even though we constructed the instance, we don't need to unpack it. - fun test_ignore() { - let no_drop = NoDrop {}; - let _ = IgnoreMe { a: 1, b: 2 }; // no need to unpack +#[test] +// Create an instance of the `IgnoreMe` struct and ignore it. +// Even though we constructed the instance, we don't need to unpack it. +fun test_ignore() { + let no_drop = NoDrop {}; + let _ = IgnoreMe { a: 1, b: 2 }; // no need to unpack - // The value must be unpacked for the code to compile. - let NoDrop {} = no_drop; // OK - } + // The value must be unpacked for the code to compile. + let NoDrop {} = no_drop; // OK } // ANCHOR_END: main diff --git a/packages/samples/sources/move-basics/function.move b/packages/samples/sources/move-basics/function.move index 3a2c794c..3f8b96d7 100644 --- a/packages/samples/sources/move-basics/function.move +++ b/packages/samples/sources/move-basics/function.move @@ -1,46 +1,29 @@ // Copyright (c) Mysten Labs, Inc. // SPDX-License-Identifier: Apache-2.0 -#[allow(unused_variable)] +#[allow(unused_variable, unused_function, unused_let_mut)] // ANCHOR: math -module book::math { - /// Function takes two arguments of type `u64` and returns their sum. - /// The `public` visibility modifier makes the function accessible from - /// outside the module. - public fun add(a: u64, b: u64): u64 { - a + b - } +module book::math; - #[test] - fun test_add() { - let sum = add(1, 2); - assert!(sum == 3, 0); - } +/// Function takes two arguments of type `u64` and returns their sum. +/// The `public` visibility modifier makes the function accessible from +/// outside the module. +public fun add(a: u64, b: u64): u64 { + a + b +} + +#[test] +fun test_add() { + let sum = add(1, 2); + assert!(sum == 3, 0); } // ANCHOR_END: math -#[allow(unused_variable, unused_function)] -module book::function_declaration { + // ANCHOR: return_nothing fun return_nothing() { // empty expression, function returns `()` } // ANCHOR_END: return_nothing -} - -#[allow(unused_variable, unused_function)] -// ANCHOR: use_math -module book::use_math { - use book::math; - - fun call_add() { - // function is called via the path - let sum = math::add(1, 2); - } -} -// ANCHOR_END: use_math - -#[allow(unused_variable, unused_let_mut)] -module book::function_multi_return { // ANCHOR: tuple_return fun get_name_and_age(): (vector, u8) { @@ -67,4 +50,3 @@ let (mut name, age) = get_name_and_age(); let (_, age) = get_name_and_age(); // ANCHOR_END: tuple_return_ignore } -} diff --git a/packages/samples/sources/move-basics/function_use.move b/packages/samples/sources/move-basics/function_use.move new file mode 100644 index 00000000..ff528bcd --- /dev/null +++ b/packages/samples/sources/move-basics/function_use.move @@ -0,0 +1,14 @@ +// Copyright (c) Mysten Labs, Inc. +// SPDX-License-Identifier: Apache-2.0 + +#[allow(unused_variable, unused_function)] +// ANCHOR: use_math +module book::use_math; + +use book::math; + +fun call_add() { + // function is called via the path + let sum = math::add(1, 2); +} +// ANCHOR_END: use_math diff --git a/packages/samples/sources/move-basics/generics.move b/packages/samples/sources/move-basics/generics.move index b1f778d4..869e7196 100644 --- a/packages/samples/sources/move-basics/generics.move +++ b/packages/samples/sources/move-basics/generics.move @@ -1,7 +1,7 @@ // Copyright (c) Mysten Labs, Inc. // SPDX-License-Identifier: Apache-2.0 #[allow(unused_variable, unused_field)] -module book::generics { +module book::generics; // ANCHOR: container /// Container for any type `T`. @@ -29,10 +29,6 @@ fun test_container() { let Container { value: _ } = container; } // ANCHOR_END: test_container -} - -#[allow(unused_variable, unused_field)] -module book::generics_multiple { // ANCHOR: pair /// A pair of values of any type `T` and `U`. @@ -82,11 +78,8 @@ fun test_swap_type_params() { assert!(ps1 == pf2, 0x0); // true == true } // ANCHOR_END: test_pair_swap -} -#[allow(unused_variable, unused_field)] -module book::generics_user { - use std::string::String; +use std::string::String; // ANCHOR: user /// A user record with name, age, and some generic metadata @@ -109,10 +102,6 @@ public fun update_age(user: &mut User, age: u8) { user.age = age; } // ANCHOR_END: update_user -} - -#[allow(unused_variable, unused_field)] -module book::generics_phantom { // ANCHOR: phantom /// A generic type with a phantom type parameter. @@ -135,10 +124,6 @@ fun test_phantom_type() { let Coin { value: _ } = coin2; } // ANCHOR_END: test_phantom -} - -#[allow(unused_variable, unused_field)] -module book::generics_constraints { // ANCHOR: constraints /// A generic type with a type parameter that has the `drop` ability. @@ -165,5 +150,3 @@ fun test_constraints() { // let copyable_droppable = CopyableDroppable { value: 10 }; } // ANCHOR_END: test_constraints - -} diff --git a/packages/samples/sources/move-basics/importing-module-members.move b/packages/samples/sources/move-basics/importing-module-members.move new file mode 100644 index 00000000..91472676 --- /dev/null +++ b/packages/samples/sources/move-basics/importing-module-members.move @@ -0,0 +1,15 @@ +// Copyright (c) Mysten Labs, Inc. +// SPDX-License-Identifier: Apache-2.0 + +#[allow(unused_use)] +// ANCHOR: members +module book::more_imports; + +use book::module_one::new; // imports the `new` function from the `module_one` module +use book::module_one::Character; // importing the `Character` struct from the `module_one` module + +/// Calls the `new` function from the `module_one` module. +public fun create_character(): Character { + new() +} +// ANCHOR_END: members diff --git a/packages/samples/sources/move-basics/importing-modules-conflict-resolution.move b/packages/samples/sources/move-basics/importing-modules-conflict-resolution.move new file mode 100644 index 00000000..bd04bfb0 --- /dev/null +++ b/packages/samples/sources/move-basics/importing-modules-conflict-resolution.move @@ -0,0 +1,15 @@ +// Copyright (c) Mysten Labs, Inc. +// SPDX-License-Identifier: Apache-2.0 + +#[allow(unused_use)] +// ANCHOR: conflict +module book::conflict_resolution; + +// `as` can be placed after any import, including group imports +use book::module_one::{Self as mod, Character as Char}; + +/// Calls the `new` function from the `module_one` module. +public fun create(): Char { + mod::new() +} +// ANCHOR_END: conflict diff --git a/packages/samples/sources/move-basics/importing-modules-external.move b/packages/samples/sources/move-basics/importing-modules-external.move new file mode 100644 index 00000000..f9800296 --- /dev/null +++ b/packages/samples/sources/move-basics/importing-modules-external.move @@ -0,0 +1,10 @@ +// Copyright (c) Mysten Labs, Inc. +// SPDX-License-Identifier: Apache-2.0 + +#[allow(unused_use)] +// ANCHOR: external +module book::imports; + +use std::string; // std = 0x1, string is a module in the standard library +use sui::coin; // sui = 0x2, coin is a module in the Sui Framework +// ANCHOR_END: external diff --git a/packages/samples/sources/move-basics/importing-modules-grouped.move b/packages/samples/sources/move-basics/importing-modules-grouped.move new file mode 100644 index 00000000..952c71e6 --- /dev/null +++ b/packages/samples/sources/move-basics/importing-modules-grouped.move @@ -0,0 +1,16 @@ +// Copyright (c) Mysten Labs, Inc. +// SPDX-License-Identifier: Apache-2.0 + +#[allow(unused_use)] +// ANCHOR: grouped +module book::grouped_imports; + +// imports the `new` function and the `Character` struct from +// the `module_one` module +use book::module_one::{new, Character}; + +/// Calls the `new` function from the `module_one` module. +public fun create_character(): Character { + new() +} +// ANCHOR_END: grouped diff --git a/packages/samples/sources/move-basics/importing-modules-self.move b/packages/samples/sources/move-basics/importing-modules-self.move new file mode 100644 index 00000000..02682277 --- /dev/null +++ b/packages/samples/sources/move-basics/importing-modules-self.move @@ -0,0 +1,15 @@ +// Copyright (c) Mysten Labs, Inc. +// SPDX-License-Identifier: Apache-2.0 + +#[allow(unused_use)] +// ANCHOR: self +module book::self_imports; + +// imports the `Character` struct, and the `module_one` module +use book::module_one::{Self, Character}; + +/// Calls the `new` function from the `module_one` module. +public fun create_character(): Character { + module_one::new() +} +// ANCHOR_END: self diff --git a/packages/samples/sources/move-basics/importing-modules-two.move b/packages/samples/sources/move-basics/importing-modules-two.move new file mode 100644 index 00000000..d62e5483 --- /dev/null +++ b/packages/samples/sources/move-basics/importing-modules-two.move @@ -0,0 +1,14 @@ +// Copyright (c) Mysten Labs, Inc. +// SPDX-License-Identifier: Apache-2.0 + +#[allow(unused_use)] +// ANCHOR: module_two +module book::module_two; + +use book::module_one; // importing module_one from the same package + +/// Calls the `new` function from the `module_one` module. +public fun create_and_ignore() { + let _ = module_one::new(); +} +// ANCHOR_END: module_two diff --git a/packages/samples/sources/move-basics/importing-modules.move b/packages/samples/sources/move-basics/importing-modules.move index d86f86be..bca39336 100644 --- a/packages/samples/sources/move-basics/importing-modules.move +++ b/packages/samples/sources/move-basics/importing-modules.move @@ -3,84 +3,11 @@ #[allow(unused_use)] // ANCHOR: module_one -module book::module_one { - /// Struct defined in the same module. - public struct Character has drop {} +module book::module_one; - /// Simple function that creates a new `Character` instance. - public fun new(): Character { Character {} } -} -// ANCHOR_END: module_one - -#[allow(unused_use)] -// ANCHOR: module_two -module book::module_two { - use book::module_one; // importing module_one from the same package - - /// Calls the `new` function from the `module_one` module. - public fun create_and_ignore() { - let _ = module_one::new(); - } -} -// ANCHOR_END: module_two - -#[allow(unused_use)] -// ANCHOR: members -module book::more_imports { - use book::module_one::new; // imports the `new` function from the `module_one` module - use book::module_one::Character; // importing the `Character` struct from the `module_one` module - - /// Calls the `new` function from the `module_one` module. - public fun create_character(): Character { - new() - } -} -// ANCHOR_END: members - -#[allow(unused_use)] -// ANCHOR: grouped -module book::grouped_imports { - // imports the `new` function and the `Character` struct from - /// the `module_one` module - use book::module_one::{new, Character}; +/// Struct defined in the same module. +public struct Character has drop {} - /// Calls the `new` function from the `module_one` module. - public fun create_character(): Character { - new() - } -} -// ANCHOR_END: grouped - -#[allow(unused_use)] -// ANCHOR: self -module book::self_imports { - // imports the `Character` struct, and the `module_one` module - use book::module_one::{Self, Character}; - - /// Calls the `new` function from the `module_one` module. - public fun create_character(): Character { - module_one::new() - } -} -// ANCHOR_END: self - -#[allow(unused_use)] -// ANCHOR: conflict -module book::conflict_resolution { - // `as` can be placed after any import, including group imports - use book::module_one::{Self as mod, Character as Char}; - - /// Calls the `new` function from the `module_one` module. - public fun create(): Char { - mod::new() - } -} -// ANCHOR_END: conflict - -#[allow(unused_use)] -// ANCHOR: external -module book::imports { - use std::string; // std = 0x1, string is a module in the standard library - use sui::coin; // sui = 0x2, coin is a module in the Sui Framework -} -// ANCHOR_END: external +/// Simple function that creates a new `Character` instance. +public fun new(): Character { Character {} } +// ANCHOR_END: module_one diff --git a/packages/samples/sources/move-basics/module-label.move b/packages/samples/sources/move-basics/module-label.move new file mode 100644 index 00000000..c19cd218 --- /dev/null +++ b/packages/samples/sources/move-basics/module-label.move @@ -0,0 +1,9 @@ +// Copyright (c) Mysten Labs, Inc. +// SPDX-License-Identifier: Apache-2.0 + +// ANCHOR: module +// Module label. +module book::my_module; + +// module body +// ANCHOR_END: module diff --git a/packages/samples/sources/move-basics/module-members.move b/packages/samples/sources/move-basics/module-members.move new file mode 100644 index 00000000..9cc91086 --- /dev/null +++ b/packages/samples/sources/move-basics/module-members.move @@ -0,0 +1,22 @@ +// Copyright (c) Mysten Labs, Inc. +// SPDX-License-Identifier: Apache-2.0 + +#[allow(unused_function, unused_const, unused_use)] +// ANCHOR: members +module book::my_module_with_members; + +// import +use book::my_module; + +// a constant +const CONST: u8 = 0; + +// a struct +public struct Struct {} + +// method alias +public use fun function as Struct.struct_fun; + +// function +fun function(_: &Struct) { /* function body */ } +// ANCHOR_END: members diff --git a/packages/samples/sources/move-basics/module.move b/packages/samples/sources/move-basics/module.move index 40d6506b..6316b67d 100644 --- a/packages/samples/sources/move-basics/module.move +++ b/packages/samples/sources/move-basics/module.move @@ -1,12 +1,6 @@ // Copyright (c) Mysten Labs, Inc. // SPDX-License-Identifier: Apache-2.0 -// ANCHOR: module -module book::my_module { - // module body -} -// ANCHOR_END: module - // ANCHOR: address_literal module 0x0::address_literal { /* ... */ } module book::named_address { /* ... */ } @@ -14,7 +8,7 @@ module book::named_address { /* ... */ } #[allow(unused_function, unused_const, unused_use)] // ANCHOR: members -module book::my_module_with_members { +module book::my_block_module_with_members { // import use book::my_module; @@ -30,4 +24,10 @@ module book::my_module_with_members { // function fun function(_: &Struct) { /* function body */ } } + +// module block allows multiple module definitions in the +// same file but this is not a recommended practice +module book::another_module_in_the_file { + // ... +} // ANCHOR_END: members diff --git a/packages/samples/sources/move-basics/option.move b/packages/samples/sources/move-basics/option.move index e40079ae..593d4b71 100644 --- a/packages/samples/sources/move-basics/option.move +++ b/packages/samples/sources/move-basics/option.move @@ -1,30 +1,29 @@ // Copyright (c) Mysten Labs, Inc. // SPDX-License-Identifier: Apache-2.0 +#[allow(unused_variable)] // ANCHOR: registry -module book::user_registry { - use std::string::String; - - /// A struct representing a user record. - public struct User has drop { - first_name: String, - middle_name: Option, - last_name: String, - } - - /// Create a new `User` struct with the given fields. - public fun register( - first_name: String, - middle_name: Option, - last_name: String, - ): User { - User { first_name, middle_name, last_name } - } +module book::user_registry; + +use std::string::String; + +/// A struct representing a user record. +public struct User has drop { + first_name: String, + middle_name: Option, + last_name: String, +} + +/// Create a new `User` struct with the given fields. +public fun register( + first_name: String, + middle_name: Option, + last_name: String, +): User { + User { first_name, middle_name, last_name } } // ANCHOR_END: registry -#[allow(unused_variable)] -module book::option_usage { #[test] fun use_option() { // ANCHOR: usage @@ -44,4 +43,3 @@ let inner = opt.extract(); assert!(opt.is_none(), 2); // ANCHOR_END: usage } -} diff --git a/packages/samples/sources/move-basics/references.move b/packages/samples/sources/move-basics/references.move index 91abddff..1326899c 100644 --- a/packages/samples/sources/move-basics/references.move +++ b/packages/samples/sources/move-basics/references.move @@ -2,78 +2,77 @@ // SPDX-License-Identifier: Apache-2.0 // ANCHOR: main -module book::references { +module book::references; // ANCHOR: header - /// Error code for when the card is empty. - const ENoUses: u64 = 0; +/// Error code for when the card is empty. +const ENoUses: u64 = 0; - /// Number of uses for a metro pass card. - const USES: u8 = 3; +/// Number of uses for a metro pass card. +const USES: u8 = 3; - /// A metro pass card - public struct Card { uses: u8 } +/// A metro pass card +public struct Card { uses: u8 } // ANCHOR_END: header - // ANCHOR: new - /// Purchase a metro pass card. - public fun purchase(/* pass a Coin */): Card { - Card { uses: USES } - } - // ANCHOR_END: new +// ANCHOR: new +/// Purchase a metro pass card. +public fun purchase(/* pass a Coin */): Card { + Card { uses: USES } +} +// ANCHOR_END: new - // ANCHOR: immutable - /// Show the metro pass card to the inspector. - public fun is_valid(card: &Card): bool { - card.uses > 0 - } - // ANCHOR_END: immutable +// ANCHOR: immutable +/// Show the metro pass card to the inspector. +public fun is_valid(card: &Card): bool { + card.uses > 0 +} +// ANCHOR_END: immutable - // ANCHOR: mutable - /// Use the metro pass card at the turnstile to enter the metro. - public fun enter_metro(card: &mut Card) { - assert!(card.uses > 0, ENoUses); - card.uses = card.uses - 1; - } - // ANCHOR_END: mutable +// ANCHOR: mutable +/// Use the metro pass card at the turnstile to enter the metro. +public fun enter_metro(card: &mut Card) { + assert!(card.uses > 0, ENoUses); + card.uses = card.uses - 1; +} +// ANCHOR_END: mutable - // ANCHOR: move - /// Recycle the metro pass card. - public fun recycle(card: Card) { - assert!(card.uses == 0, ENoUses); - let Card { uses: _ } = card; - } - // ANCHOR_END: move +// ANCHOR: move +/// Recycle the metro pass card. +public fun recycle(card: Card) { + assert!(card.uses == 0, ENoUses); + let Card { uses: _ } = card; +} +// ANCHOR_END: move - // ANCHOR: test - #[test] - fun test_card() { - // declaring variable as mutable because we modify it - let mut card = purchase(); +// ANCHOR: test +#[test] +fun test_card() { + // declaring variable as mutable because we modify it + let mut card = purchase(); - enter_metro(&mut card); + enter_metro(&mut card); - assert!(is_valid(&card), 0); // read the card! + assert!(is_valid(&card), 0); // read the card! - enter_metro(&mut card); // modify the card but don't move it - enter_metro(&mut card); // modify the card but don't move it + enter_metro(&mut card); // modify the card but don't move it + enter_metro(&mut card); // modify the card but don't move it - recycle(card); // move the card out of the scope - } - // ANCHOR_END: test + recycle(card); // move the card out of the scope +} +// ANCHOR_END: test - // ANCHOR: move_2024 - #[test] - fun test_card_2024() { - // declaring variable as mutable because we modify it - let mut card = purchase(); +// ANCHOR: move_2024 +#[test] +fun test_card_2024() { + // declaring variable as mutable because we modify it + let mut card = purchase(); - card.enter_metro(); // modify the card but don't move it - assert!(card.is_valid(), 0); // read the card! + card.enter_metro(); // modify the card but don't move it + assert!(card.is_valid(), 0); // read the card! - card.enter_metro(); // modify the card but don't move it - card.enter_metro(); // modify the card but don't move it + card.enter_metro(); // modify the card but don't move it + card.enter_metro(); // modify the card but don't move it - card.recycle(); // move the card out of the scope - } - // ANCHOR_END: move_2024 + card.recycle(); // move the card out of the scope } +// ANCHOR_END: move_2024 // ANCHOR_END: main diff --git a/packages/samples/sources/move-basics/string-custom.move b/packages/samples/sources/move-basics/string-custom.move new file mode 100644 index 00000000..40a8edab --- /dev/null +++ b/packages/samples/sources/move-basics/string-custom.move @@ -0,0 +1,2 @@ +// Copyright (c) Mysten Labs, Inc. +// SPDX-License-Identifier: Apache-2.0 diff --git a/packages/samples/sources/move-basics/string.move b/packages/samples/sources/move-basics/string.move index 83119ffd..8cc50137 100644 --- a/packages/samples/sources/move-basics/string.move +++ b/packages/samples/sources/move-basics/string.move @@ -1,31 +1,31 @@ // Copyright (c) Mysten Labs, Inc. // SPDX-License-Identifier: Apache-2.0 +#[allow(unused_variable)] // ANCHOR: custom -module book::custom_string { - /// Anyone can implement a custom string-like type by wrapping a vector. - public struct MyString { - bytes: vector, - } - - /// Implement a `from_bytes` function to convert a vector of bytes to a string. - public fun from_bytes(bytes: vector): MyString { - MyString { bytes } - } - - /// Implement a `bytes` function to convert a string to a vector of bytes. - public fun bytes(self: &MyString): &vector { - &self.bytes - } +module book::custom_string; + +/// Anyone can implement a custom string-like type by wrapping a vector. +public struct MyString { + bytes: vector, +} + +/// Implement a `from_bytes` function to convert a vector of bytes to a string. +public fun from_bytes(bytes: vector): MyString { + MyString { bytes } +} + +/// Implement a `bytes` function to convert a string to a vector of bytes. +public fun bytes(self: &MyString): &vector { + &self.bytes } // ANCHOR_END: custom -module book::string_ascii { - // use std::ascii::String; +// use std::ascii::String; - #[allow(unused_variable)] - #[test] - fun using_strings() { +#[allow(unused_variable)] +#[test] +fun using_strings() { // ANCHOR: ascii // the module is `std::ascii` and the type is `String` use std::ascii::{Self, String}; @@ -38,17 +38,9 @@ let hey: String = ascii::string(b"Hey"); let hey = b"Hey".to_ascii_string(); // ANCHOR_END: ascii - } -} - -module book::string_safe_utf { - } -#[allow(unused_variable)] -module book::string_utf { - #[test] - fun using_strings() { +#[test] fun using_strings_utf8() { // ANCHOR: utf8 // the module is `std::string` and the type is `String` use std::string::{Self, String}; @@ -60,10 +52,9 @@ let hello: String = string::utf8(b"Hello"); // The `.to_string()` alias on the `vector` is more convenient let hello = b"Hello".to_string(); // ANCHOR_END: utf8 - } +} - #[test] - fun safe_strings() { +#[test] fun safe_strings() { // ANCHOR: safe_utf8 // this is a valid UTF-8 string let hello = b"Hello".try_to_string(); @@ -75,5 +66,4 @@ let invalid = b"\xFF".try_to_string(); assert!(invalid.is_none(), 0); // abort if the value is valid UTF-8 // ANCHOR_END: safe_utf8 - } } diff --git a/packages/samples/sources/move-basics/struct-methods-2.move b/packages/samples/sources/move-basics/struct-methods-2.move new file mode 100644 index 00000000..a7923eef --- /dev/null +++ b/packages/samples/sources/move-basics/struct-methods-2.move @@ -0,0 +1,44 @@ +// Copyright (c) Mysten Labs, Inc. +// SPDX-License-Identifier: Apache-2.0 + +// ANCHOR: hero_and_villain +module book::hero_and_villain; + +/// A struct representing a hero. +public struct Hero has drop { + health: u8, +} + +/// A struct representing a villain. +public struct Villain has drop { + health: u8, +} + +/// Create a new Hero. +public fun new_hero(): Hero { Hero { health: 100 } } + +/// Create a new Villain. +public fun new_villain(): Villain { Villain { health: 100 } } + +// Alias for the `hero_health` method. Will be imported automatically when +// the module is imported. +public use fun hero_health as Hero.health; + +public fun hero_health(hero: &Hero): u8 { hero.health } + +// Alias for the `villain_health` method. Will be imported automatically +// when the module is imported. +public use fun villain_health as Villain.health; + +public fun villain_health(villain: &Villain): u8 { villain.health } + +#[test] +// Test the methods of the `Hero` and `Villain` structs. +fun test_associated_methods() { + let hero = new_hero(); + assert!(hero.health() == 100, 1); + + let villain = new_villain(); + assert!(villain.health() == 100, 3); +} +// ANCHOR_END: hero_and_villain diff --git a/packages/samples/sources/move-basics/struct-methods-3.move b/packages/samples/sources/move-basics/struct-methods-3.move new file mode 100644 index 00000000..d1e9ad7f --- /dev/null +++ b/packages/samples/sources/move-basics/struct-methods-3.move @@ -0,0 +1,28 @@ +// Copyright (c) Mysten Labs, Inc. +// SPDX-License-Identifier: Apache-2.0 + +// ANCHOR: hero_to_bytes +// TODO: better example (external module...) +module book::hero_to_bytes; + +// Alias for the `bcs::to_bytes` method. Imported aliases should be defined +// in the top of the module. +// public use fun bcs::to_bytes as Hero.to_bytes; + +/// A struct representing a hero. +public struct Hero has drop { + health: u8, + mana: u8, +} + +/// Create a new Hero. +public fun new(): Hero { Hero { health: 100, mana: 100 } } + +#[test] +// Test the methods of the `Hero` struct. +fun test_hero_serialize() { + // let mut hero = new(); + // let serialized = hero.to_bytes(); + // assert!(serialized.length() == 3, 1); +} +// ANCHOR_END: hero_to_bytes diff --git a/packages/samples/sources/move-basics/struct-methods.move b/packages/samples/sources/move-basics/struct-methods.move index 7eb51034..3d8df5a8 100644 --- a/packages/samples/sources/move-basics/struct-methods.move +++ b/packages/samples/sources/move-basics/struct-methods.move @@ -1,105 +1,37 @@ +// Copyright (c) Mysten Labs, Inc. +// SPDX-License-Identifier: Apache-2.0 // ANCHOR: hero -module book::hero { - /// A struct representing a hero. - public struct Hero has drop { - health: u8, - mana: u8, - } +module book::hero; - /// Create a new Hero. - public fun new(): Hero { Hero { health: 100, mana: 100 } } - - /// A method which casts a spell, consuming mana. - public fun heal_spell(hero: &mut Hero) { - hero.health = hero.health + 10; - hero.mana = hero.mana - 10; - } - - /// A method which returns the health of the hero. - public fun health(hero: &Hero): u8 { hero.health } - - /// A method which returns the mana of the hero. - public fun mana(hero: &Hero): u8 { hero.mana } - - #[test] - // Test the methods of the `Hero` struct. - fun test_methods() { - let mut hero = new(); - hero.heal_spell(); - - assert!(hero.health() == 110, 1); - assert!(hero.mana() == 90, 2); - } +/// A struct representing a hero. +public struct Hero has drop { + health: u8, + mana: u8, } -// ANCHOR_END: hero - - -// ANCHOR: hero_and_villain -module book::hero_and_villain { - /// A struct representing a hero. - public struct Hero has drop { - health: u8, - } - - /// A struct representing a villain. - public struct Villain has drop { - health: u8, - } - /// Create a new Hero. - public fun new_hero(): Hero { Hero { health: 100 } } +/// Create a new Hero. +public fun new(): Hero { Hero { health: 100, mana: 100 } } - /// Create a new Villain. - public fun new_villain(): Villain { Villain { health: 100 } } - - // Alias for the `hero_health` method. Will be imported automatically when - // the module is imported. - public use fun hero_health as Hero.health; - - public fun hero_health(hero: &Hero): u8 { hero.health } - - // Alias for the `villain_health` method. Will be imported automatically - // when the module is imported. - public use fun villain_health as Villain.health; - - public fun villain_health(villain: &Villain): u8 { villain.health } - - #[test] - // Test the methods of the `Hero` and `Villain` structs. - fun test_associated_methods() { - let hero = new_hero(); - assert!(hero.health() == 100, 1); - - let villain = new_villain(); - assert!(villain.health() == 100, 3); - } +/// A method which casts a spell, consuming mana. +public fun heal_spell(hero: &mut Hero) { + hero.health = hero.health + 10; + hero.mana = hero.mana - 10; } -// ANCHOR_END: hero_and_villain +/// A method which returns the health of the hero. +public fun health(hero: &Hero): u8 { hero.health } -// ANCHOR: hero_to_bytes -// TODO: better example (external module...) -module book::hero_to_bytes { - // Alias for the `bcs::to_bytes` method. Imported aliases should be defined - // in the top of the module. - // public use fun bcs::to_bytes as Hero.to_bytes; +/// A method which returns the mana of the hero. +public fun mana(hero: &Hero): u8 { hero.mana } - /// A struct representing a hero. - public struct Hero has drop { - health: u8, - mana: u8, - } +#[test] +// Test the methods of the `Hero` struct. +fun test_methods() { + let mut hero = new(); + hero.heal_spell(); - /// Create a new Hero. - public fun new(): Hero { Hero { health: 100, mana: 100 } } - - #[test] - // Test the methods of the `Hero` struct. - fun test_hero_serialize() { - // let mut hero = new(); - // let serialized = hero.to_bytes(); - // assert!(serialized.length() == 3, 1); - } + assert!(hero.health() == 110, 1); + assert!(hero.mana() == 90, 2); } -// ANCHOR_END: hero_to_bytes +// ANCHOR_END: hero diff --git a/packages/samples/sources/move-basics/struct.move b/packages/samples/sources/move-basics/struct.move index 97a4da5d..7e91e038 100644 --- a/packages/samples/sources/move-basics/struct.move +++ b/packages/samples/sources/move-basics/struct.move @@ -2,8 +2,9 @@ // SPDX-License-Identifier: Apache-2.0 #[allow(unused_variable, unused_field)] -module book::struct_syntax { - use std::string::{Self, String}; +module book::struct_syntax; + +use std::string::{Self, String}; // ANCHOR: def /// A struct representing an artist. @@ -35,7 +36,6 @@ let mut artist = Artist { }; // ANCHOR_END: pack - // ANCHOR: access // Access the `name` field of the `Artist` struct. let artist_name = artist.name; @@ -64,6 +64,4 @@ let artist = Artist { // Unpack the `Artist` struct and ignore the `name` field. let Artist { name: _ } = artist; // ANCHOR_END: unpack_ignore - -} } diff --git a/packages/samples/sources/move-basics/type-reflection.move b/packages/samples/sources/move-basics/type-reflection.move index 02cb7c93..3670db49 100644 --- a/packages/samples/sources/move-basics/type-reflection.move +++ b/packages/samples/sources/move-basics/type-reflection.move @@ -3,35 +3,35 @@ #[allow(unused_variable)] // ANCHOR: main -module book::type_reflection { - use std::ascii::String; - use std::type_name::{Self, TypeName}; +module book::type_reflection; - /// A function that returns the name of the type `T` and its module and address. - public fun do_i_know_you(): (String, String, String) { - let type_name: TypeName = type_name::get(); +use std::ascii::String; +use std::type_name::{Self, TypeName}; - // there's a way to borrow - let str: &String = type_name.borrow_string(); +/// A function that returns the name of the type `T` and its module and address. +public fun do_i_know_you(): (String, String, String) { + let type_name: TypeName = type_name::get(); - let module_name: String = type_name.get_module(); - let address_str: String = type_name.get_address(); + // there's a way to borrow + let str: &String = type_name.borrow_string(); - // and a way to consume the value - let str = type_name.into_string(); + let module_name: String = type_name.get_module(); + let address_str: String = type_name.get_address(); - (str, module_name, address_str) - } + // and a way to consume the value + let str = type_name.into_string(); - #[test_only] - public struct MyType {} + (str, module_name, address_str) +} + +#[test_only] +public struct MyType {} - #[test] - fun test_type_reflection() { - let (type_name, module_name, _address_str) = do_i_know_you(); +#[test] +fun test_type_reflection() { + let (type_name, module_name, _address_str) = do_i_know_you(); - // - assert!(module_name == b"type_reflection".to_ascii_string(), 1); - } + // + assert!(module_name == b"type_reflection".to_ascii_string(), 1); } // ANCHOR_END: main diff --git a/packages/samples/sources/move-basics/vector.move b/packages/samples/sources/move-basics/vector.move index 1a092561..29b4e792 100644 --- a/packages/samples/sources/move-basics/vector.move +++ b/packages/samples/sources/move-basics/vector.move @@ -41,17 +41,17 @@ assert!(last_value == 40, 2); module book::non_droppable_vec { // ANCHOR: no_drop - /// A struct without `drop` ability. - public struct NoDrop {} - - #[test] - fun test_destroy_empty() { - // Initialize a vector of `NoDrop` elements. - let v = vector[]; - - // While we know that `v` is empty, we still need to call - // the explicit `destroy_empty` function to discard the vector. - v.destroy_empty(); - } +/// A struct without `drop` ability. +public struct NoDrop {} + +#[test] +fun test_destroy_empty() { + // Initialize a vector of `NoDrop` elements. + let v = vector[]; + + // While we know that `v` is empty, we still need to call + // the explicit `destroy_empty` function to discard the vector. + v.destroy_empty(); +} // ANCHOR_END: no_drop } diff --git a/packages/samples/sources/programmability/capability-2.move b/packages/samples/sources/programmability/capability-2.move new file mode 100644 index 00000000..b5a6250a --- /dev/null +++ b/packages/samples/sources/programmability/capability-2.move @@ -0,0 +1,19 @@ +// Copyright (c) Mysten Labs, Inc. +// SPDX-License-Identifier: Apache-2.0 + +// ANCHOR: admin_cap +module book::admin_cap; + +/// The capability granting the admin privileges in the system. +/// Created only once in the `init` function. +public struct AdminCap has key { id: UID } + +/// Create the AdminCap object on package publish and transfer it to the +/// package owner. +fun init(ctx: &mut TxContext) { + transfer::transfer( + AdminCap { id: object::new(ctx) }, + ctx.sender() + ) +} +// ANCHOR_END: admin_cap diff --git a/packages/samples/sources/programmability/capability-3.move b/packages/samples/sources/programmability/capability-3.move new file mode 100644 index 00000000..d2b8a2cd --- /dev/null +++ b/packages/samples/sources/programmability/capability-3.move @@ -0,0 +1,21 @@ +// Copyright (c) Mysten Labs, Inc. +// SPDX-License-Identifier: Apache-2.0 + +module book::addr_vs_cap; + +public struct User has key, store { id: UID } + +// ANCHOR: with_address +/// Error code for unauthorized access. +const ENotAuthorized: u64 = 0; + +/// The application admin address. +const APPLICATION_ADMIN: address = @0xa11ce; + +/// Creates a new user in the system. Requires the sender to be the application +/// admin. +public fun new(ctx: &mut TxContext): User { + assert!(ctx.sender() == APPLICATION_ADMIN, ENotAuthorized); + User { id: object::new(ctx) } +} +// ANCHOR_END: with_address diff --git a/packages/samples/sources/programmability/capability-4.move b/packages/samples/sources/programmability/capability-4.move new file mode 100644 index 00000000..2ba47cd1 --- /dev/null +++ b/packages/samples/sources/programmability/capability-4.move @@ -0,0 +1,17 @@ +// Copyright (c) Mysten Labs, Inc. +// SPDX-License-Identifier: Apache-2.0 + +module book::cap_vs_addr; + +public struct User has key, store { id: UID } + +// ANCHOR: with_capability +/// Grants the owner the right to create new users in the system. +public struct AdminCap {} + +/// Creates a new user in the system. Requires the `AdminCap` capability to be +/// passed as the first argument. +public fun new(_: &AdminCap, ctx: &mut TxContext): User { + User { id: object::new(ctx) } +} +// ANCHOR_END: with_capability diff --git a/packages/samples/sources/programmability/capability.move b/packages/samples/sources/programmability/capability.move index 00a8e1b0..f81ca273 100644 --- a/packages/samples/sources/programmability/capability.move +++ b/packages/samples/sources/programmability/capability.move @@ -2,98 +2,43 @@ // SPDX-License-Identifier: Apache-2.0 // ANCHOR: main -module book::capability { - use std::string::String; - use sui::event; +module book::capability; - /// The capability granting the application admin the right to create new - /// accounts in the system. - public struct AdminCap has key, store { id: UID } +use std::string::String; +use sui::event; - /// The user account in the system. - public struct Account has key, store { - id: UID, - name: String - } - - /// A simple `Ping` event with no data. - public struct Ping has copy, drop { by: ID } - - /// Creates a new account in the system. Requires the `AdminCap` capability - /// to be passed as the first argument. - public fun new(_: &AdminCap, name: String, ctx: &mut TxContext): Account { - Account { - id: object::new(ctx), - name, - } - } - - /// Account, and any other objects, can also be used as a Capability in the - /// application. For example, to emit an event. - public fun send_ping(acc: &Account) { - event::emit(Ping { - by: acc.id.to_inner() - }) - } +/// The capability granting the application admin the right to create new +/// accounts in the system. +public struct AdminCap has key, store { id: UID } - /// Updates the account name. Can only be called by the `Account` owner. - public fun update(account: &mut Account, name: String) { - account.name = name; - } +/// The user account in the system. +public struct Account has key, store { + id: UID, + name: String } -// ANCHOR_END: main -// ANCHOR: admin_cap -module book::admin_cap { - /// The capability granting the admin privileges in the system. - /// Created only once in the `init` function. - public struct AdminCap has key { id: UID } +/// A simple `Ping` event with no data. +public struct Ping has copy, drop { by: ID } - /// Create the AdminCap object on package publish and transfer it to the - /// package owner. - fun init(ctx: &mut TxContext) { - transfer::transfer( - AdminCap { id: object::new(ctx) }, - ctx.sender() - ) +/// Creates a new account in the system. Requires the `AdminCap` capability +/// to be passed as the first argument. +public fun new(_: &AdminCap, name: String, ctx: &mut TxContext): Account { + Account { + id: object::new(ctx), + name, } } -// ANCHOR_END: admin_cap - - -module book::addr_vs_cap { - - public struct User has key, store { id: UID } - -// ANCHOR: with_address -/// Error code for unauthorized access. -const ENotAuthorized: u64 = 0; - -/// The application admin address. -const APPLICATION_ADMIN: address = @0xa11ce; - -/// Creates a new user in the system. Requires the sender to be the application -/// admin. -public fun new(ctx: &mut TxContext): User { - assert!(ctx.sender() == APPLICATION_ADMIN, ENotAuthorized); - User { id: object::new(ctx) } -} -// ANCHOR_END: with_address +/// Account, and any other objects, can also be used as a Capability in the +/// application. For example, to emit an event. +public fun send_ping(acc: &Account) { + event::emit(Ping { + by: acc.id.to_inner() + }) } -module book::cap_vs_addr { - - public struct User has key, store { id: UID } - -// ANCHOR: with_capability -/// Grants the owner the right to create new users in the system. -public struct AdminCap {} - -/// Creates a new user in the system. Requires the `AdminCap` capability to be -/// passed as the first argument. -public fun new(_: &AdminCap, ctx: &mut TxContext): User { - User { id: object::new(ctx) } -} -// ANCHOR_END: with_capability +/// Updates the account name. Can only be called by the `Account` owner. +public fun update(account: &mut Account, name: String) { + account.name = name; } +// ANCHOR_END: main diff --git a/packages/samples/sources/programmability/collections-2.move b/packages/samples/sources/programmability/collections-2.move new file mode 100644 index 00000000..9c5c28a6 --- /dev/null +++ b/packages/samples/sources/programmability/collections-2.move @@ -0,0 +1,29 @@ +// Copyright (c) Mysten Labs, Inc. +// SPDX-License-Identifier: Apache-2.0 + +#[allow(unused_variable, unused_field)] +// ANCHOR: vec_set +module book::collections_vec_set; + +use sui::vec_set::{Self, VecSet}; + +public struct App has drop { + /// `VecSet` used in the struct definition + subscribers: VecSet
+} + +#[test] +fun vec_set_playground() { + let set = vec_set::empty(); // create an empty set + let mut set = vec_set::singleton(1); // create a set with a single item + + set.insert(2); // add an item to the set + set.insert(3); + + assert!(set.contains(&1), 0); // check if an item is in the set + assert!(set.size() == 3, 1); // get the number of items in the set + assert!(!set.is_empty(), 2); // check if the set is empty + + set.remove(&2); // remove an item from the set +} +// ANCHOR_END: vec_set diff --git a/packages/samples/sources/programmability/collections-3.move b/packages/samples/sources/programmability/collections-3.move new file mode 100644 index 00000000..05664e99 --- /dev/null +++ b/packages/samples/sources/programmability/collections-3.move @@ -0,0 +1,28 @@ +// Copyright (c) Mysten Labs, Inc. +// SPDX-License-Identifier: Apache-2.0 + +#[allow(unused_field, unused_variable)] +// ANCHOR: vec_map +module book::collections_vec_map; + +use std::string::String; +use sui::vec_map::{Self, VecMap}; + +public struct Metadata has drop { + name: String, + /// `VecMap` used in the struct definition + attributes: VecMap +} + +#[test] +fun vec_map_playground() { + let mut map = vec_map::empty(); // create an empty map + + map.insert(2, b"two".to_string()); // add a key-value pair to the map + map.insert(3, b"three".to_string()); + + assert!(map.contains(&2), 0); // check if a key is in the map + + map.remove(&2); // remove a key-value pair from the map +} +// ANCHOR_END: vec_map diff --git a/packages/samples/sources/programmability/collections-4.move b/packages/samples/sources/programmability/collections-4.move new file mode 100644 index 00000000..1050d165 --- /dev/null +++ b/packages/samples/sources/programmability/collections-4.move @@ -0,0 +1,22 @@ +// Copyright (c) Mysten Labs, Inc. +// SPDX-License-Identifier: Apache-2.0 + +#[allow(unused_field, unused_variable, lint(collection_equality))] +module book::collections_compare_vec_set; + +use sui::vec_set; + +#[test, expected_failure] +fun test_compare() { +// ANCHOR: vec_set_comparison +let mut set1 = vec_set::empty(); +set1.insert(1); +set1.insert(2); + +let mut set2 = vec_set::empty(); +set2.insert(2); +set2.insert(1); + +assert!(set1 == set2); // aborts! +// ANCHOR_END: vec_set_comparison +} diff --git a/packages/samples/sources/programmability/collections.move b/packages/samples/sources/programmability/collections.move index 086eb46c..ed51ecea 100644 --- a/packages/samples/sources/programmability/collections.move +++ b/packages/samples/sources/programmability/collections.move @@ -3,91 +3,19 @@ #[allow(unused_variable, unused_field)] // ANCHOR: vector -module book::collections_vector { - use std::string::String; +module book::collections_vector; - /// The Book that can be sold by a `BookStore` - public struct Book has key, store { - id: UID, - name: String - } +use std::string::String; - /// The BookStore that sells `Book`s - public struct BookStore has key, store { - id: UID, - books: vector - } +/// The Book that can be sold by a `BookStore` +public struct Book has key, store { + id: UID, + name: String } -// ANCHOR_END: vector - -#[allow(unused_variable, unused_field)] -// ANCHOR: vec_set -module book::collections_vec_set { - use sui::vec_set::{Self, VecSet}; - - public struct App has drop { - /// `VecSet` used in the struct definition - subscribers: VecSet
- } - - #[test] - fun vec_set_playground() { - let set = vec_set::empty(); // create an empty set - let mut set = vec_set::singleton(1); // create a set with a single item - - set.insert(2); // add an item to the set - set.insert(3); - - assert!(set.contains(&1), 0); // check if an item is in the set - assert!(set.size() == 3, 1); // get the number of items in the set - assert!(!set.is_empty(), 2); // check if the set is empty - - set.remove(&2); // remove an item from the set - } -} -// ANCHOR_END: vec_set - -#[allow(unused_field, unused_variable)] -// ANCHOR: vec_map -module book::collections { - use std::string::String; - use sui::vec_map::{Self, VecMap}; - public struct Metadata has drop { - name: String, - /// `VecMap` used in the struct definition - attributes: VecMap - } - - #[test] - fun vec_map_playground() { - let mut map = vec_map::empty(); // create an empty map - - map.insert(2, b"two".to_string()); // add a key-value pair to the map - map.insert(3, b"three".to_string()); - - assert!(map.contains(&2), 0); // check if a key is in the map - - map.remove(&2); // remove a key-value pair from the map - } -} -// ANCHOR_END: vec_map - -#[allow(unused_field, unused_variable, lint(collection_equality))] -module book::collections_compare_vec_set { -use sui::vec_set; -#[test, expected_failure] -fun test_compare() { -// ANCHOR: vec_set_comparison -let mut set1 = vec_set::empty(); -set1.insert(1); -set1.insert(2); - -let mut set2 = vec_set::empty(); -set2.insert(2); -set2.insert(1); - -assert!(set1 == set2, 0); -// ANCHOR_END: vec_set_comparison -} +/// The BookStore that sells `Book`s +public struct BookStore has key, store { + id: UID, + books: vector } +// ANCHOR_END: vector diff --git a/packages/samples/sources/programmability/display.move b/packages/samples/sources/programmability/display.move index eb7a2ca9..07f3f9a0 100644 --- a/packages/samples/sources/programmability/display.move +++ b/packages/samples/sources/programmability/display.move @@ -1,9 +1,59 @@ // Copyright (c) Mysten Labs, Inc. // SPDX-License-Identifier: Apache-2.0 + #[allow(unused_field)] -module book::background { - use std::string::String; +// ANCHOR: hero +module book::arena; + +use std::string::String; +use sui::package; +use sui::display; + +/// The One Time Witness to claim the `Publisher` object. +public struct ARENA has drop {} + +/// Some object which will be displayed. +public struct Hero has key { + id: UID, + class: String, + level: u64, +} + +/// In the module initializer we create the `Publisher` object, and then +/// the Display for the `Hero` type. +fun init(otw: ARENA, ctx: &mut TxContext) { + let publisher = package::claim(otw, ctx); + let mut display = display::new(&publisher, ctx); + + display.add( + b"name".to_string(), + b"{class} (lvl. {level})".to_string() + ); + + display.add( + b"description".to_string(), + b"One of the greatest heroes of all time. Join us!".to_string() + ); + + display.add( + b"link".to_string(), + b"https://example.com/hero/{id}".to_string() + ); + + display.add( + b"image_url".to_string(), + b"https://example.com/hero/{class}.jpg".to_string() + ); + + // Update the display with the new data. + // Must be called to apply changes. + display.update_version(); + + transfer::public_transfer(publisher, ctx.sender()); + transfer::public_transfer(display, ctx.sender()); +} +// ANCHOR_END: hero // ANCHOR: background /// An attempt to standardize the object structure for display. @@ -20,64 +70,6 @@ public struct CounterWithDisplay has key { // ... } // ANCHOR_END: background -} - -#[allow(unused_field)] -// ANCHOR: hero -module book::arena { - use std::string::String; - use sui::package; - use sui::display; - - /// The One Time Witness to claim the `Publisher` object. - public struct ARENA has drop {} - - /// Some object which will be displayed. - public struct Hero has key { - id: UID, - class: String, - level: u64, - } - - /// In the module initializer we create the `Publisher` object, and then - /// the Display for the `Hero` type. - fun init(otw: ARENA, ctx: &mut TxContext) { - let publisher = package::claim(otw, ctx); - let mut display = display::new(&publisher, ctx); - - display.add( - b"name".to_string(), - b"{class} (lvl. {level})".to_string() - ); - - display.add( - b"description".to_string(), - b"One of the greatest heroes of all time. Join us!".to_string() - ); - - display.add( - b"link".to_string(), - b"https://example.com/hero/{id}".to_string() - ); - - display.add( - b"image_url".to_string(), - b"https://example.com/hero/{class}.jpg".to_string() - ); - - // Update the display with the new data. - // Must be called to apply changes. - display.update_version(); - - transfer::public_transfer(publisher, ctx.sender()); - transfer::public_transfer(display, ctx.sender()); - } -} -// ANCHOR_END: hero - -#[allow(unused_field)] -module book::nested_metadata { - use std::string::String; // ANCHOR: nested /// Some common metadata for objects. @@ -94,5 +86,3 @@ public struct LittlePony has key, store { metadata: Metadata } // ANCHOR_END: nested - -} diff --git a/packages/samples/sources/programmability/dynamic-fields.move b/packages/samples/sources/programmability/dynamic-fields.move index 9169bae8..b0e11bfe 100644 --- a/packages/samples/sources/programmability/dynamic-fields.move +++ b/packages/samples/sources/programmability/dynamic-fields.move @@ -2,62 +2,63 @@ // SPDX-License-Identifier: Apache-2.0 // ANCHOR: usage -module book::dynamic_collection { - // a very common alias for `dynamic_field` is `df` since the - // module name is quite long - use sui::dynamic_field as df; - use std::string::String; - - /// The object that we will attach dynamic fields to. - public struct Character has key { - id: UID - } - - // List of different accessories that can be attached to a character. - // They must have the `store` ability. - public struct Hat has key, store { id: UID, color: u32 } - public struct Mustache has key, store { id: UID } - - #[test] - fun test_character_and_accessories() { - let ctx = &mut tx_context::dummy(); - let mut character = Character { id: object::new(ctx) }; - - // Attach a hat to the character's UID - df::add( - &mut character.id, - b"hat_key", - Hat { id: object::new(ctx), color: 0xFF0000 } - ); - - // Similarly, attach a mustache to the character's UID - df::add( - &mut character.id, - b"mustache_key", - Mustache { id: object::new(ctx) } - ); - - // Check that the hat and mustache are attached to the character - // - assert!(df::exists_(&character.id, b"hat_key"), 0); - assert!(df::exists_(&character.id, b"mustache_key"), 1); - - // Modify the color of the hat - let hat: &mut Hat = df::borrow_mut(&mut character.id, b"hat_key"); - hat.color = 0x00FF00; - - // Remove the hat and mustache from the character - let hat: Hat = df::remove(&mut character.id, b"hat_key"); - let mustache: Mustache = df::remove(&mut character.id, b"mustache_key"); - - // Check that the hat and mustache are no longer attached to the character - assert!(!df::exists_(&character.id, b"hat_key"), 0); - assert!(!df::exists_(&character.id, b"mustache_key"), 1); - - sui::test_utils::destroy(character); - sui::test_utils::destroy(mustache); - sui::test_utils::destroy(hat); - } +module book::dynamic_fields; + +// a very common alias for `dynamic_field` is `df` since the +// module name is quite long +use sui::dynamic_field as df; +use std::string::String; + +/// The object that we will attach dynamic fields to. +public struct Character has key { + id: UID +} + +// List of different accessories that can be attached to a character. +// They must have the `store` ability. +public struct Hat has key, store { id: UID, color: u32 } +public struct Mustache has key, store { id: UID } + +#[test] +fun test_character_and_accessories() { + let ctx = &mut tx_context::dummy(); + let mut character = Character { id: object::new(ctx) }; + + // Attach a hat to the character's UID + df::add( + &mut character.id, + b"hat_key", + Hat { id: object::new(ctx), color: 0xFF0000 } + ); + + // Similarly, attach a mustache to the character's UID + df::add( + &mut character.id, + b"mustache_key", + Mustache { id: object::new(ctx) } + ); + + // Check that the hat and mustache are attached to the character + // + assert!(df::exists_(&character.id, b"hat_key"), 0); + assert!(df::exists_(&character.id, b"mustache_key"), 1); + + // Modify the color of the hat + let hat: &mut Hat = df::borrow_mut(&mut character.id, b"hat_key"); + hat.color = 0x00FF00; + + // Remove the hat and mustache from the character + let hat: Hat = df::remove(&mut character.id, b"hat_key"); + let mustache: Mustache = df::remove(&mut character.id, b"mustache_key"); + + // Check that the hat and mustache are no longer attached to the character + assert!(!df::exists_(&character.id, b"hat_key"), 0); + assert!(!df::exists_(&character.id, b"mustache_key"), 1); + + sui::test_utils::destroy(character); + sui::test_utils::destroy(mustache); + sui::test_utils::destroy(hat); +} // ANCHOR_END: usage @@ -150,4 +151,3 @@ df::add(&mut character.id, MetadataKey {}, 42); // ANCHOR_END: custom_type_usage sui::test_utils::destroy(character); } -} diff --git a/packages/samples/sources/programmability/dynamic-object-fields.move b/packages/samples/sources/programmability/dynamic-object-fields.move index cf59d677..3b99a118 100644 --- a/packages/samples/sources/programmability/dynamic-object-fields.move +++ b/packages/samples/sources/programmability/dynamic-object-fields.move @@ -3,48 +3,48 @@ #[allow(unused_variable)] // ANCHOR: usage -module book::dynamic_object_field { - use std::string::String; +module book::dynamic_object_field; - // there are two common aliases for the long module name: `dof` and - // `ofield`. Both are commonly used and met in different projects. - use sui::dynamic_object_field as dof; - use sui::dynamic_field as df; +use std::string::String; - /// The `Character` that we will use for the example - public struct Character has key { id: UID } +// there are two common aliases for the long module name: `dof` and +// `ofield`. Both are commonly used and met in different projects. +use sui::dynamic_object_field as dof; +use sui::dynamic_field as df; - /// Metadata that doesn't have the `key` ability - public struct Metadata has store, drop { name: String } +/// The `Character` that we will use for the example +public struct Character has key { id: UID } - /// Accessory that has the `key` and `store` abilities. - public struct Accessory has key, store { id: UID } +/// Metadata that doesn't have the `key` ability +public struct Metadata has store, drop { name: String } - #[test] - fun equip_accessory() { - let ctx = &mut tx_context::dummy(); - let mut character = Character { id: object::new(ctx) }; +/// Accessory that has the `key` and `store` abilities. +public struct Accessory has key, store { id: UID } - // Create an accessory and attach it to the character - let hat = Accessory { id: object::new(ctx) }; +#[test] +fun equip_accessory() { + let ctx = &mut tx_context::dummy(); + let mut character = Character { id: object::new(ctx) }; - // Add the hat to the character. Just like with `dynamic_fields` - dof::add(&mut character.id, b"hat_key", hat); + // Create an accessory and attach it to the character + let hat = Accessory { id: object::new(ctx) }; - // However for non-key structs we can only use `dynamic_field` - df::add(&mut character.id, b"metadata_key", Metadata { - name: b"John".to_string() - }); + // Add the hat to the character. Just like with `dynamic_fields` + dof::add(&mut character.id, b"hat_key", hat); - // Borrow the hat from the character - let hat_id = dof::id(&character.id, b"hat_key").extract(); // Option - let hat_ref: &Accessory = dof::borrow(&character.id, b"hat_key"); - let hat_mut: &mut Accessory = dof::borrow_mut(&mut character.id, b"hat_key"); - let hat: Accessory = dof::remove(&mut character.id, b"hat_key"); + // However for non-key structs we can only use `dynamic_field` + df::add(&mut character.id, b"metadata_key", Metadata { + name: b"John".to_string() + }); - // Clean up, Metadata is an orphan now. - sui::test_utils::destroy(hat); - sui::test_utils::destroy(character); - } + // Borrow the hat from the character + let hat_id = dof::id(&character.id, b"hat_key").extract(); // Option + let hat_ref: &Accessory = dof::borrow(&character.id, b"hat_key"); + let hat_mut: &mut Accessory = dof::borrow_mut(&mut character.id, b"hat_key"); + let hat: Accessory = dof::remove(&mut character.id, b"hat_key"); + + // Clean up, Metadata is an orphan now. + sui::test_utils::destroy(hat); + sui::test_utils::destroy(character); } // ANCHOR_END: usage diff --git a/packages/samples/sources/programmability/events.move b/packages/samples/sources/programmability/events.move index f9508205..ba4d5977 100644 --- a/packages/samples/sources/programmability/events.move +++ b/packages/samples/sources/programmability/events.move @@ -2,33 +2,33 @@ // SPDX-License-Identifier: Apache-2.0 // ANCHOR: emit -module book::events { - use sui::coin::Coin; - use sui::sui::SUI; - use sui::event; +module book::events; - /// The item that can be purchased. - public struct Item has key { id: UID } +use sui::coin::Coin; +use sui::sui::SUI; +use sui::event; - /// Event emitted when an item is purchased. Contains the ID of the item and - /// the price for which it was purchased. - public struct ItemPurchased has copy, drop { - item: ID, - price: u64 - } +/// The item that can be purchased. +public struct Item has key { id: UID } - /// A marketplace function which performs the purchase of an item. - public fun purchase(coin: Coin, ctx: &mut TxContext) { - let item = Item { id: object::new(ctx) }; +/// Event emitted when an item is purchased. Contains the ID of the item and +/// the price for which it was purchased. +public struct ItemPurchased has copy, drop { + item: ID, + price: u64 +} + +/// A marketplace function which performs the purchase of an item. +public fun purchase(coin: Coin, ctx: &mut TxContext) { + let item = Item { id: object::new(ctx) }; - // Create an instance of `ItemPurchased` and pass it to `event::emit`. - event::emit(ItemPurchased { - item: object::id(&item), - price: coin.value() - }); + // Create an instance of `ItemPurchased` and pass it to `event::emit`. + event::emit(ItemPurchased { + item: object::id(&item), + price: coin.value() + }); - // Omitting the rest of the implementation to keep the example simple. - abort 0 - } + // Omitting the rest of the implementation to keep the example simple. + abort 0 } // ANCHOR_END: emit diff --git a/packages/samples/sources/programmability/module-initializer-2.move b/packages/samples/sources/programmability/module-initializer-2.move new file mode 100644 index 00000000..abb16aec --- /dev/null +++ b/packages/samples/sources/programmability/module-initializer-2.move @@ -0,0 +1,18 @@ +// Copyright (c) Mysten Labs, Inc. +// SPDX-License-Identifier: Apache-2.0 + +// ANCHOR: other +// In the same package as the `shop` module +module book::bank; + +public struct Bank has key { + id: UID, + /* ... */ +} + +fun init(ctx: &mut TxContext) { + transfer::share_object(Bank { + id: object::new(ctx) + }); +} +// ANCHOR_END: other diff --git a/packages/samples/sources/programmability/module-initializer.move b/packages/samples/sources/programmability/module-initializer.move index a5ca3dde..fb433868 100644 --- a/packages/samples/sources/programmability/module-initializer.move +++ b/packages/samples/sources/programmability/module-initializer.move @@ -2,46 +2,29 @@ // SPDX-License-Identifier: Apache-2.0 // ANCHOR: main -module book::shop { - /// The Capability which grants the Shop owner the right to manage - /// the shop. - public struct ShopOwnerCap has key, store { id: UID } +module book::shop; - /// The singular Shop itself, created in the `init` function. - public struct Shop has key { - id: UID, - /* ... */ - } +/// The Capability which grants the Shop owner the right to manage +/// the shop. +public struct ShopOwnerCap has key, store { id: UID } - // Called only once, upon module publication. It must be - // private to prevent external invocation. - fun init(ctx: &mut TxContext) { - // Transfers the ShopOwnerCap to the sender (publisher). - transfer::transfer(ShopOwnerCap { - id: object::new(ctx) - }, ctx.sender()); - - // Shares the Shop object. - transfer::share_object(Shop { - id: object::new(ctx) - }); - } +/// The singular Shop itself, created in the `init` function. +public struct Shop has key { + id: UID, + /* ... */ } -// ANCHOR_END: main -// ANCHOR: other -// In the same package as the `shop` module -module book::bank { +// Called only once, upon module publication. It must be +// private to prevent external invocation. +fun init(ctx: &mut TxContext) { + // Transfers the ShopOwnerCap to the sender (publisher). + transfer::transfer(ShopOwnerCap { + id: object::new(ctx) + }, ctx.sender()); - public struct Bank has key { - id: UID, - /* ... */ - } - - fun init(ctx: &mut TxContext) { - transfer::share_object(Bank { - id: object::new(ctx) - }); - } + // Shares the Shop object. + transfer::share_object(Shop { + id: object::new(ctx) + }); } -// ANCHOR_END: other +// ANCHOR_END: main diff --git a/packages/samples/sources/programmability/one-time-witness.move b/packages/samples/sources/programmability/one-time-witness.move index af98a1e9..3325e508 100644 --- a/packages/samples/sources/programmability/one-time-witness.move +++ b/packages/samples/sources/programmability/one-time-witness.move @@ -3,19 +3,18 @@ #[allow(unused_variable, unused_mut_parameter)] // ANCHOR: definition -module book::one_time { - /// The OTW for the `book::one_time` module. - /// Only `drop`, no fields, no generics, all uppercase. - public struct ONE_TIME has drop {} +module book::one_time; - /// Receive the instance of `ONE_TIME` as the first argument. - fun init(otw: ONE_TIME, ctx: &mut TxContext) { - // do something with the OTW - } +/// The OTW for the `book::one_time` module. +/// Only `drop`, no fields, no generics, all uppercase. +public struct ONE_TIME has drop {} + +/// Receive the instance of `ONE_TIME` as the first argument. +fun init(otw: ONE_TIME, ctx: &mut TxContext) { + // do something with the OTW } // ANCHOR_END: definition -module book::one_time_usage { // ANCHOR: usage use sui::types; @@ -26,4 +25,3 @@ public fun takes_witness(otw: T) { assert!(types::is_one_time_witness(&otw), ENotOneTimeWitness); } // ANCHOR_END: usage -} diff --git a/packages/samples/sources/programmability/publisher.move b/packages/samples/sources/programmability/publisher.move index e6365ce7..20c1a4f3 100644 --- a/packages/samples/sources/programmability/publisher.move +++ b/packages/samples/sources/programmability/publisher.move @@ -1,35 +1,32 @@ // Copyright (c) Mysten Labs, Inc. // SPDX-License-Identifier: Apache-2.0 +#[allow(unused_variable)] // ANCHOR: publisher -module book::publisher { - /// Some type defined in the module. - public struct Book {} - - /// The OTW for the module. - public struct PUBLISHER has drop {} - - /// Uses the One Time Witness to claim the Publisher object. - fun init(otw: PUBLISHER, ctx: &mut TxContext) { - // Claim the Publisher object. - let publisher = sui::package::claim(otw, ctx); - - // Usually it is transferred to the sender. - // It can also be stored in another object. - transfer::public_transfer(publisher, ctx.sender()) - } -} -// ANCHOR_END: publisher +module book::publisher; -#[allow(unused_variable)] -module book::use_publisher { - use sui::package::{Self, Publisher}; +use sui::package::{Self, Publisher}; + +/// Some type defined in the module. +public struct Book {} - public struct Book {} +/// The OTW for the module. +public struct PUBLISHER has drop {} - public struct USE_PUBLISHER has drop {} +/// Uses the One Time Witness to claim the Publisher object. +fun init(otw: PUBLISHER, ctx: &mut TxContext) { + // Claim the Publisher object. + let publisher: Publisher = sui::package::claim(otw, ctx); - const ENotAuthorized: u64 = 1; + // Usually it is transferred to the sender. + // It can also be stored in another object. + transfer::public_transfer(publisher, ctx.sender()) +} +// ANCHOR_END: publisher + +public struct USE_PUBLISHER has drop {} + +const ENotAuthorized: u64 = 1; #[test] @@ -56,4 +53,3 @@ public fun admin_action(cap: &Publisher, /* app objects... */ param: u64) { // perform application-specific action } // ANCHOR_END: publisher_as_admin -} diff --git a/packages/samples/sources/programmability/transaction-context.move b/packages/samples/sources/programmability/transaction-context.move index d8a4ce85..373f554a 100644 --- a/packages/samples/sources/programmability/transaction-context.move +++ b/packages/samples/sources/programmability/transaction-context.move @@ -2,7 +2,7 @@ // SPDX-License-Identifier: Apache-2.0 #[allow(unused_variable)] -module book::transaction_context { +module book::transaction_context; // ANCHOR: reading public fun some_action(ctx: &TxContext) { @@ -12,5 +12,3 @@ public fun some_action(ctx: &TxContext) { // ... } // ANCHOR_END: reading - -} diff --git a/packages/samples/sources/programmability/witness-pattern.move b/packages/samples/sources/programmability/witness-pattern.move index 619ddb6f..45bbdb97 100644 --- a/packages/samples/sources/programmability/witness-pattern.move +++ b/packages/samples/sources/programmability/witness-pattern.move @@ -1,14 +1,13 @@ // Copyright (c) Mysten Labs, Inc. // SPDX-License-Identifier: Apache-2.0 -module book::witness_definition { +module book::witness_definition; + // ANCHOR: definition /// Canonical definition of a witness - a type with the `drop` ability. public struct MyWitness has drop {} // ANCHOR_END: definition -} -module book::regulated_coin { // ANCHOR: regulated_coin /// A custom RegulatedCoin type with implementable functions. public struct RegulatedCoin has key { @@ -42,4 +41,3 @@ public fun join(coin: &mut RegulatedCoin, other: RegulatedCoin) { id.delete(); } // ANCHOR_END: regulated_coin -} diff --git a/packages/todo_list/sources/todo_list.move b/packages/todo_list/sources/todo_list.move index 787ed95d..abb89722 100644 --- a/packages/todo_list/sources/todo_list.move +++ b/packages/todo_list/sources/todo_list.move @@ -1,43 +1,43 @@ // ANCHOR: all /// Module: todo_list -module todo_list::todo_list { - use std::string::String; - - /// List of todos. Can be managed by the owner and shared with others. - public struct TodoList has key, store { - id: UID, - items: vector - } - - /// Create a new todo list. - public fun new(ctx: &mut TxContext): TodoList { - let list = TodoList { - id: object::new(ctx), - items: vector[] - }; - - (list) - } - - /// Add a new todo item to the list. - public fun add(list: &mut TodoList, item: String) { - list.items.push_back(item); - } - - /// Remove a todo item from the list by index. - public fun remove(list: &mut TodoList, index: u64): String { - list.items.remove(index) - } - - /// Delete the list and the capability to manage it. - public fun delete(list: TodoList) { - let TodoList { id, items: _ } = list; - id.delete(); - } - - /// Get the number of items in the list. - public fun length(list: &TodoList): u64 { - list.items.length() - } +module todo_list::todo_list; + +use std::string::String; + +/// List of todos. Can be managed by the owner and shared with others. +public struct TodoList has key, store { + id: UID, + items: vector +} + +/// Create a new todo list. +public fun new(ctx: &mut TxContext): TodoList { + let list = TodoList { + id: object::new(ctx), + items: vector[] + }; + + (list) +} + +/// Add a new todo item to the list. +public fun add(list: &mut TodoList, item: String) { + list.items.push_back(item); +} + +/// Remove a todo item from the list by index. +public fun remove(list: &mut TodoList, index: u64): String { + list.items.remove(index) +} + +/// Delete the list and the capability to manage it. +public fun delete(list: TodoList) { + let TodoList { id, items: _ } = list; + id.delete(); +} + +/// Get the number of items in the list. +public fun length(list: &TodoList): u64 { + list.items.length() } // ANCHOR_END: all From d58ad8c96c5d6e1a02f5d3f11c110366099f99bb Mon Sep 17 00:00:00 2001 From: Damir Shamanaev Date: Mon, 21 Oct 2024 18:09:56 +0300 Subject: [PATCH 2/2] follow up, whoopsie --- book/src/move-basics/comments.md | 10 +- book/src/move-basics/constants.md | 18 +-- book/src/move-basics/function.md | 4 +- book/src/move-basics/importing-modules.md | 12 +- book/src/move-basics/module.md | 20 ++- book/src/move-basics/ownership-and-scope.md | 126 +++++++++--------- book/src/move-basics/references.md | 1 - book/src/move-basics/struct-methods.md | 4 +- book/src/move-basics/testing.md | 99 +++++++------- book/src/move-basics/visibility.md | 64 ++++----- book/src/programmability/capability.md | 6 +- book/src/programmability/collections.md | 6 +- book/src/programmability/events.md | 20 +-- .../src/programmability/module-initializer.md | 2 +- book/src/programmability/witness-pattern.md | 32 ++--- book/src/your-first-move/hello-world.md | 55 ++++---- theme/highlight.js | 2 +- 17 files changed, 242 insertions(+), 239 deletions(-) diff --git a/book/src/move-basics/comments.md b/book/src/move-basics/comments.md index 5f7cabe5..64b76cd4 100644 --- a/book/src/move-basics/comments.md +++ b/book/src/move-basics/comments.md @@ -20,15 +20,11 @@ comment. ## Line comment -```Move -{{#include ../../../packages/samples/sources/move-basics/comments.move:line}} -``` - You can use double slash `//` to comment out the rest of the line. Everything after `//` will be ignored by the compiler. ```Move -{{#include ../../../packages/samples/sources/move-basics/comments.move:line_2}} +{{#include ../../../packages/samples/sources/move-basics/comments-line.move:main}} ``` ## Block comment @@ -38,7 +34,7 @@ Everything between `/*` and `*/` will be ignored by the compiler. You can use bl comment out a single line or multiple lines. You can even use them to comment out a part of a line. ```Move -{{#include ../../../packages/samples/sources/move-basics/comments.move:block}} +{{#include ../../../packages/samples/sources/move-basics/comments-block.move:main}} ``` This example is a bit extreme, but it shows how you can use block comments to comment out a part of @@ -51,7 +47,7 @@ They are similar to block comments, but they start with three slashes `///` and the definition of the item they document. ```Move -{{#include ../../../packages/samples/sources/move-basics/comments.move:doc}} +{{#include ../../../packages/samples/sources/move-basics/comments-doc.move:main}} ``` diff --git a/book/src/move-basics/constants.md b/book/src/move-basics/constants.md index f00e3bd6..b9eba314 100644 --- a/book/src/move-basics/constants.md +++ b/book/src/move-basics/constants.md @@ -24,7 +24,7 @@ price for a product, you might define a constant for it. Constants are stored in bytecode, and each time they are used, the value is copied. ```move -{{#include ../../../packages/samples/sources/move-basics/constants.move:shop_price}} +{{#include ../../../packages/samples/sources/move-basics/constants-shop-price.move:shop_price}} ``` ## Naming Convention @@ -35,7 +35,7 @@ It's a way to make constants stand out from other identifiers in the code. One e [error constants](./assert-and-abort.md#assert-and-abort), which are written in ECamelCase. ```move -{{#include ../../../packages/samples/sources/move-basics/constants.move:naming}} +{{#include ../../../packages/samples/sources/move-basics/constants-naming.move:naming}} ``` ## Constants are Immutable @@ -44,13 +44,13 @@ Constants can't be changed and assigned new values. They are part of the package inherently immutable. ```move -module book::immutable_constants { - const ITEM_PRICE: u64 = 100; +module book::immutable_constants; - // emits an error - fun change_price() { - ITEM_PRICE = 200; - } +const ITEM_PRICE: u64 = 100; + +// emits an error +fun change_price() { + ITEM_PRICE = 200; } ``` @@ -61,7 +61,7 @@ codebase. But due to constants being private to the module, they can't be access modules. One way to solve this is to define a "config" module that exports the constants. ```move -{{#include ../../../packages/samples/sources/move-basics/constants.move:config}} +{{#include ../../../packages/samples/sources/move-basics/constants-config.move:config}} ``` This way other modules can import and read the constants, and the update process is simplified. If diff --git a/book/src/move-basics/function.md b/book/src/move-basics/function.md index 08c03f4c..66ef63bc 100644 --- a/book/src/move-basics/function.md +++ b/book/src/move-basics/function.md @@ -7,7 +7,7 @@ the `fun` keyword at the module level. Just like any other module member, by def and can only be accessed from within the module. ```move -{{#include ../../../packages/samples/sources/move-basics/function.move:math}} +{{#include ../../../packages/samples/sources/move-basics/function_math.move:math}} ``` In this example, we define a function `add` that takes two arguments of type `u64` and returns their @@ -38,7 +38,7 @@ function called `add` in the `math` module in the `book` package, the path to it `book::math::add`, or, if the module is imported, `math::add`. ```move -{{#include ../../../packages/samples/sources/move-basics/function.move:use_math}} +{{#include ../../../packages/samples/sources/move-basics/function_use.move:use_math}} ``` ## Multiple return values diff --git a/book/src/move-basics/importing-modules.md b/book/src/move-basics/importing-modules.md index 98695431..f20cbae3 100644 --- a/book/src/move-basics/importing-modules.md +++ b/book/src/move-basics/importing-modules.md @@ -38,7 +38,7 @@ Another module defined in the same package can import the first module using the ```move // File: sources/module_two.move -{{#include ../../../packages/samples/sources/move-basics/importing-modules.move:module_two}} +{{#include ../../../packages/samples/sources/move-basics/importing-modules-two.move:module_two}} ``` ## Importing Members @@ -48,7 +48,7 @@ function or a single type from a module. The syntax is the same as for importing add the member name after the module path. ```move -{{#include ../../../packages/samples/sources/move-basics/importing-modules.move:members}} +{{#include ../../../packages/samples/sources/move-basics/importing-modules-members.move:members}} ``` ## Grouping Imports @@ -58,7 +58,7 @@ when you need to import multiple members from the same module. Move allows group same module and from the same package. ```move -{{#include ../../../packages/samples/sources/move-basics/importing-modules.move:grouped}} +{{#include ../../../packages/samples/sources/move-basics/importing-modules-grouped.move:grouped}} ``` Single function imports are less common in Move, since the function names can overlap and cause @@ -69,7 +69,7 @@ To import members and the module itself in the group import, you can use the `Se `Self` keyword refers to the module itself and can be used to import the module and its members. ```move -{{#include ../../../packages/samples/sources/move-basics/importing-modules.move:self}} +{{#include ../../../packages/samples/sources/move-basics/importing-modules-self.move:self}} ``` ## Resolving Name Conflicts @@ -81,7 +81,7 @@ in different packages. To resolve the conflict and avoid ambiguity, Move offers rename the imported member. ```move -{{#include ../../../packages/samples/sources/move-basics/importing-modules.move:conflict}} +{{#include ../../../packages/samples/sources/move-basics/importing-modules-conflict-resolution.move:conflict}} ``` ## Adding an External Dependency @@ -116,5 +116,5 @@ To import a module from another package, you use the `use` keyword followed by t module path consists of the package address (or alias) and the module name separated by `::`. ```move -{{#include ../../../packages/samples/sources/move-basics/importing-modules.move:external}} +{{#include ../../../packages/samples/sources/move-basics/importing-modules-external.move:external}} ``` diff --git a/book/src/move-basics/module.md b/book/src/move-basics/module.md index ce7bc4a7..e9bd0f19 100644 --- a/book/src/move-basics/module.md +++ b/book/src/move-basics/module.md @@ -18,17 +18,19 @@ learn how to define a module, how to declare its members and how to access them ## Module declaration -Modules are declared using the `module` keyword followed by the package address, module name and the -module body inside the curly braces `{}`. The module name should be in `snake_case` - all lowercase -letters with underscores between words. Modules names must be unique in the package. +Modules are declared using the `module` keyword followed by the package address, module name, +semicolon, and the module body. The module name should be in `snake_case` - all lowercase letters +with underscores between words. Modules names must be unique in the package. Usually, a single file in the `sources/` folder contains a single module. The file name should match the module name - for example, a `donut_shop` module should be stored in the `donut_shop.move` file. You can read more about coding conventions in the [Coding Conventions](../special-topics/coding-conventions.md) section. +> If you need to declare more than one module in a file, you must use [Module Block](#module-block). + ```Move -{{#include ../../../packages/samples/sources/move-basics/module.move:module}} +{{#include ../../../packages/samples/sources/move-basics/module-label.move:module}} ``` Structs, functions, constants and imports all part of the module: @@ -63,6 +65,16 @@ book = "0x0" Module members are declared inside the module body. To illustrate that, let's define a simple module with a struct, a function and a constant: +```Move +{{#include ../../../packages/samples/sources/move-basics/module-members.move:members}} +``` + +## Module block + +Pre-2024 edition of Move required _module block_ - the contents of the module need to be surrounded +by curly braces `{}`. The main reason to use block and not _label_ is if you need to define more +than one module in a file. + ```Move {{#include ../../../packages/samples/sources/move-basics/module.move:members}} ``` diff --git a/book/src/move-basics/ownership-and-scope.md b/book/src/move-basics/ownership-and-scope.md index f11c4b18..94ce17af 100644 --- a/book/src/move-basics/ownership-and-scope.md +++ b/book/src/move-basics/ownership-and-scope.md @@ -20,21 +20,21 @@ scope and executes every expression and statement. Once the function scope end, defined in it are dropped or deallocated. ```move -module book::ownership { - public fun owner() { - let a = 1; // a is owned by the `owner` function - } // a is dropped here - - public fun other() { - let b = 2; // b is owned by the `other` function - } // b is dropped here - - #[test] - fun test_owner() { - owner(); - other(); - // a & b is not valid here - } +module book::ownership; + +public fun owner() { + let a = 1; // a is owned by the `owner` function +} // a is dropped here + +public fun other() { + let b = 2; // b is owned by the `other` function +} // b is dropped here + +#[test] +fun test_owner() { + owner(); + other(); + // a & b is not valid here } ``` @@ -48,18 +48,18 @@ If we changed the `owner` function to return the variable `a`, then the ownershi transferred to the caller of the function. ```move -module book::ownership { - public fun owner(): u8 { - let a = 1; // a defined here - a // scope ends, a is returned - } - - #[test] - fun test_owner() { - let a = owner(); - // a is valid here - } // a is dropped here +module book::ownership; + +public fun owner(): u8 { + let a = 1; // a defined here + a // scope ends, a is returned } + +#[test] +fun test_owner() { + let a = owner(); + // a is valid here +} // a is dropped here ``` ## Passing by Value @@ -69,22 +69,22 @@ transferred to this function. When performing this operation, we _move_ the valu another. This is also called _move semantics_. ```move -module book::ownership { - public fun owner(): u8 { - let a = 10; - a - } // a is returned - - public fun take_ownership(v: u8) { - // v is owned by `take_ownership` - } // v is dropped here - - #[test] - fun test_owner() { - let a = owner(); - take_ownership(a); - // a is not valid here - } +module book::ownership; + +public fun owner(): u8 { + let a = 10; + a +} // a is returned + +public fun take_ownership(v: u8) { + // v is owned by `take_ownership` +} // v is dropped here + +#[test] +fun test_owner() { + let a = owner(); + take_ownership(a); + // a is not valid here } ``` @@ -95,34 +95,34 @@ sequence of statements and expressions, and it has its own scope. Variables defi owned by this block, and when the block ends, the variables are dropped. ```move -module book::ownership { - public fun owner() { - let a = 1; // a is owned by the `owner` function's scope +module book::ownership; + +public fun owner() { + let a = 1; // a is owned by the `owner` function's scope + { + let b = 2; // b is owned by the block { - let b = 2; // b is owned by the block - { - let c = 3; // c is owned by the block - }; // c is dropped here - }; // b is dropped here - // a = b; // error: b is not valid here - // a = c; // error: c is not valid here - } // a is dropped here -} + let c = 3; // c is owned by the block + }; // c is dropped here + }; // b is dropped here + // a = b; // error: b is not valid here + // a = c; // error: c is not valid here +} // a is dropped here ``` However, shall we use the return value of a block, the ownership of the variable is transferred to the caller of the block. ```move -module book::ownership { - public fun owner(): u8 { - let a = 1; // a is owned by the `owner` function's scope - let b = { - let c = 2; // c is owned by the block - c // c is returned - }; // c is dropped here - a + b // both a and b are valid here - } +module book::ownership; + +public fun owner(): u8 { + let a = 1; // a is owned by the `owner` function's scope + let b = { + let c = 2; // c is owned by the block + c // c is returned + }; // c is dropped here + a + b // both a and b are valid here } ``` diff --git a/book/src/move-basics/references.md b/book/src/move-basics/references.md index 72b27c24..66ef6aa3 100644 --- a/book/src/move-basics/references.md +++ b/book/src/move-basics/references.md @@ -42,7 +42,6 @@ module book::metro_pass { {{#include ../../../packages/samples/sources/move-basics/references.move:header}} {{#include ../../../packages/samples/sources/move-basics/references.move:new}} -} ``` diff --git a/book/src/move-basics/struct-methods.md b/book/src/move-basics/struct-methods.md index f596314f..e35fee8f 100644 --- a/book/src/move-basics/struct-methods.md +++ b/book/src/move-basics/struct-methods.md @@ -41,7 +41,7 @@ with `hero_` and `villain_` respectively. However, we can create aliases for the they can be called on the instances of the structs without the prefix. ```move -{{#include ../../../packages/samples/sources/move-basics/struct-methods.move:hero_and_villain}} +{{#include ../../../packages/samples/sources/move-basics/struct-methods-2.move:hero_and_villain}} ``` As you can see, in the test function, we called the `health` method on the instances of `Hero` and @@ -57,7 +57,7 @@ associate it with the `Hero` struct. It will allow serializing the `Hero` struct bytes. ```move -{{#include ../../../packages/samples/sources/move-basics/struct-methods.move:hero_to_bytes}} +{{#include ../../../packages/samples/sources/move-basics/struct-methods-3.move:hero_to_bytes}} ``` ## Further reading diff --git a/book/src/move-basics/testing.md b/book/src/move-basics/testing.md index a66df80c..b49aa1ab 100644 --- a/book/src/move-basics/testing.md +++ b/book/src/move-basics/testing.md @@ -12,21 +12,21 @@ functions are regular functions, but they must take no arguments and have no ret are excluded from the bytecode, and are never published. ```move -module book::testing { - // Test attribute is placed before the `fun` keyword. Can be both above or - // right before the `fun` keyword: `#[test] fun my_test() { ... }` - // The name of the test would be `book::testing::simple_test`. - #[test] - fun simple_test() { - let sum = 2 + 2; - assert!(sum == 4, 1); - } - - // The name of the test would be `book::testing::more_advanced_test`. - #[test] fun more_advanced_test() { - let sum = 2 + 2 + 2; - assert!(sum == 4, 1); - } +module book::testing; + +// Test attribute is placed before the `fun` keyword. Can be both above or +// right before the `fun` keyword: `#[test] fun my_test() { ... }` +// The name of the test would be `book::testing::simple_test`. +#[test] +fun simple_test() { + let sum = 2 + 2; + assert!(sum == 4); +} + +// The name of the test would be `book::testing::more_advanced_test`. +#[test] fun more_advanced_test() { + let sum = 2 + 2 + 2; + assert!(sum == 4); } ``` @@ -60,21 +60,20 @@ fails. If the test fails with a different abort code, the test will fail. If the abort, the test will also fail. ```move -module book::testing_failure { +module book::testing_failure; - const EInvalidArgument: u64 = 1; +const EInvalidArgument: u64 = 1; - #[test] - #[expected_failure(abort_code = 0)] - fun test_fail() { - abort 0 // aborts with 0 - } +#[test] +#[expected_failure(abort_code = 0)] +fun test_fail() { + abort 0 // aborts with 0 +} - // attributes can be grouped together - #[test, expected_failure(abort_code = EInvalidArgument)] - fun test_fail_1() { - abort 1 // aborts with 1 - } +// attributes can be grouped together +#[test, expected_failure(abort_code = EInvalidArgument)] +fun test_fail_1() { + abort 1 // aborts with 1 } ``` @@ -89,29 +88,29 @@ important to remember that these functions should not be included in the final p where the `#[test_only]` attribute comes in handy. ```move -module book::testing { - // Public function which uses the `secret` function. - public fun multiply_by_secret(x: u64): u64 { - x * secret() - } - - /// Private function which is not available to the public. - fun secret(): u64 { 100 } - - #[test_only] - /// This function is only available for testing purposes in tests and other - /// test-only functions. Mind the visibility - for `#[test_only]` it is - /// common to use `public` visibility. - public fun secret_for_testing(): u64 { - secret() - } - - #[test] - // In the test environment we have access to the `secret_for_testing` function. - fun test_multiply_by_secret() { - let expected = secret_for_testing() * 2; - assert!(multiply_by_secret(2) == expected, 1); - } +module book::testing; + +// Public function which uses the `secret` function. +public fun multiply_by_secret(x: u64): u64 { + x * secret() +} + +/// Private function which is not available to the public. +fun secret(): u64 { 100 } + +#[test_only] +/// This function is only available for testing purposes in tests and other +/// test-only functions. Mind the visibility - for `#[test_only]` it is +/// common to use `public` visibility. +public fun secret_for_testing(): u64 { + secret() +} + +#[test] +// In the test environment we have access to the `secret_for_testing` function. +fun test_multiply_by_secret() { + let expected = secret_for_testing() * 2; + assert!(multiply_by_secret(2) == expected); } ``` diff --git a/book/src/move-basics/visibility.md b/book/src/move-basics/visibility.md index 8febf7fc..b01e69f9 100644 --- a/book/src/move-basics/visibility.md +++ b/book/src/move-basics/visibility.md @@ -12,14 +12,14 @@ A function or a struct defined in a module which has no visibility modifier is _ module. It can't be called from other modules. ```move -module book::internal_visibility { - // This function can be called from other functions in the same module - fun internal() { /* ... */ } - - // Same module -> can call internal() - fun call_internal() { - internal(); - } +module book::internal_visibility; + +// This function can be called from other functions in the same module +fun internal() { /* ... */ } + +// Same module -> can call internal() +fun call_internal() { + internal(); } ``` @@ -28,13 +28,13 @@ module book::internal_visibility { ```move -module book::try_calling_internal { - use book::internal_visibility; +module book::try_calling_internal; + +use book::internal_visibility; - // Different module -> can't call internal() - fun try_calling_internal() { - internal_visibility::internal(); - } +// Different module -> can't call internal() +fun try_calling_internal() { + internal_visibility::internal(); } ``` @@ -44,22 +44,22 @@ A struct or a function can be made _public_ by adding the `public` keyword befor `struct` keyword. ```move -module book::public_visibility { - // This function can be called from other modules - public fun public() { /* ... */ } -} +module book::public_visibility; + +// This function can be called from other modules +public fun public() { /* ... */ } ``` A public function can be imported and called from other modules. The following code will compile: ```move module book::try_calling_public { - use book::public_visibility; - // Different module -> can call public() - fun try_calling_public() { - public_visibility::public(); - } +use book::public_visibility; + +// Different module -> can call public() +fun try_calling_public() { + public_visibility::public(); } ``` @@ -69,20 +69,20 @@ Move 2024 introduces the _package visibility_ modifier. A function with _package called from any module within the same package. It can't be called from other packages. ```move -module book::package_visibility { - public(package) fun package_only() { /* ... */ } -} +module book::package_visibility; + +public(package) fun package_only() { /* ... */ } ``` A package function can be called from any module within the same package: ```move -module book::try_calling_package { - use book::package_visibility; +module book::try_calling_package; + +use book::package_visibility; - // Same package `book` -> can call package_only() - fun try_calling_package() { - package_visibility::package_only(); - } +// Same package `book` -> can call package_only() +fun try_calling_package() { + package_visibility::package_only(); } ``` diff --git a/book/src/programmability/capability.md b/book/src/programmability/capability.md index 1e93be4b..8c993937 100644 --- a/book/src/programmability/capability.md +++ b/book/src/programmability/capability.md @@ -26,7 +26,7 @@ A very common practice is to create a single `AdminCap` object on package publis application can have a setup phase where the admin account prepares the state of the application. ```move -{{#include ../../../packages/samples/sources/programmability/capability.move:admin_cap}} +{{#include ../../../packages/samples/sources/programmability/capability-2.move:admin_cap}} ``` ## Address check vs Capability @@ -40,13 +40,13 @@ Let's look at how the `new` function that creates a user would look like if it w check: ```move -{{#include ../../../packages/samples/sources/programmability/capability.move:with_address}} +{{#include ../../../packages/samples/sources/programmability/capability-3.move:with_address}} ``` And now, let's see how the same function would look like with the capability: ```move -{{#include ../../../packages/samples/sources/programmability/capability.move:with_capability}} +{{#include ../../../packages/samples/sources/programmability/capability-4.move:with_capability}} ``` Using capabilities has several advantages over the address check: diff --git a/book/src/programmability/collections.md b/book/src/programmability/collections.md index 34d26c4e..20979710 100644 --- a/book/src/programmability/collections.md +++ b/book/src/programmability/collections.md @@ -23,7 +23,7 @@ does not allow duplicate items. This makes it useful for storing a collection of as a list of unique IDs or addresses. ```move -{{#include ../../../packages/samples/sources/programmability/collections.move:vec_set}} +{{#include ../../../packages/samples/sources/programmability/collections-2.move:vec_set}} ``` VecSet will fail on attempt to insert an item that already exists in the set. @@ -40,7 +40,7 @@ to insert a key-value pair with a key that already exists in the map, the old va with the new value. ```move -{{#include ../../../packages/samples/sources/programmability/collections.move:vec_map}} +{{#include ../../../packages/samples/sources/programmability/collections-3.move:vec_map}} ``` ## Limitations @@ -59,7 +59,7 @@ results. > 'sui::vec_set::VecSet' may yield unexpected result_ ```move -{{#include ../../../packages/samples/sources/programmability/collections.move:vec_set_comparison}} +{{#include ../../../packages/samples/sources/programmability/collections-4.move:vec_set_comparison}} ``` In the example above, the comparison will fail because the order of insertion is not guaranteed, and diff --git a/book/src/programmability/events.md b/book/src/programmability/events.md index d2a78d36..68260d17 100644 --- a/book/src/programmability/events.md +++ b/book/src/programmability/events.md @@ -11,16 +11,16 @@ on-chain. Events are emitted by the `sui::event` module located in the ```move // File: sui-framework/sources/event.move -module sui::event { - /// Emit a custom Move event, sending the data offchain. - /// - /// Used for creating custom indexes and tracking onchain - /// activity in a way that suits a specific application the most. - /// - /// The type `T` is the main way to index the event, and can contain - /// phantom parameters, eg `emit(MyEvent)`. - public native fun emit(event: T); -} +module sui::event; + +/// Emit a custom Move event, sending the data offchain. +/// +/// Used for creating custom indexes and tracking onchain +/// activity in a way that suits a specific application the most. +/// +/// The type `T` is the main way to index the event, and can contain +/// phantom parameters, eg `emit(MyEvent)`. +public native fun emit(event: T); ``` ## Emitting Events diff --git a/book/src/programmability/module-initializer.md b/book/src/programmability/module-initializer.md index 1ce6c2ce..76da5037 100644 --- a/book/src/programmability/module-initializer.md +++ b/book/src/programmability/module-initializer.md @@ -16,7 +16,7 @@ function will automatically be called when the module is published. In the same package, another module can have its own `init` function, encapsulating distinct logic. ```move -{{#include ../../../packages/samples/sources/programmability/module-initializer.move:other}} +{{#include ../../../packages/samples/sources/programmability/module-initializer-2.move:other}} ``` ## `init` features diff --git a/book/src/programmability/witness-pattern.md b/book/src/programmability/witness-pattern.md index 30475ebf..a135d69f 100644 --- a/book/src/programmability/witness-pattern.md +++ b/book/src/programmability/witness-pattern.md @@ -19,14 +19,14 @@ to create a `Instance` instance. > the [Drop](./../move-basics/drop-ability.md) ability for the type. ```move -module book::witness { - /// A struct that requires a witness to be created. - public struct Instance { t: T } - - /// Create a new instance of `Instance` with the provided T. - public fun new(witness: T): Instance { - Instance { t: witness } - } +module book::witness; + +/// A struct that requires a witness to be created. +public struct Instance { t: T } + +/// Create a new instance of `Instance` with the provided T. +public fun new(witness: T): Instance { + Instance { t: witness } } ``` @@ -35,16 +35,16 @@ type `T`. This is a basic example of the witness pattern in Move. A module provi has a matching implementation, like the module `book::witness_source` below: ```move -module book::witness_source { - use book::witness::{Self, Instance}; +module book::witness_source; + +use book::witness::{Self, Instance}; - /// A struct used as a witness. - public struct W {} +/// A struct used as a witness. +public struct W {} - /// Create a new instance of `Instance`. - public fun new_instance(): Instance { - witness::new(W {}) - } +/// Create a new instance of `Instance`. +public fun new_instance(): Instance { + witness::new(W {}) } ``` diff --git a/book/src/your-first-move/hello-world.md b/book/src/your-first-move/hello-world.md index eb3bbff6..5ed10068 100644 --- a/book/src/your-first-move/hello-world.md +++ b/book/src/your-first-move/hello-world.md @@ -83,9 +83,7 @@ _hello_world.move_ and the Move CLI has already placed commented out code inside ```move /* /// Module: hello_world -module hello_world::hello_world { - -} +module hello_world::hello_world; */ ``` @@ -116,21 +114,20 @@ The _hello_world_tests.move_ file contains a commented out test module template: ```move /* #[test_only] -module hello_world::hello_world_tests { - // uncomment this line to import the module - // use hello_world::hello_world; +module hello_world::hello_world_tests; +// uncomment this line to import the module +// use hello_world::hello_world; - const ENotImplemented: u64 = 0; +const ENotImplemented: u64 = 0; - #[test] - fun test_hello_world() { - // pass - } +#[test] +fun test_hello_world() { + // pass +} - #[test, expected_failure(abort_code = hello_world::hello_world_tests::ENotImplemented)] - fun test_hello_world_fail() { - abort ENotImplemented - } +#[test, expected_failure(abort_code = hello_world::hello_world_tests::ENotImplemented)] +fun test_hello_world_fail() { + abort ENotImplemented } */ ``` @@ -154,14 +151,14 @@ with the following: ```move /// The module `hello_world` under named address `hello_world`. /// The named address is set in the `Move.toml`. -module hello_world::hello_world { - // Imports the `String` type from the Standard Library - use std::string::String; - - /// Returns the "Hello, World!" as a `String`. - public fun hello_world(): String { - b"Hello, World!".to_string() - } +module hello_world::hello_world; + +// Imports the `String` type from the Standard Library +use std::string::String; + +/// Returns the "Hello, World!" as a `String`. +public fun hello_world(): String { + b"Hello, World!".to_string() } ``` @@ -203,13 +200,13 @@ Replace the contents of the `tests/hello_world_tests.move` with the following co ```move #[test_only] -module hello_world::hello_world_tests { - use hello_world::hello_world; +module hello_world::hello_world_tests; + +use hello_world::hello_world; - #[test] - fun test_hello_world() { - assert!(hello_world::hello_world() == b"Hello, World!".to_string(), 0); - } +#[test] +fun test_hello_world() { + assert!(hello_world::hello_world() == b"Hello, World!".to_string(), 0); } ``` diff --git a/theme/highlight.js b/theme/highlight.js index 0c23b73a..a63c3615 100644 --- a/theme/highlight.js +++ b/theme/highlight.js @@ -441,7 +441,7 @@ hljs.registerLanguage('move', function(hljs) { // module definition scope: 'module', begin: /\bmodule\b/, - end: /\{/, + end: /[;{]/, keywords: 'module', contains: [ BLOCK_COMMENT,