referrerpolicy=no-referrer-when-downgrade

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/// Marker trait for types that should be registered as [`Externalities`](crate::Externalities)
36/// extension.
37///
38/// As extensions are stored as `Box<Any>`, this trait should give more confidence that the correct
39/// type is registered and requested.
40pub trait Extension: Send + 'static {
41	/// Return the extension as `&mut dyn Any`.
42	///
43	/// This is a trick to make the trait type castable into an `Any`.
44	fn as_mut_any(&mut self) -> &mut dyn Any;
45
46	/// Get the [`TypeId`] of this `Extension`.
47	fn type_id(&self) -> TypeId;
48}
49
50impl Extension for Box<dyn Extension> {
51	fn as_mut_any(&mut self) -> &mut dyn Any {
52		(**self).as_mut_any()
53	}
54
55	fn type_id(&self) -> TypeId {
56		(**self).type_id()
57	}
58}
59
60/// Macro for declaring an extension that usable with [`Extensions`].
61///
62/// The extension will be an unit wrapper struct that implements [`Extension`], `Deref` and
63/// `DerefMut`. The wrapped type is given by the user.
64///
65/// # Example
66/// ```
67/// # use sp_externalities::decl_extension;
68/// decl_extension! {
69///     /// Some test extension
70///     struct TestExt(String);
71/// }
72/// ```
73#[macro_export]
74macro_rules! decl_extension {
75	(
76		$( #[ $attr:meta ] )*
77		$vis:vis struct $ext_name:ident ($inner:ty);
78	) => {
79		$( #[ $attr ] )*
80		$vis struct $ext_name (pub $inner);
81
82		impl $crate::Extension for $ext_name {
83			fn as_mut_any(&mut self) -> &mut dyn core::any::Any {
84				self
85			}
86
87			fn type_id(&self) -> core::any::TypeId {
88				core::any::Any::type_id(self)
89			}
90		}
91
92		impl core::ops::Deref for $ext_name {
93			type Target = $inner;
94
95			fn deref(&self) -> &Self::Target {
96				&self.0
97			}
98		}
99
100		impl core::ops::DerefMut for $ext_name {
101			fn deref_mut(&mut self) -> &mut Self::Target {
102				&mut self.0
103			}
104		}
105
106		impl From<$inner> for $ext_name {
107			fn from(inner: $inner) -> Self {
108				Self(inner)
109			}
110 		}
111	};
112	(
113		$( #[ $attr:meta ] )*
114		$vis:vis struct $ext_name:ident;
115	) => {
116		$( #[ $attr ] )*
117		$vis struct $ext_name;
118
119		impl $crate::Extension for $ext_name {
120			fn as_mut_any(&mut self) -> &mut dyn core::any::Any {
121				self
122			}
123
124			fn type_id(&self) -> core::any::TypeId {
125				core::any::Any::type_id(self)
126			}
127		}
128	}
129}
130
131/// Something that provides access to the [`Extensions`] store.
132///
133/// This is a super trait of the [`Externalities`](crate::Externalities).
134pub trait ExtensionStore {
135	/// Tries to find a registered extension by the given `type_id` and returns it as a `&mut dyn
136	/// Any`.
137	///
138	/// It is advised to use [`ExternalitiesExt::extension`](crate::ExternalitiesExt::extension)
139	/// instead of this function to get type system support and automatic type downcasting.
140	fn extension_by_type_id(&mut self, type_id: TypeId) -> Option<&mut dyn Any>;
141
142	/// Register extension `extension` with specified `type_id`.
143	///
144	/// It should return error if extension is already registered.
145	fn register_extension_with_type_id(
146		&mut self,
147		type_id: TypeId,
148		extension: Box<dyn Extension>,
149	) -> Result<(), Error>;
150
151	/// Deregister extension with specified 'type_id' and drop it.
152	///
153	/// It should return error if extension is not registered.
154	fn deregister_extension_by_type_id(&mut self, type_id: TypeId) -> Result<(), Error>;
155}
156
157/// Stores extensions that should be made available through the externalities.
158#[derive(Default)]
159pub struct Extensions {
160	extensions: BTreeMap<TypeId, Box<dyn Extension>>,
161}
162
163impl core::fmt::Debug for Extensions {
164	fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
165		write!(f, "Extensions: ({})", self.extensions.len())
166	}
167}
168
169impl Extensions {
170	/// Create new instance of `Self`.
171	pub fn new() -> Self {
172		Self::default()
173	}
174
175	/// Register the given extension.
176	pub fn register<E: Extension>(&mut self, ext: E) {
177		let type_id = ext.type_id();
178		self.extensions.insert(type_id, Box::new(ext));
179	}
180
181	/// Register extension `extension` using the given `type_id`.
182	pub fn register_with_type_id(
183		&mut self,
184		type_id: TypeId,
185		extension: Box<dyn Extension>,
186	) -> Result<(), Error> {
187		match self.extensions.entry(type_id) {
188			Entry::Vacant(vacant) => {
189				vacant.insert(extension);
190				Ok(())
191			},
192			Entry::Occupied(_) => Err(Error::ExtensionAlreadyRegistered),
193		}
194	}
195
196	/// Return a mutable reference to the requested extension.
197	pub fn get_mut(&mut self, ext_type_id: TypeId) -> Option<&mut dyn Any> {
198		self.extensions
199			.get_mut(&ext_type_id)
200			.map(DerefMut::deref_mut)
201			.map(Extension::as_mut_any)
202	}
203
204	/// Deregister extension for the given `type_id`.
205	///
206	/// Returns `true` when the extension was registered.
207	pub fn deregister(&mut self, type_id: TypeId) -> bool {
208		self.extensions.remove(&type_id).is_some()
209	}
210
211	/// Returns a mutable iterator over all extensions.
212	pub fn iter_mut(&mut self) -> impl Iterator<Item = (&TypeId, &mut Box<dyn Extension>)> {
213		self.extensions.iter_mut()
214	}
215
216	/// Merge `other` into `self`.
217	///
218	/// If both contain the same extension, the extension instance of `other` will overwrite the
219	/// instance found in `self`.
220	pub fn merge(&mut self, other: Self) {
221		self.extensions.extend(other.extensions);
222	}
223}
224
225impl Extend<Extensions> for Extensions {
226	fn extend<T: IntoIterator<Item = Extensions>>(&mut self, iter: T) {
227		iter.into_iter()
228			.for_each(|ext| self.extensions.extend(ext.extensions.into_iter()));
229	}
230}
231
232#[cfg(test)]
233mod tests {
234	use super::*;
235
236	decl_extension! {
237		struct DummyExt(u32);
238	}
239	decl_extension! {
240		struct DummyExt2(u32);
241	}
242
243	#[test]
244	fn register_and_retrieve_extension() {
245		let mut exts = Extensions::new();
246		exts.register(DummyExt(1));
247		exts.register(DummyExt2(2));
248
249		let ext = exts.get_mut(TypeId::of::<DummyExt>()).expect("Extension is registered");
250		let ext_ty = ext.downcast_mut::<DummyExt>().expect("Downcasting works");
251
252		assert_eq!(ext_ty.0, 1);
253	}
254
255	#[test]
256	fn register_box_extension() {
257		let mut exts = Extensions::new();
258		let box1: Box<dyn Extension> = Box::new(DummyExt(1));
259		let box2: Box<dyn Extension> = Box::new(DummyExt2(2));
260		exts.register(box1);
261		exts.register(box2);
262
263		{
264			let ext = exts.get_mut(TypeId::of::<DummyExt>()).expect("Extension 1 is registered");
265			let ext_ty = ext.downcast_mut::<DummyExt>().expect("Downcasting works for Extension 1");
266			assert_eq!(ext_ty.0, 1);
267		}
268		{
269			let ext2 = exts.get_mut(TypeId::of::<DummyExt2>()).expect("Extension 2 is registered");
270			let ext_ty2 =
271				ext2.downcast_mut::<DummyExt2>().expect("Downcasting works for Extension 2");
272			assert_eq!(ext_ty2.0, 2);
273		}
274	}
275}