diff --git a/listings/getting-started/cairo_cheatsheet/src/enum_example.cairo b/listings/getting-started/cairo_cheatsheet/src/enum_example.cairo new file mode 100644 index 00000000..5e632ee6 --- /dev/null +++ b/listings/getting-started/cairo_cheatsheet/src/enum_example.cairo @@ -0,0 +1,83 @@ +// ANCHOR: enums +#[derive(Drop, Serde, Copy, starknet::Store)] +struct Position { + x: u32, + y: u32, +} + +#[derive(Drop, Serde, Copy, starknet::Store)] +enum UserCommand { + Login, + UpdateProfile, + Logout, +} + +#[derive(Drop, Serde, Copy, starknet::Store)] +enum Action { + Quit, + Move: Position, + SendMessage: felt252, + ChangeAvatarColor: (u8, u8, u8), + ProfileState: UserCommand +} +// ANCHOR_END: enums + +// ANCHOR: enum_contract +#[starknet::interface] +trait IEnumContract { + fn register_action(ref self: TContractState, action: Action); + fn generate_default_actions_list(self: @TContractState) -> Array; +} + +#[starknet::contract] +mod EnumContract { + use core::clone::Clone; + use core::traits::Into; + use super::IEnumContract; + use super::{Action, Position, UserCommand}; + + #[storage] + struct Storage { + most_recent_action: Action, + } + + #[abi(embed_v0)] + impl IEnumContractImpl of IEnumContract { + fn register_action(ref self: ContractState, action: Action) { + // quick note: match takes ownership of variable (but enum Action implements Copy trait) + match action { + Action::Quit => { println!("Quit"); }, + Action::Move(value) => { println!("Move with x: {} and y: {}", value.x, value.y); }, + Action::SendMessage(msg) => { println!("Write with message: {}", msg); }, + Action::ChangeAvatarColor(( + r, g, b + )) => { println!("Change color to r: {}, g: {}, b: {}", r, g, b); }, + Action::ProfileState(state) => { + let profile_state = match state { + UserCommand::Login => 1, + UserCommand::UpdateProfile => 2, + UserCommand::Logout => 3, + }; + println!("profile_state: {}", profile_state); + } + }; + + self.most_recent_action.write(action); + } + + fn generate_default_actions_list(self: @ContractState) -> Array { + let actions = array![ + Action::Quit, + Action::Move(Position { x: 1, y: 2 }), + Action::SendMessage('here is my message'), + Action::ChangeAvatarColor((1, 2, 3)), + Action::ProfileState(UserCommand::Login), + ]; + + actions + } + } +} +// ANCHOR_END: enum_contract + + diff --git a/listings/getting-started/cairo_cheatsheet/src/lib.cairo b/listings/getting-started/cairo_cheatsheet/src/lib.cairo index 63b38485..b495fd77 100644 --- a/listings/getting-started/cairo_cheatsheet/src/lib.cairo +++ b/listings/getting-started/cairo_cheatsheet/src/lib.cairo @@ -3,6 +3,7 @@ mod mapping_example; mod felt_example; mod loop_example; mod while_example; +mod enum_example; mod match_example; mod struct_example; mod type_casting_example; diff --git a/src/SUMMARY.md b/src/SUMMARY.md index 4f948385..f76fdac3 100644 --- a/src/SUMMARY.md +++ b/src/SUMMARY.md @@ -35,6 +35,7 @@ Summary - [while](./ch00/cairo_cheatsheet/while.md) - [if let](./ch00/cairo_cheatsheet/if_let.md) - [while let](./ch00/cairo_cheatsheet/while_let.md) + - [Enums](./ch00/cairo_cheatsheet/enums.md) - [Match](./ch00/cairo_cheatsheet/match.md) - [Tuples](./ch00/cairo_cheatsheet/tuples.md) - [Struct](./ch00/cairo_cheatsheet/struct.md) diff --git a/src/ch00/cairo_cheatsheet/enums.md b/src/ch00/cairo_cheatsheet/enums.md new file mode 100644 index 00000000..ba5694fe --- /dev/null +++ b/src/ch00/cairo_cheatsheet/enums.md @@ -0,0 +1,27 @@ +# Enums + +Just like other programming languages, enums (enumerations) are used in cairo to define variables that can only hold a set of predefined variants (= enum options), enhancing code readability and safety. They facilitate strong type checking and are ideal for organizing related options and supporting structured logic through pattern matching for example, which is also described in the next chapter. + +In cairo, `enum variants` can hold different data types (the unit type, structs, other enums, tuples, default core library types, arrays, dictionaries, ...), as shown in the code snippet below. Furthermore, as a quick reminder, enums are expressions, meaning they can return values. + +```rust +{{#include ../../../listings/getting-started/cairo_cheatsheet/src/enum_example.cairo:enums}} +``` + +Enums can be declared both inside and outside a contract. If declared outside, they need to be imported inside using the `use` keyword, just like other imports. + +1. Storing enums in contract + + - It is possible to store `enums` in the contract storage. But unlike most of the core library types which implement the `Store` trait, enums are custom types and therefore do not automatically implement the `Store` trait. The enum as well as all of its variants have to explicitly implement the `Store` trait in order for it to be stored inside a contract storage. + + - If all of its variants implement the `Store` trait, implementing the `Store` trait on the enum is as simple as deriving it, using `#[derive(starknet::Store)]` (as shown in example above). If not, the `Store` trait has to be manually implemented -- see an example of manually implementing the `Store` trait for a complex type in chapter [Storing Arrays](https://starknet-by-example.voyager.online/ch02/storing_arrays.html). + +2. Enums as parameters and return values to entrypoints + + - It is possible to pass `enums` to contract entrypoints as parameters, as well as return them from entrypoints. For that purpose, the enum needs to be serializable and dropable, hence the derivation of traits `Serde` and `Drop` in the above code snippet. + +Here is an example of a contract illustrating the above statements : + +```rust +{{#include ../../../listings/getting-started/cairo_cheatsheet/src/enum_example.cairo:enum_contract}} +```