referrerpolicy=no-referrer-when-downgrade

frame_support/storage/types/
mod.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//! Storage types to build abstraction on storage, they implements storage traits such as
19//! StorageMap and others.
20
21use alloc::vec::Vec;
22use codec::FullCodec;
23use sp_metadata_ir::{StorageEntryMetadataIR, StorageEntryModifierIR};
24
25mod counted_map;
26mod counted_nmap;
27mod double_map;
28mod key;
29mod map;
30mod nmap;
31mod value;
32
33pub use counted_map::{CountedStorageMap, CountedStorageMapInstance, Counter};
34pub use counted_nmap::{CountedStorageNMap, CountedStorageNMapInstance};
35pub use double_map::StorageDoubleMap;
36pub use key::{
37	EncodeLikeTuple, HasKeyPrefix, HasReversibleKeyPrefix, Key, KeyGenerator,
38	KeyGeneratorMaxEncodedLen, ReversibleKeyGenerator, TupleToEncodedIter,
39};
40pub use map::StorageMap;
41pub use nmap::StorageNMap;
42pub use value::StorageValue;
43
44/// Trait implementing how the storage optional value is converted into the queried type.
45///
46/// It is implemented most notable by:
47///
48/// * [`OptionQuery`] which converts an optional value to an optional value, used when querying
49///   storage returns an optional value.
50/// * [`ResultQuery`] which converts an optional value to a result value, used when querying storage
51///   returns a result value.
52/// * [`ValueQuery`] which converts an optional value to a value, used when querying storage returns
53///   a value.
54///
55/// ## Example
56#[doc = docify::embed!("src/storage/types/mod.rs", value_query_examples)]
57pub trait QueryKindTrait<Value, OnEmpty> {
58	/// Metadata for the storage kind.
59	const METADATA: StorageEntryModifierIR;
60
61	/// Type returned on query
62	type Query: FullCodec + 'static;
63
64	/// Convert an optional value (i.e. some if trie contains the value or none otherwise) to the
65	/// query.
66	fn from_optional_value_to_query(v: Option<Value>) -> Self::Query;
67
68	/// Convert a query to an optional value.
69	fn from_query_to_optional_value(v: Self::Query) -> Option<Value>;
70}
71
72/// Implements [`QueryKindTrait`] with `Query` type being `Option<_>`.
73///
74/// NOTE: it doesn't support a generic `OnEmpty`. This means only `None` can be returned when no
75/// value is found. To use another `OnEmpty` implementation, `ValueQuery` can be used instead.
76pub struct OptionQuery;
77impl<Value> QueryKindTrait<Value, crate::traits::GetDefault> for OptionQuery
78where
79	Value: FullCodec + 'static,
80{
81	const METADATA: StorageEntryModifierIR = StorageEntryModifierIR::Optional;
82
83	type Query = Option<Value>;
84
85	fn from_optional_value_to_query(v: Option<Value>) -> Self::Query {
86		// NOTE: OnEmpty is fixed to GetDefault, thus it returns `None` on no value.
87		v
88	}
89
90	fn from_query_to_optional_value(v: Self::Query) -> Option<Value> {
91		v
92	}
93}
94
95/// Implements [`QueryKindTrait`] with `Query` type being `Result<Value, PalletError>`.
96pub struct ResultQuery<Error>(core::marker::PhantomData<Error>);
97impl<Value, Error, OnEmpty> QueryKindTrait<Value, OnEmpty> for ResultQuery<Error>
98where
99	Value: FullCodec + 'static,
100	Error: FullCodec + 'static,
101	OnEmpty: crate::traits::Get<Result<Value, Error>>,
102{
103	const METADATA: StorageEntryModifierIR = StorageEntryModifierIR::Optional;
104
105	type Query = Result<Value, Error>;
106
107	fn from_optional_value_to_query(v: Option<Value>) -> Self::Query {
108		match v {
109			Some(v) => Ok(v),
110			None => OnEmpty::get(),
111		}
112	}
113
114	fn from_query_to_optional_value(v: Self::Query) -> Option<Value> {
115		v.ok()
116	}
117}
118
119/// Implements [`QueryKindTrait`] with `Query` type being `Value`.
120pub struct ValueQuery;
121impl<Value, OnEmpty> QueryKindTrait<Value, OnEmpty> for ValueQuery
122where
123	Value: FullCodec + 'static,
124	OnEmpty: crate::traits::Get<Value>,
125{
126	const METADATA: StorageEntryModifierIR = StorageEntryModifierIR::Default;
127
128	type Query = Value;
129
130	fn from_optional_value_to_query(v: Option<Value>) -> Self::Query {
131		v.unwrap_or_else(|| OnEmpty::get())
132	}
133
134	fn from_query_to_optional_value(v: Self::Query) -> Option<Value> {
135		Some(v)
136	}
137}
138
139/// Build the metadata of a storage.
140///
141/// Implemented by each of the storage types: value, map, countedmap, doublemap and nmap.
142pub trait StorageEntryMetadataBuilder {
143	/// Build into `entries` the storage metadata entries of a storage given some `docs`.
144	fn build_metadata(
145		deprecation_status: sp_metadata_ir::ItemDeprecationInfoIR,
146		doc: Vec<&'static str>,
147		entries: &mut Vec<StorageEntryMetadataIR>,
148	);
149}
150
151#[cfg(test)]
152mod test {
153	use super::*;
154	use crate::{
155		storage::types::ValueQuery,
156		traits::{Get, StorageInstance},
157	};
158	use sp_io::TestExternalities;
159
160	struct Prefix;
161	impl StorageInstance for Prefix {
162		fn pallet_prefix() -> &'static str {
163			"test"
164		}
165		const STORAGE_PREFIX: &'static str = "foo";
166	}
167
168	#[docify::export]
169	#[test]
170	pub fn value_query_examples() {
171		/// Custom default impl to be used with `ValueQuery`.
172		struct UniverseSecret;
173		impl Get<u32> for UniverseSecret {
174			fn get() -> u32 {
175				42
176			}
177		}
178
179		/// Custom default impl to be used with `ResultQuery`.
180		struct GetDefaultForResult;
181		impl Get<Result<u32, ()>> for GetDefaultForResult {
182			fn get() -> Result<u32, ()> {
183				Err(())
184			}
185		}
186
187		type A = StorageValue<Prefix, u32, ValueQuery>;
188		type B = StorageValue<Prefix, u32, OptionQuery>;
189		type C = StorageValue<Prefix, u32, ResultQuery<()>, GetDefaultForResult>;
190		type D = StorageValue<Prefix, u32, ValueQuery, UniverseSecret>;
191
192		TestExternalities::default().execute_with(|| {
193			// normal value query returns default
194			assert_eq!(A::get(), 0);
195
196			// option query returns none
197			assert_eq!(B::get(), None);
198
199			// result query returns error
200			assert_eq!(C::get(), Err(()));
201
202			// value query with custom on empty returns 42
203			assert_eq!(D::get(), 42);
204		});
205	}
206}