sp_externalities/
extensions.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//! Externalities extensions storage.
19//!
20//! Externalities support to register a wide variety custom extensions. The [`Extensions`] provides
21//! some convenience functionality to store and retrieve these extensions.
22//!
23//! It is required that each extension implements the [`Extension`] trait.
24
25use crate::Error;
26use alloc::{
27	boxed::Box,
28	collections::btree_map::{BTreeMap, Entry},
29};
30use core::{
31	any::{Any, TypeId},
32	ops::DerefMut,
33};
34
35/// Informs [`Extension`] about what type of transaction is started, committed or rolled back.
36#[derive(Clone, Copy, Debug, PartialEq, Eq)]
37pub enum TransactionType {
38	/// A transaction started by the host.
39	Host,
40	/// A transaction started by the runtime.
41	Runtime,
42}
43
44impl TransactionType {
45	/// Is `self` set to [`Self::Host`].
46	pub fn is_host(self) -> bool {
47		matches!(self, Self::Host)
48	}
49
50	/// Is `self` set to [`Self::Runtime`].
51	pub fn is_runtime(self) -> bool {
52		matches!(self, Self::Runtime)
53	}
54}
55
56/// Marker trait for types that should be registered as [`Externalities`](crate::Externalities)
57/// extension.
58///
59/// As extensions are stored as `Box<Any>`, this trait should give more confidence that the correct
60/// type is registered and requested.
61pub trait Extension: Send + 'static {
62	/// Return the extension as `&mut dyn Any`.
63	///
64	/// This is a trick to make the trait type castable into an [`Any`].
65	fn as_mut_any(&mut self) -> &mut dyn Any;
66
67	/// Get the [`TypeId`] of this `Extension`.
68	fn type_id(&self) -> TypeId;
69
70	/// Start a transaction of type `ty`.
71	fn start_transaction(&mut self, ty: TransactionType) {
72		let _ty = ty;
73	}
74
75	/// Commit a transaction of type `ty`.
76	fn commit_transaction(&mut self, ty: TransactionType) {
77		let _ty = ty;
78	}
79
80	/// Rollback a transaction of type `ty`.
81	fn rollback_transaction(&mut self, ty: TransactionType) {
82		let _ty = ty;
83	}
84}
85
86impl Extension for Box<dyn Extension> {
87	fn as_mut_any(&mut self) -> &mut dyn Any {
88		(**self).as_mut_any()
89	}
90
91	fn type_id(&self) -> TypeId {
92		(**self).type_id()
93	}
94
95	fn start_transaction(&mut self, ty: TransactionType) {
96		(**self).start_transaction(ty);
97	}
98
99	fn commit_transaction(&mut self, ty: TransactionType) {
100		(**self).commit_transaction(ty);
101	}
102
103	fn rollback_transaction(&mut self, ty: TransactionType) {
104		(**self).rollback_transaction(ty);
105	}
106}
107
108/// Macro for declaring an extension that usable with [`Extensions`].
109///
110/// The extension will be an unit wrapper struct that implements [`Extension`], `Deref` and
111/// `DerefMut`. The wrapped type is given by the user.
112///
113/// # Example
114/// ```
115/// # use sp_externalities::decl_extension;
116/// decl_extension! {
117///     /// Some test extension
118///     struct TestExt(String);
119/// }
120/// ```
121///
122/// The [`Extension`] trait provides hooks that are called when starting, committing or rolling back
123/// a transaction. These can be implemented with the macro as well:
124/// ```
125/// # use sp_externalities::{decl_extension, TransactionType};
126/// decl_extension! {
127///     /// Some test extension
128///     struct TestExtWithCallback(String);
129///
130///     impl TestExtWithCallback {
131///         fn start_transaction(&mut self, ty: TransactionType) {
132///             // do something cool
133///         }
134///
135///         // The other methods `commit_transaction` and `rollback_transaction` can also
136///         // be implemented in the same way.
137///     }
138/// }
139/// ```
140#[macro_export]
141macro_rules! decl_extension {
142	(
143		$( #[ $attr:meta ] )*
144		$vis:vis struct $ext_name:ident ($inner:ty);
145		$(
146			impl $ext_name_impl:ident {
147				$(
148					$impls:tt
149				)*
150			}
151		)*
152	) => {
153		$( #[ $attr ] )*
154		$vis struct $ext_name (pub $inner);
155
156		impl $crate::Extension for $ext_name {
157			fn as_mut_any(&mut self) -> &mut dyn core::any::Any {
158				self
159			}
160
161			fn type_id(&self) -> core::any::TypeId {
162				core::any::Any::type_id(self)
163			}
164
165			$(
166				$(
167					$impls
168				)*
169			)*
170		}
171
172		impl core::ops::Deref for $ext_name {
173			type Target = $inner;
174
175			fn deref(&self) -> &Self::Target {
176				&self.0
177			}
178		}
179
180		impl core::ops::DerefMut for $ext_name {
181			fn deref_mut(&mut self) -> &mut Self::Target {
182				&mut self.0
183			}
184		}
185
186		impl From<$inner> for $ext_name {
187			fn from(inner: $inner) -> Self {
188				Self(inner)
189			}
190 		}
191	};
192	(
193		$( #[ $attr:meta ] )*
194		$vis:vis struct $ext_name:ident;
195	) => {
196		$( #[ $attr ] )*
197		$vis struct $ext_name;
198
199		impl $crate::Extension for $ext_name {
200			fn as_mut_any(&mut self) -> &mut dyn core::any::Any {
201				self
202			}
203
204			fn type_id(&self) -> core::any::TypeId {
205				core::any::Any::type_id(self)
206			}
207		}
208	}
209}
210
211/// Something that provides access to the [`Extensions`] store.
212///
213/// This is a super trait of the [`Externalities`](crate::Externalities).
214pub trait ExtensionStore {
215	/// Tries to find a registered extension by the given `type_id` and returns it as a `&mut dyn
216	/// Any`.
217	///
218	/// It is advised to use [`ExternalitiesExt::extension`](crate::ExternalitiesExt::extension)
219	/// instead of this function to get type system support and automatic type downcasting.
220	fn extension_by_type_id(&mut self, type_id: TypeId) -> Option<&mut dyn Any>;
221
222	/// Register extension `extension` with specified `type_id`.
223	///
224	/// It should return error if extension is already registered.
225	fn register_extension_with_type_id(
226		&mut self,
227		type_id: TypeId,
228		extension: Box<dyn Extension>,
229	) -> Result<(), Error>;
230
231	/// Deregister extension with specified 'type_id' and drop it.
232	///
233	/// It should return error if extension is not registered.
234	fn deregister_extension_by_type_id(&mut self, type_id: TypeId) -> Result<(), Error>;
235}
236
237/// Stores extensions that should be made available through the externalities.
238#[derive(Default)]
239pub struct Extensions {
240	extensions: BTreeMap<TypeId, Box<dyn Extension>>,
241}
242
243impl core::fmt::Debug for Extensions {
244	fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
245		write!(f, "Extensions: ({})", self.extensions.len())
246	}
247}
248
249impl Extensions {
250	/// Create new instance of `Self`.
251	pub fn new() -> Self {
252		Self::default()
253	}
254
255	/// Register the given extension.
256	pub fn register<E: Extension>(&mut self, ext: E) {
257		let type_id = ext.type_id();
258		self.extensions.insert(type_id, Box::new(ext));
259	}
260
261	/// Register extension `extension` using the given `type_id`.
262	pub fn register_with_type_id(
263		&mut self,
264		type_id: TypeId,
265		extension: Box<dyn Extension>,
266	) -> Result<(), Error> {
267		match self.extensions.entry(type_id) {
268			Entry::Vacant(vacant) => {
269				vacant.insert(extension);
270				Ok(())
271			},
272			Entry::Occupied(_) => Err(Error::ExtensionAlreadyRegistered),
273		}
274	}
275
276	/// Return a mutable reference to the requested extension.
277	pub fn get_mut(&mut self, ext_type_id: TypeId) -> Option<&mut dyn Any> {
278		self.extensions
279			.get_mut(&ext_type_id)
280			.map(DerefMut::deref_mut)
281			.map(Extension::as_mut_any)
282	}
283
284	/// Deregister extension for the given `type_id`.
285	///
286	/// Returns `true` when the extension was registered.
287	pub fn deregister(&mut self, type_id: TypeId) -> bool {
288		self.extensions.remove(&type_id).is_some()
289	}
290
291	/// Returns a mutable iterator over all extensions.
292	pub fn iter_mut(&mut self) -> impl Iterator<Item = (&TypeId, &mut Box<dyn Extension>)> {
293		self.extensions.iter_mut()
294	}
295
296	/// Merge `other` into `self`.
297	///
298	/// If both contain the same extension, the extension instance of `other` will overwrite the
299	/// instance found in `self`.
300	pub fn merge(&mut self, other: Self) {
301		self.extensions.extend(other.extensions);
302	}
303
304	/// Start a transaction of type `ty`.
305	pub fn start_transaction(&mut self, ty: TransactionType) {
306		self.extensions.values_mut().for_each(|e| e.start_transaction(ty));
307	}
308
309	/// Commit a transaction of type `ty`.
310	pub fn commit_transaction(&mut self, ty: TransactionType) {
311		self.extensions.values_mut().for_each(|e| e.commit_transaction(ty));
312	}
313
314	/// Rollback a transaction of type `ty`.
315	pub fn rollback_transaction(&mut self, ty: TransactionType) {
316		self.extensions.values_mut().for_each(|e| e.rollback_transaction(ty));
317	}
318}
319
320impl Extend<Extensions> for Extensions {
321	fn extend<T: IntoIterator<Item = Extensions>>(&mut self, iter: T) {
322		iter.into_iter()
323			.for_each(|ext| self.extensions.extend(ext.extensions.into_iter()));
324	}
325}
326
327#[cfg(test)]
328mod tests {
329	use super::*;
330
331	decl_extension! {
332		struct DummyExt(u32);
333	}
334	decl_extension! {
335		struct DummyExt2(u32);
336	}
337
338	#[test]
339	fn register_and_retrieve_extension() {
340		let mut exts = Extensions::new();
341		exts.register(DummyExt(1));
342		exts.register(DummyExt2(2));
343
344		let ext = exts.get_mut(TypeId::of::<DummyExt>()).expect("Extension is registered");
345		let ext_ty = ext.downcast_mut::<DummyExt>().expect("Downcasting works");
346
347		assert_eq!(ext_ty.0, 1);
348	}
349
350	#[test]
351	fn register_box_extension() {
352		let mut exts = Extensions::new();
353		let box1: Box<dyn Extension> = Box::new(DummyExt(1));
354		let box2: Box<dyn Extension> = Box::new(DummyExt2(2));
355		exts.register(box1);
356		exts.register(box2);
357
358		{
359			let ext = exts.get_mut(TypeId::of::<DummyExt>()).expect("Extension 1 is registered");
360			let ext_ty = ext.downcast_mut::<DummyExt>().expect("Downcasting works for Extension 1");
361			assert_eq!(ext_ty.0, 1);
362		}
363		{
364			let ext2 = exts.get_mut(TypeId::of::<DummyExt2>()).expect("Extension 2 is registered");
365			let ext_ty2 =
366				ext2.downcast_mut::<DummyExt2>().expect("Downcasting works for Extension 2");
367			assert_eq!(ext_ty2.0, 2);
368		}
369	}
370}