pallet_paged_list/lib.rs
1// This file is part of Substrate.
2
3// Copyright (C) Parity Technologies (UK) Ltd.
4// SPDX-License-Identifier: Apache-2.0
5
6// Licensed under the Apache License, Version 2.0 (the "License");
7// you may not use this file except in compliance with the License.
8// You may obtain a copy of the License at
9//
10// http://www.apache.org/licenses/LICENSE-2.0
11//
12// Unless required by applicable law or agreed to in writing, software
13// distributed under the License is distributed on an "AS IS" BASIS,
14// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15// See the License for the specific language governing permissions and
16// limitations under the License.
17
18//! > Made with *Substrate*, for *DotSama*.
19//!
20//! [![github]](https://github.com/paritytech/substrate/frame/fast-unstake) -
21//! [![polkadot]](https://polkadot.com)
22//!
23//! [polkadot]: https://img.shields.io/badge/polkadot-E6007A?style=for-the-badge&logo=polkadot&logoColor=white
24//! [github]: https://img.shields.io/badge/github-8da0cb?style=for-the-badge&labelColor=555555&logo=github
25//!
26//! # Paged List Pallet
27//!
28//! A thin wrapper pallet around a [`paged_list::StoragePagedList`]. It provides an API for a single
29//! paginated list. It can be instantiated multiple times to provide multiple lists.
30//!
31//! ## Overview
32//!
33//! The pallet is quite unique since it does not expose any `Call`s, `Error`s or `Event`s. All
34//! interaction goes through the implemented
35//! [`StorageList`][frame::deps::frame_support::storage::StorageList] trait.
36//!
37//! A fuzzer for testing is provided in crate `pallet-paged-list-fuzzer`.
38//!
39//! ## Examples
40//!
41//! 1. **Appending** some data to the list can happen either by [`Pallet::append_one`]:
42#![doc = docify::embed!("src/tests.rs", append_one_works)]
43//! 2. or by [`Pallet::append_many`]. This should always be preferred to repeated calls to
44//! [`Pallet::append_one`]:
45#![doc = docify::embed!("src/tests.rs", append_many_works)]
46//! 3. If you want to append many values (ie. in a loop), then best use the [`Pallet::appender`]:
47#![doc = docify::embed!("src/tests.rs", appender_works)]
48//! 4. **Iterating** over the list can be done with [`Pallet::iter`]. It uses the standard
49//! `Iterator` trait:
50#![doc = docify::embed!("src/tests.rs", iter_works)]
51//! 5. **Draining** elements happens through the [`Pallet::drain`] iterator. Note that even
52//! *peeking* a value will already remove it.
53#![doc = docify::embed!("src/tests.rs", drain_works)]
54//!
55//! ## Pallet API
56//!
57//! None. Only things to consider is the [`Config`] traits.
58//!
59//! ## Low Level / Implementation Details
60//!
61//! Implementation details are documented in [`paged_list::StoragePagedList`].
62//! All storage entries are prefixed with a unique prefix that is generated by [`ListPrefix`].
63
64#![cfg_attr(not(feature = "std"), no_std)]
65
66pub use pallet::*;
67
68pub mod mock;
69mod paged_list;
70mod tests;
71
72extern crate alloc;
73
74use codec::FullCodec;
75use frame::{prelude::*, traits::StorageInstance};
76pub use paged_list::StoragePagedList;
77
78#[frame::pallet]
79pub mod pallet {
80 use super::*;
81
82 #[pallet::pallet]
83 pub struct Pallet<T, I = ()>(_);
84
85 #[pallet::config]
86 pub trait Config<I: 'static = ()>: frame_system::Config {
87 /// The value type that can be stored in the list.
88 type Value: FullCodec;
89
90 /// The number of values that can be put into newly created pages.
91 ///
92 /// Note that this does not retroactively affect already created pages. This value can be
93 /// changed at any time without requiring a runtime migration.
94 #[pallet::constant]
95 type ValuesPerNewPage: Get<u32>;
96 }
97
98 /// A storage paged list akin to what the FRAME macros would generate.
99 // Note that FRAME does natively support paged lists in storage.
100 pub type List<T, I> = StoragePagedList<
101 ListPrefix<T, I>,
102 <T as Config<I>>::Value,
103 <T as Config<I>>::ValuesPerNewPage,
104 >;
105}
106
107// This exposes the list functionality to other pallets.
108impl<T: Config<I>, I: 'static> StorageList<T::Value> for Pallet<T, I> {
109 type Iterator = <List<T, I> as StorageList<T::Value>>::Iterator;
110 type Appender = <List<T, I> as StorageList<T::Value>>::Appender;
111
112 fn iter() -> Self::Iterator {
113 List::<T, I>::iter()
114 }
115
116 fn drain() -> Self::Iterator {
117 List::<T, I>::drain()
118 }
119
120 fn appender() -> Self::Appender {
121 List::<T, I>::appender()
122 }
123}
124
125/// Generates a unique storage prefix for each instance of the pallet.
126pub struct ListPrefix<T, I>(core::marker::PhantomData<(T, I)>);
127
128impl<T: Config<I>, I: 'static> StorageInstance for ListPrefix<T, I> {
129 fn pallet_prefix() -> &'static str {
130 crate::Pallet::<T, I>::name()
131 }
132
133 const STORAGE_PREFIX: &'static str = "paged_list";
134}