From 5ddafdc52cefdbf4688742450fac0e5e7852b789 Mon Sep 17 00:00:00 2001 From: Artur Yurii Korchynskyi <42449190+akorchyn@users.noreply.github.com> Date: Thu, 6 Feb 2025 16:05:44 +0200 Subject: [PATCH] doc: moved annotations to the near macro documentation. (#1299) * Moved annotations docs into near doc * Crated back-links on annotations. * Actualize urls * Extended annotations with serializers, serialize, contract_state, contract_metadata, event_json --- README.md | 2 +- near-sdk/src/lib.rs | 285 +++++++++++++++++++++++++------ near-sdk/src/near.rs | 147 ---------------- near-sdk/src/near_annotations.rs | 47 +++++ 4 files changed, 281 insertions(+), 200 deletions(-) delete mode 100644 near-sdk/src/near.rs create mode 100644 near-sdk/src/near_annotations.rs diff --git a/README.md b/README.md index 742ae8976..7bb392e38 100644 --- a/README.md +++ b/README.md @@ -38,7 +38,7 @@ **Release notes and unreleased changes can be found in the [CHANGELOG](https://github.com/near/near-sdk-rs/blob/master/CHANGELOG.md)** -## Example +## Example. For more information, see the [near](https://docs.rs/near-sdk/latest/near_sdk/attr.near.html) documentation Wrap a struct in `#[near]` and it generates a smart contract compatible with the NEAR blockchain: ```rust diff --git a/near-sdk/src/lib.rs b/near-sdk/src/lib.rs index 47063b567..39dab8644 100644 --- a/near-sdk/src/lib.rs +++ b/near-sdk/src/lib.rs @@ -24,7 +24,7 @@ //! near-sdk = "5.6.0" //! ``` //! -//! ### Example: Counter Smart Contract. For more information, see the [macro@near] documentation. +//! ### Example: Counter Smart Contract. For more information, see the [near] documentation. //! //! Below is an example of a simple counter contract that increments and retrieves a value: //! @@ -102,47 +102,186 @@ extern crate quickcheck; /// to generate the necessary code to expose `pub` methods from the contract as well /// as generating the glue code to be a valid NEAR contract. /// -/// The macro is a syntactic sugar for [macro@near_bindgen] and expands to the [macro@near_bindgen] macro invocations. +/// The macro is a syntactic sugar for [near_bindgen] and expands to the [near_bindgen] macro invocations. +/// Both of them share the same attributes, except for those that are explicitly marked as specific to the [near] macro. ([1](near#nearserializers-annotates-structsenums), [2](near#nearcontract_state-annotates-structsenums)) /// -/// ## Example +/// # Attributes +/// +/// ## `#[near(contract_state)]` (annotates structs/enums) +/// +/// The attribute prepares a struct/enum to be a contract state. Only one contract state is allowed per crate. +/// This attribute is also required to make the [`#[near(contract_metadata(...))]`](near#nearcontract_metadata-annotates-structsenums) attribute work. +/// **The attribute specific to the [near] macro only.** +/// +/// ### Basic example +/// ```rust +/// use near_sdk::near; +/// +/// #[near(contract_state)] +/// pub struct Contract { +/// data: i8, +/// } +/// ``` +/// +/// ## `#[near(serializers=[...])` (annotates structs/enums) +/// +/// The attribute makes the struct or enum serializable with either json or borsh. By default, borsh is used. +/// **The attribute specific to the [near] macro only.** +/// +/// ### Make struct/enum serializable with borsh +/// +/// ```rust +/// use near_sdk::near; +/// +/// #[near(serializers=[borsh])] +/// pub enum MyEnum { +/// Variant1, +/// } +/// +/// #[near(serializers=[borsh])] +/// pub struct MyStruct { +/// pub name: String, +/// } +/// ``` +/// +/// ### Make struct/enum serializable with json +/// +/// ```rust +/// use near_sdk::near; +/// #[near(serializers=[json])] +/// pub enum MyEnum { +/// Variant1, +/// } +/// +/// #[near(serializers=[json])] +/// pub struct MyStruct { +/// pub name: String, +/// } +/// ``` +/// +/// ### Make struct/enum serializable with both borsh and json /// /// ```rust /// use near_sdk::near; +/// #[near(serializers=[borsh, json])] +/// pub enum MyEnum { +/// Variant1, +/// } /// /// #[near(serializers=[borsh, json])] -/// struct MyStruct { -/// pub name: String, +/// pub struct MyStruct { +/// pub name: String, /// } /// ``` /// -/// This macro will generate code to load and deserialize state if the `self` parameter is included -/// as well as saving it back to state if `&mut self` is used. +/// ## `#[serializer(...)]` (annotates function arguments) +/// +/// The attribute makes the function argument serializable with either json or borsh. By default, json is used. +/// Please, note that all the arguments of the function should be using the same serializer. +/// +/// ### Basic example /// -/// # Parameter and result serialization -/// If the macro is used with Impl section, for parameter serialization, this macro will generate a struct with all of the parameters as -/// fields and derive deserialization for it. By default this will be JSON deserialized with `serde` -/// but can be overwritten by using `#[serializer(borsh)]`: /// ```rust /// use near_sdk::near; +///# #[near(contract_state)] +///# pub struct Contract {} /// -/// # #[near(contract_state)] -/// # struct MyContract { -/// # pub name: String, -/// # } +/// #[near] +/// impl Contract { +/// pub fn borsh_arguments(&self, #[serializer(borsh)] a: String, #[serializer(borsh)] b: String) {} +/// } +/// ``` +/// +/// ## `#[init]` (annotates methods of a type in its `impl` block) +/// +/// Contract initialization method annotation. More details can be found [here](https://docs.near.org/build/smart-contracts/anatomy/storage#initializing-the-state) +/// +/// By default, the `Default::default()` implementation of a contract will be used to initialize a contract. +/// There can be a custom initialization function which takes parameters or performs custom logic with the following `#[init]` annotation. +/// +/// You can provide several initialization functions. +/// +/// ### Basic example +/// +/// ```rust +/// use near_sdk::{log, near}; +/// +/// #[near(contract_state)] +/// #[derive(Default)] +/// pub struct Counter { +/// value: u64, +/// } /// /// #[near] -/// impl MyContract { -/// #[result_serializer(borsh)] -/// pub fn borsh_parameters(&self, #[serializer(borsh)] a: String, #[serializer(borsh)] b: String) -> String { -/// format!("{} {}", a, b) -/// } +/// impl Counter { +/// #[init] +/// pub fn new(value: u64) -> Self { +/// log!("Custom counter initialization!"); +/// Self { value } +/// } +/// } +/// ``` +/// +/// ## `#[payable]` (annotates methods of a type in its `impl` block) +/// +/// Specifies that the method can accept NEAR tokens. More details can be found [here](https://docs.near.org/build/smart-contracts/anatomy/functions#payable-functions) +/// +/// Methods can be annotated with `#[payable]` to allow tokens to be transferred with the method invocation. For more information, see payable methods. +/// +/// To declare a function as payable, use the `#[payable]` annotation as follows: +/// +/// ### Basic example +/// +/// ```rust +///use near_sdk::near; +/// +/// #[near(contract_state)] +/// #[derive(Default)] +/// pub struct Counter { +/// val: i8, +/// } +/// +/// #[near] +/// impl Counter { +/// #[payable] +/// pub fn my_method(&mut self) { +/// //... +/// } /// } /// ``` /// -/// `#[near]` will also handle serializing and setting the return value of the -/// function execution based on what type is returned by the function. By default, this will be -/// done through `serde` serialized as JSON, but this can be overridden using -/// `#[result_serializer(borsh)]`: +/// ## `#[private]` (annotates methods of a type in its `impl` block)] +/// +/// The attribute forbids to call the method except from within the contract. +/// This is useful for internal methods that should not be called from outside the contract. +/// +/// More details can be found [here](https://docs.near.org/build/smart-contracts/anatomy/functions#private-functions) +/// +/// ### Basic example +/// +/// ```rust +/// use near_sdk::near; +/// +/// #[near(contract_state)] +/// #[derive(Default)] +/// pub struct Counter { +/// val: u64, +/// } +/// +/// #[near] +/// impl Counter { +/// #[private] +/// pub fn my_method(&mut self) { +/// // ... +/// } +/// } +/// ``` +/// +/// ## `#[result_serializer(...)]` (annotates methods of a type in its `impl` block) +/// +/// The attribute defines the serializer for function return serialization. +/// Only one of `borsh` or `json` can be specified. +/// /// ```rust /// use near_sdk::near; /// @@ -154,49 +293,91 @@ extern crate quickcheck; /// #[near] /// impl MyContract { /// #[result_serializer(borsh)] -/// pub fn borsh_parameters(&self) -> String { -/// self.name.clone() +/// pub fn borsh_return_value(&self) -> String { +/// "hello_world".to_string() /// } /// } /// ``` /// -/// # Usage for enum / struct +/// ## `#[handle_result]` (annotates methods of a type in its `impl` block) /// -/// If the macro is used with struct or enum, it will make the struct or enum serializable with either -/// Borsh or Json depending on serializers passed. Use `#[near(serializers=[borsh])]` to make it serializable with Borsh. -/// Or use `#[near(serializers=[json])]` to make it serializable with Json. By default, borsh is used. -/// You can also specify both and none. BorshSchema or JsonSchema are always generated if respective serializer is toggled on. +/// Have `#[handle_result]` to Support Result types regardless of how they're referred to +/// Function marked with `#[handle_result]` should return `Result` (where E implements [FunctionError]). +/// If you're trying to use a type alias for `Result`, try `#[handle_result(aliased)]` /// -/// If you want the struct/enum to be a contract state, you can pass in the contract_state argument. +/// ### Basic error handling with Result /// -/// ## Example /// ```rust -/// use near_sdk::near; +/// use near_sdk::{near, AccountId, Promise, PromiseError}; /// /// #[near(contract_state)] -/// pub struct Contract { -/// data: i8, +/// #[derive(Default)] +/// pub struct Counter { +/// val: u64, /// } /// /// #[near] -/// impl Contract { -/// pub fn some_function(&self) {} +/// impl Counter { +/// #[handle_result] +/// pub fn some_function2( +/// &self, +/// ) -> Result<(), &'static str> { +/// Err("error") +/// } /// } /// ``` /// -/// # Events Standard: +/// ### Typed error handling /// -/// By passing `event_json` as an argument `near_bindgen` will generate the relevant code to format events +/// This example shows how to use error handling in a contract when the error are defined in the contract. +/// This way the contract can utilize result types and panic with the type using its [ToString] implementation +/// +/// ```rust +/// use near_sdk::{near, FunctionError}; +/// +/// #[derive(FunctionError)] +/// pub enum MyError { +/// SomePanicError, +/// } +/// +/// impl std::fmt::Display for MyError { +/// fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { +/// match self { +/// MyError::SomePanicError => write!(f, "Panic error message that would be displayed to the user"), +/// } +/// } +/// } +///# #[near(contract_state)] +///# #[derive(Default)] +///# pub struct Counter { +///# val: u64, +///# } +/// +/// #[near] +/// impl Counter { +/// #[handle_result] +/// pub fn some_function(&self) -> Result<(), MyError> { +/// if self.val == 0 { +/// return Err(MyError::SomePanicError); +/// } +/// Ok(()) +/// } +/// } +/// ``` +/// +/// ## `#[near(event_json(...))]` (annotates enums) +/// +/// By passing `event_json` as an argument `near` will generate the relevant code to format events /// according to [NEP-297](https://github.com/near/NEPs/blob/master/neps/nep-0297.md) /// -/// For parameter serialization, this macro will generate a wrapper struct to include the NEP-297 standard fields `standard` and `version +/// For parameter serialization, this macro will generate a wrapper struct to include the NEP-297 standard fields `standard` and `version` /// as well as include serialization reformatting to include the `event` and `data` fields automatically. /// The `standard` and `version` values must be included in the enum and variant declaration (see example below). /// By default this will be JSON deserialized with `serde` /// /// The version is required to allow backward compatibility. The older back-end will use the version field to determine if the event is supported. /// -/// ## Examples +/// ### Basic example /// /// ```rust /// use near_sdk::{near, AccountId}; @@ -205,8 +386,6 @@ extern crate quickcheck; /// # pub struct Contract { /// # data: i8, /// # } -/// -/// /// #[near(event_json(standard = "nepXXX"))] /// pub enum MyEvents { /// #[event_version("1.0.0")] @@ -230,7 +409,7 @@ extern crate quickcheck; /// } /// ``` /// -/// # Contract Source Metadata Standard: +/// ## `#[near(contract_metadata(...))]` (annotates structs/enums) /// /// By using `contract_metadata` as an argument `near` will populate the contract metadata /// according to [`NEP-330`]() standard. This still applies even when `#[near]` is used without @@ -239,17 +418,19 @@ extern crate quickcheck; /// All fields(version, link) are optional and will be populated with defaults from the Cargo.toml file if not specified. /// The `standard` will be populated with `nep330` by default. /// -/// Any additional standards can be added and should be specified using the `standard` sub-attribute. +/// Any additional standards can be added and should be specified using the `standard` attribute. /// /// The `contract_source_metadata()` view function will be added and can be used to retrieve the source metadata. /// Also, the source metadata will be stored as a constant, `CONTRACT_SOURCE_METADATA`, in the contract code. /// -/// ## Examples +/// **Please note that the `contract_metadata` will be ignored if [`#[near(contract_state)]`](near#nearcontract_state-annotates-structsenums) is not used**. +/// +/// ### Basic example /// /// ```rust /// use near_sdk::near; /// -/// #[near(contract_metadata( +/// #[near(contract_state, contract_metadata( /// version = "39f2d2646f2f60e18ab53337501370dc02a5661c", /// link = "https://github.com/near-examples/nft-tutorial", /// standard(standard = "nep171", version = "1.0.0"), @@ -259,7 +440,7 @@ extern crate quickcheck; /// ``` pub use near_sdk_macros::near; -/// This macro is deprecated. Use [macro@near] instead. The difference between `#[near]` and `#[near_bindgen]` is that +/// This macro is deprecated. Use [near] instead. The difference between `#[near]` and `#[near_bindgen]` is that /// with `#[near_bindgen]` you have to manually add boilerplate code for structs and enums so that they become Json- and Borsh-serializable: /// ```rust /// use near_sdk::{near_bindgen, NearSchema, borsh::{BorshSerialize, BorshDeserialize}}; @@ -366,7 +547,7 @@ pub use near_sdk_macros::BorshStorageKey; pub use near_sdk_macros::PanicOnDefault; /// NOTE: This is an internal implementation for `#[near_bindgen(events(standard = ...))]` attribute. -/// Please use [macro@near] instead. +/// Please use [near] instead. /// /// This derive macro is used to inject the necessary wrapper and logic to auto format /// standard event logs and generate the `emit` function, and event version. @@ -391,7 +572,7 @@ pub use near_sdk_macros::EventMetadata; pub use near_sdk_macros::NearSchema; /// `FunctionError` generates implementation for `near_sdk::FunctionError` trait. -/// It allows contract runtime to panic with the type using its `ToString` implementation +/// It allows contract runtime to panic with the type using its [ToString] implementation /// as the message. /// ## Example /// ```rust @@ -461,7 +642,7 @@ pub use crate::utils::storage_key_impl::IntoStorageKey; pub use crate::utils::*; #[cfg(feature = "__macro-docs")] -pub mod near; +pub mod near_annotations; #[cfg(all(feature = "unit-testing", not(target_arch = "wasm32")))] pub mod test_utils; diff --git a/near-sdk/src/near.rs b/near-sdk/src/near.rs deleted file mode 100644 index 13a57426e..000000000 --- a/near-sdk/src/near.rs +++ /dev/null @@ -1,147 +0,0 @@ -//! `#[near]` and `#[near_bindgen]` documentation module -//! -//! This is not a real module; here we document the attributes that [`#[near]`](../attr.near.html) -//! and [`#[near_bindgen]`](../attr.near_bindgen.html) macro use. - -/// Initialization Methods inner [`#[near]`](../attr.near.html) annotation. More details can be found [here](https://docs.near.org/sdk/rust/contract-structure/near-bindgen#initialization-methods) -/// -/// By default, the `Default::default()` implementation of a contract will be used to initialize a contract. There can be a custom initialization function which takes parameters or performs custom logic with the following `#[init]` annotation: -/// # Examples -/// -/// ## Basic example -/// -/// ```rust -/// use near_sdk::{log, near}; -/// -/// #[near(contract_state)] -/// #[derive(Default)] -/// pub struct Counter { -/// value: u64, -/// } -/// -/// #[near] -/// impl Counter { -/// #[init] -/// pub fn new(value: u64) -> Self { -/// log!("Custom counter initialization!"); -/// Self { value } -/// } -/// } -/// ``` -pub fn init() {} - -/// Payable Methods inner [`#[near]`](../attr.near.html) annotation. More details can be found [here](https://docs.near.org/sdk/rust/contract-structure/near-bindgen#payable-methods) -/// -/// Methods can be annotated with `#[payable]` to allow tokens to be transferred with the method invocation. For more information, see payable methods. -/// -/// To declare a function as payable, use the `#[payable]` annotation as follows: -/// # Examples -/// -/// ## Basic example -/// -/// ```rust -///use near_sdk::near; -/// -/// #[near(contract_state)] -/// #[derive(Default)] -/// pub struct Counter { -/// val: i8, -/// } -/// -/// #[near] -/// impl Counter { -/// #[payable] -/// pub fn my_method(&mut self) { -/// //... -/// } -/// } -/// ``` -pub fn payable() {} - -/// Private Methods inner [`#[near]`](../attr.near.html) annotation. More details can be found [here](https://docs.near.org/sdk/rust/contract-structure/near-bindgen#private-methods) -/// -/// Some methods need to be exposed to allow the contract to call a method on itself through a promise, but want to disallow any other contract to call it. For this, use the `#[private]` annotation to panic when this method is called externally. See [private methods](https://docs.near.org/sdk/rust/contract-interface/private-methods) for more information. -/// -/// This annotation can be applied to any method through the following: -/// # Examples -/// -/// ## Basic example -/// -/// ```rust -/// use near_sdk::near; -/// -/// #[near(contract_state)] -/// #[derive(Default)] -/// pub struct Counter { -/// val: u64, -/// } -/// -/// #[near] -/// impl Counter { -/// #[private] -/// pub fn my_method(&mut self) { -/// // ... -/// } -/// } -/// ``` -pub fn private() {} - -/// Result serialization inner [`#[near]`](../attr.near.html) annotation. -/// -/// Only one of `borsh` or `json` can be specified. -/// -/// # Examples -/// -/// ## Basic example -/// -/// ```rust -/// use near_sdk::near; -/// -/// #[near(contract_state)] -/// #[derive(Default)] -/// pub struct Counter { -/// val: u64, -/// } -/// -/// #[near] -/// impl Counter { -/// #[result_serializer(borsh)] -/// pub fn add_borsh(&self, #[serializer(borsh)] _a: Vec) { -/// // .. -/// } -/// } -/// ``` -pub fn result_serializer() {} - -/// Support Result types regardless of how they're referred to inner [`#[near]`](../attr.near.html) annotation. -/// -/// Have `#[handle_result]` to Support Result types regardless of how they're referred to -/// Function marked with `#[handle_result]` should return `Result (where E implements FunctionError)`. If you're trying to use a type alias for `Result`, try `#[handle_result(aliased)]` -/// -/// # Examples -/// -/// ## Basic example -/// -/// ```rust -/// use near_sdk::{near, AccountId, Promise, PromiseError}; -/// -/// #[near(contract_state)] -/// #[derive(Default)] -/// pub struct Counter { -/// val: u64, -/// } -/// -/// #[near] -/// impl Counter { -/// #[handle_result] -/// pub fn get_result( -/// &self, -/// account_id: AccountId, -/// #[callback_result] set_status_result: Result<(), PromiseError>, -/// ) -> Result<(), &'static str> { -/// // .. -/// Ok(()) -/// } -/// } -/// ``` -pub fn handle_result() {} diff --git a/near-sdk/src/near_annotations.rs b/near-sdk/src/near_annotations.rs new file mode 100644 index 000000000..1dca4a56c --- /dev/null +++ b/near-sdk/src/near_annotations.rs @@ -0,0 +1,47 @@ +//! `#[near]` and `#[near_bindgen]` documentation module +//! +//! This is not a real module; here we document the attributes that [`#[near]`](crate::near) +//! and [`#[near_bindgen]`](crate::near_bindgen) macro use. +//! +//! `near_bindgen` and `near_sdk` shares almost the same attributes: +//! * init +//! * payable +//! * private +//! * handle_result +//! * event_json +//! * contract_metadata +//! * serializer +//! +//! These attributes are only part of the `near` macro. +//! * serializers +//! * contract_state + +/// See [`near_sdk::near #[init]`](crate::near#init-annotates-methods-of-a-type-in-its-impl-block) +pub fn init() {} + +/// See [`near_sdk::near #[payable]`](crate::near#payable-annotates-methods-of-a-type-in-its-impl-block) +pub fn payable() {} + +/// See [`near_sdk::near #[private]`](crate::near#private-annotates-methods-of-a-type-in-its-impl-block) +pub fn private() {} + +/// See [`near_sdk::near #[result_serializer]`](crate::near#result_serializer-annotates-methods-of-a-type-in-its-impl-block) +pub fn result_serializer() {} + +/// See [`near_sdk::near #[handle_result]`](crate::near#handle_result-annotates-methods-of-a-type-in-its-impl-block) +pub fn handle_result() {} + +/// See [`near_sdk::near #[near(event_json(...))]`](crate::near#nearevent_json-annotates-enums) +pub fn event_json() {} + +/// See [`near_sdk::near #[near(contract_metadata(...))]`](crate::near#nearcontract_metadata-annotates-structsenums) +pub fn contract_metadata() {} + +/// See [`near_sdk::near #[serializer(...)]`](crate::near#serializer-annotates-function-arguments) +pub fn serializer() {} + +/// See [`near_sdk::near #[near(serializers=[...])]`](crate::near#nearserializers-annotates-structsenums) +pub fn serializers() {} + +/// See [`near_sdk::near #[near(contract_state)]`](crate::near#nearcontract_state-annotates-structsenums) +pub fn contract_state() {}