Skip to main content

topsoil_core/traits/
dynamic_params.rs

1// This file is part of Soil.
2
3// Copyright (C) Soil contributors.
4// Copyright (C) Parity Technologies (UK) Ltd.
5// SPDX-License-Identifier: Apache-2.0 OR GPL-3.0-or-later WITH Classpath-exception-2.0
6
7//! Types and traits for dynamic parameters.
8//!
9//! Can be used by 3rd party macros to define dynamic parameters that are compatible with the the
10//! `parameters` pallet.
11
12use codec::MaxEncodedLen;
13use topsoil_core::Parameter;
14
15/// A dynamic parameter store across an aggregated KV type.
16pub trait RuntimeParameterStore {
17	type AggregatedKeyValue: AggregatedKeyValue;
18
19	/// Get the value of a parametrized key.
20	///
21	/// Should return `None` if no explicit value was set instead of a default.
22	fn get<KV, K>(key: K) -> Option<K::Value>
23	where
24		KV: AggregatedKeyValue,
25		K: Key + Into<<KV as AggregatedKeyValue>::Key>,
26		<KV as AggregatedKeyValue>::Key: IntoKey<
27			<<Self as RuntimeParameterStore>::AggregatedKeyValue as AggregatedKeyValue>::Key,
28		>,
29		<<Self as RuntimeParameterStore>::AggregatedKeyValue as AggregatedKeyValue>::Value:
30			TryIntoKey<<KV as AggregatedKeyValue>::Value>,
31		<KV as AggregatedKeyValue>::Value: TryInto<K::WrappedValue>;
32}
33
34/// A dynamic parameter store across a concrete KV type.
35pub trait ParameterStore<KV: AggregatedKeyValue> {
36	/// Get the value of a parametrized key.
37	fn get<K>(key: K) -> Option<K::Value>
38	where
39		K: Key + Into<<KV as AggregatedKeyValue>::Key>,
40		<KV as AggregatedKeyValue>::Value: TryInto<K::WrappedValue>;
41}
42
43/// Key of a dynamic parameter.
44pub trait Key {
45	/// The value that the key is parametrized with.
46	type Value;
47
48	/// An opaque representation of `Self::Value`.
49	type WrappedValue: Into<Self::Value>;
50}
51
52/// The aggregated key-value type of a dynamic parameter store.
53pub trait AggregatedKeyValue: Parameter {
54	/// The aggregated key type.
55	type Key: Parameter + MaxEncodedLen;
56
57	/// The aggregated value type.
58	type Value: Parameter + MaxEncodedLen;
59
60	/// Split the aggregated key-value type into its parts.
61	fn into_parts(self) -> (Self::Key, Option<Self::Value>);
62}
63
64impl AggregatedKeyValue for () {
65	type Key = ();
66	type Value = ();
67
68	fn into_parts(self) -> (Self::Key, Option<Self::Value>) {
69		((), None)
70	}
71}
72
73/// Allows to create a `ParameterStore` from a `RuntimeParameterStore`.
74///
75/// This concretization is useful when configuring pallets, since a pallet will require a parameter
76/// store for its own KV type and not the aggregated runtime-wide KV type.
77pub struct ParameterStoreAdapter<PS, KV>(core::marker::PhantomData<(PS, KV)>);
78
79impl<PS, KV> ParameterStore<KV> for ParameterStoreAdapter<PS, KV>
80where
81	PS: RuntimeParameterStore,
82	KV: AggregatedKeyValue,
83	<KV as AggregatedKeyValue>::Key:
84		IntoKey<<<PS as RuntimeParameterStore>::AggregatedKeyValue as AggregatedKeyValue>::Key>,
85	<KV as AggregatedKeyValue>::Value: TryFromKey<
86		<<PS as RuntimeParameterStore>::AggregatedKeyValue as AggregatedKeyValue>::Value,
87	>,
88{
89	fn get<K>(key: K) -> Option<K::Value>
90	where
91		K: Key + Into<<KV as AggregatedKeyValue>::Key>,
92		<KV as AggregatedKeyValue>::Value: TryInto<K::WrappedValue>,
93	{
94		PS::get::<KV, K>(key)
95	}
96}
97
98// workaround for rust bug https://github.com/rust-lang/rust/issues/51445
99mod workaround {
100	pub trait FromKey<T>: Sized {
101		#[must_use]
102		fn from_key(value: T) -> Self;
103	}
104
105	pub trait IntoKey<T>: Sized {
106		#[must_use]
107		fn into_key(self) -> T;
108	}
109
110	impl<T, U> IntoKey<U> for T
111	where
112		U: FromKey<T>,
113	{
114		fn into_key(self) -> U {
115			U::from_key(self)
116		}
117	}
118
119	pub trait TryIntoKey<T>: Sized {
120		type Error;
121
122		fn try_into_key(self) -> Result<T, Self::Error>;
123	}
124
125	pub trait TryFromKey<T>: Sized {
126		type Error;
127
128		fn try_from_key(value: T) -> Result<Self, Self::Error>;
129	}
130
131	impl<T, U> TryIntoKey<U> for T
132	where
133		U: TryFromKey<T>,
134	{
135		type Error = U::Error;
136
137		fn try_into_key(self) -> Result<U, U::Error> {
138			U::try_from_key(self)
139		}
140	}
141}
142pub use workaround::*;