diff --git a/src/pages/cw-storage-plus/containers/deque.mdx b/src/pages/cw-storage-plus/containers/deque.mdx index 69d005b8..7f6d19c6 100644 --- a/src/pages/cw-storage-plus/containers/deque.mdx +++ b/src/pages/cw-storage-plus/containers/deque.mdx @@ -6,86 +6,136 @@ import { Callout } from "nextra/components"; # `Deque` -A `Deque` imitates a traditional double-ended queue. This collection is designed -for efficient pushes and pops from either the beginning or end, but not for -insertions/deletions from the middle. It can easily serve as a queue or stack. +A `Deque` is a container that imitates a traditional double-ended queue. It's +designed for efficient pushes and pops from either the beginning or end, making +it suitable for use as a queue or stack. However, it's not optimized for +insertions or deletions from the middle. -The main operations available here are [`push_back`], [`push_front`], +More information can be found in the [API docs]. + +## Deque operations + +The main operations available for a `Deque` are [`push_back`], [`push_front`], [`pop_back`], and [`pop_front`]. It is also possible to check the [`len`]gth of the deque, [`get`] an element by index, and [`iter`]ate over the elements. - -[`push_back`]: - https://docs.rs/cw-storage-plus/latest/cw_storage_plus/struct.Deque.html#method.push_back +{/* Links to make the above operations clickable */} [`push_back`]: +https://docs.rs/cw-storage-plus/latest/cw_storage_plus/struct.Deque.html#method.push_back [`push_front`]: - https://docs.rs/cw-storage-plus/latest/cw_storage_plus/struct.Deque.html#method.push_front +https://docs.rs/cw-storage-plus/latest/cw_storage_plus/struct.Deque.html#method.push_front [`pop_back`]: - https://docs.rs/cw-storage-plus/latest/cw_storage_plus/struct.Deque.html#method.pop_back +https://docs.rs/cw-storage-plus/latest/cw_storage_plus/struct.Deque.html#method.pop_back [`pop_front`]: - https://docs.rs/cw-storage-plus/latest/cw_storage_plus/struct.Deque.html#method.pop_front +https://docs.rs/cw-storage-plus/latest/cw_storage_plus/struct.Deque.html#method.pop_front [`len`]: - https://docs.rs/cw-storage-plus/latest/cw_storage_plus/struct.Deque.html#method.len +https://docs.rs/cw-storage-plus/latest/cw_storage_plus/struct.Deque.html#method.len [`get`]: - https://docs.rs/cw-storage-plus/latest/cw_storage_plus/struct.Deque.html#method.get +https://docs.rs/cw-storage-plus/latest/cw_storage_plus/struct.Deque.html#method.get [`iter`]: - https://docs.rs/cw-storage-plus/latest/cw_storage_plus/struct.Deque.html#method.iter +https://docs.rs/cw-storage-plus/latest/cw_storage_plus/struct.Deque.html#method.iter + +- `push_back`: Adds an element to the end of the deque. O(1) time complexity. + [Source](https://docs.rs/cw-storage-plus/latest/cw_storage_plus/struct.Deque.html#method.push_back) +- `push_front`: Adds an element to the beginning of the deque. O(1) time + complexity. + [Source](https://docs.rs/cw-storage-plus/latest/cw_storage_plus/struct.Deque.html#method.push_front) +- `pop_back`: Removes and returns the last element. Returns `None` if the deque + is empty. O(1) time complexity. + [Source](https://docs.rs/cw-storage-plus/latest/cw_storage_plus/struct.Deque.html#method.pop_back) +- `pop_front`: Removes and returns the first element. Returns `None` if the + deque is empty. O(1) time complexity. + [Source](https://docs.rs/cw-storage-plus/latest/cw_storage_plus/struct.Deque.html#method.pop_front) +- `len`: Returns the number of elements in the deque. O(1) time complexity. + [Source](https://docs.rs/cw-storage-plus/latest/cw_storage_plus/struct.Deque.html#method.len) +- `is_empty`: Returns `true` if the deque contains no elements. O(1) time + complexity. + [Source](https://docs.rs/cw-storage-plus/latest/cw_storage_plus/struct.Deque.html#method.is_empty) +- `get`: Retrieves an element by index. Returns `None` if the index is out of + bounds. O(1) time complexity. + [Source](https://docs.rs/cw-storage-plus/latest/cw_storage_plus/struct.Deque.html#method.get) +- `front`: Returns a reference to the first element without removing it. Returns + `None` if the deque is empty. + [Source](https://docs.rs/cw-storage-plus/latest/cw_storage_plus/struct.Deque.html#method.front) +- `back`: Returns a reference to the last element without removing it. Returns + `None` if the deque is empty. + [Source](https://docs.rs/cw-storage-plus/latest/cw_storage_plus/struct.Deque.html#method.back) +- `iter`: Returns an iterator over the elements of the deque. + [Source](https://docs.rs/cw-storage-plus/latest/cw_storage_plus/struct.Deque.html#method.iter) - The maximum capacity of a `Deque` is `u32::MAX - 1` elements. Trying to push - more elements is considered Undefined Behaviorđź’€. + The maximum capacity of a `Deque` is `u32::MAX - 1` elements. Attempting to + push more elements is considered Undefined Behavior. -More information can be found in the -[API docs](https://docs.rs/cw-storage-plus/latest/cw_storage_plus/struct.Deque.html). +## Deque lifecycle -## Examples +Creating a `Deque` doesn't immediately commit anything to storage. To add +elements to the deque, you need to use the `push_back` or `push_front` methods. -### Pushing and popping +Values in a `Deque` must implement the `Serialize` and `Deserialize` traits from +the [`serde`] crate to be stored. + +### Lifecycle example ```rust template="storage" use cw_storage_plus::Deque; +// Create a new deque. It doesn't exist in storage yet. let deque: Deque = Deque::new("d"); +assert_eq!(deque.len(&storage).unwrap(), 0); +// Add elements to the deque deque.push_back(&mut storage, &2).unwrap(); deque.push_back(&mut storage, &3).unwrap(); deque.push_front(&mut storage, &1).unwrap(); -// at this point, we have [1, 2, 3] +// Check the length +assert_eq!(deque.len(&storage).unwrap(), 3); +// Remove elements assert_eq!(deque.pop_back(&mut storage).unwrap(), Some(3)); assert_eq!(deque.pop_front(&mut storage).unwrap(), Some(1)); -assert_eq!(deque.pop_back(&mut storage).unwrap(), Some(2)); -assert_eq!(deque.pop_back(&mut storage).unwrap(), None); + +// Check the final state +assert_eq!(deque.len(&storage).unwrap(), 1); +assert_eq!(deque.get(&storage, 0).unwrap(), Some(2)); ``` -### Checking length +## Usage examples + +### Using Deque as a queue ```rust template="storage" use cw_storage_plus::Deque; -let deque: Deque = Deque::new("d"); - -assert_eq!(deque.len(&storage).unwrap(), 0); +let queue: Deque = Deque::new("q"); -deque.push_back(&mut storage, &1).unwrap(); -deque.push_back(&mut storage, &2).unwrap(); +// Enqueue elements +queue.push_back(&mut storage, &"first".to_string()).unwrap(); +queue.push_back(&mut storage, &"second".to_string()).unwrap(); -assert_eq!(deque.len(&storage).unwrap(), 2); +// Dequeue elements +assert_eq!(queue.pop_front(&mut storage).unwrap(), Some("first".to_string())); +assert_eq!(queue.pop_front(&mut storage).unwrap(), Some("second".to_string())); +assert_eq!(queue.pop_front(&mut storage).unwrap(), None); ``` -### Getting an element by index +### Using Deque as a stack ```rust template="storage" use cw_storage_plus::Deque; -let deque: Deque = Deque::new("d"); +let stack: Deque = Deque::new("s"); -deque.push_back(&mut storage, &1).unwrap(); -deque.push_back(&mut storage, &2).unwrap(); +// Push elements +stack.push_back(&mut storage, &1).unwrap(); +stack.push_back(&mut storage, &2).unwrap(); +stack.push_back(&mut storage, &3).unwrap(); -assert_eq!(deque.get(&storage, 0).unwrap(), Some(1)); -assert_eq!(deque.get(&storage, 1).unwrap(), Some(2)); -assert_eq!(deque.get(&storage, 2).unwrap(), None); +// Pop elements +assert_eq!(stack.pop_back(&mut storage).unwrap(), Some(3)); +assert_eq!(stack.pop_back(&mut storage).unwrap(), Some(2)); +assert_eq!(stack.pop_back(&mut storage).unwrap(), Some(1)); +assert_eq!(stack.pop_back(&mut storage).unwrap(), None); ``` ### Iterating over elements @@ -95,14 +145,60 @@ use cw_storage_plus::Deque; let deque: Deque = Deque::new("d"); +deque.push_back(&mut storage, &1).unwrap(); deque.push_back(&mut storage, &2).unwrap(); deque.push_back(&mut storage, &3).unwrap(); -deque.push_front(&mut storage, &1).unwrap(); -let mut iter = deque.iter(&storage).unwrap(); +let sum: u32 = deque.iter(&storage).unwrap().map(|r| r.unwrap()).sum(); +assert_eq!(sum, 6); +``` -assert_eq!(iter.next(), Some(Ok(1))); -assert_eq!(iter.next(), Some(Ok(2))); -assert_eq!(iter.next(), Some(Ok(3))); -assert_eq!(iter.next(), None); +### Maintaining a log store + +It is possible to use a `Deque` to maintain a store of log events or transaction +records. This is useful when you want to keep a history of production level +events to ease in debugging a deployed instance of a contract. + +```rust template="storage" +use cw_storage_plus::Deque; +use serde::{Serialize, Deserialize}; + +#[derive(Serialize, Deserialize, Clone, Debug, PartialEq)] +struct Log { + block_height: u64, + sender_addr: String, + event: String, +} + +// Initialize the Deque for storing logs +let logs: Deque = Deque::new("logs"); + +// Simulating contract execution context +let env = mock_env(); +let info = mock_info("sender", &[]); +let event = "funds_transferred".to_string(); + +// Add a new log entry +logs.push_front( + &mut storage, + &Log { + block_height: env.block.height, + sender_addr: info.sender.to_string(), + event: event.clone(), + }, +).unwrap(); + +// Optionally, limit the number of stored logs +const MAX_LOGS: u32 = 100; +if logs.len(&storage).unwrap() > MAX_LOGS { + logs.pop_back(&mut storage).unwrap(); +} + +// Retrieve the most recent log +let latest_log = logs.get(&storage, 0).unwrap().unwrap(); +assert_eq!(latest_log.event, "funds_transferred"); ``` + +[`serde`]: https://serde.rs/ +[API docs]: + https://docs.rs/cw-storage-plus/latest/cw_storage_plus/struct.Deque.html