1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
// This file is part of Substrate.

// Copyright (C) Parity Technologies (UK) Ltd.
// SPDX-License-Identifier: Apache-2.0

// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// 	http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//! Types and traits for dynamic parameters.
//!
//! Can be used by 3rd party macros to define dynamic parameters that are compatible with the the
//! `parameters` pallet.

use codec::MaxEncodedLen;
use frame_support::Parameter;

/// A dynamic parameter store across an aggregated KV type.
pub trait RuntimeParameterStore {
	type AggregatedKeyValue: AggregatedKeyValue;

	/// Get the value of a parametrized key.
	///
	/// Should return `None` if no explicit value was set instead of a default.
	fn get<KV, K>(key: K) -> Option<K::Value>
	where
		KV: AggregatedKeyValue,
		K: Key + Into<<KV as AggregatedKeyValue>::Key>,
		<KV as AggregatedKeyValue>::Key: IntoKey<
			<<Self as RuntimeParameterStore>::AggregatedKeyValue as AggregatedKeyValue>::Key,
		>,
		<<Self as RuntimeParameterStore>::AggregatedKeyValue as AggregatedKeyValue>::Value:
			TryIntoKey<<KV as AggregatedKeyValue>::Value>,
		<KV as AggregatedKeyValue>::Value: TryInto<K::WrappedValue>;
}

/// A dynamic parameter store across a concrete KV type.
pub trait ParameterStore<KV: AggregatedKeyValue> {
	/// Get the value of a parametrized key.
	fn get<K>(key: K) -> Option<K::Value>
	where
		K: Key + Into<<KV as AggregatedKeyValue>::Key>,
		<KV as AggregatedKeyValue>::Value: TryInto<K::WrappedValue>;
}

/// Key of a dynamic parameter.
pub trait Key {
	/// The value that the key is parametrized with.
	type Value;

	/// An opaque representation of `Self::Value`.
	type WrappedValue: Into<Self::Value>;
}

/// The aggregated key-value type of a dynamic parameter store.
pub trait AggregatedKeyValue: Parameter {
	/// The aggregated key type.
	type Key: Parameter + MaxEncodedLen;

	/// The aggregated value type.
	type Value: Parameter + MaxEncodedLen;

	/// Split the aggregated key-value type into its parts.
	fn into_parts(self) -> (Self::Key, Option<Self::Value>);
}

impl AggregatedKeyValue for () {
	type Key = ();
	type Value = ();

	fn into_parts(self) -> (Self::Key, Option<Self::Value>) {
		((), None)
	}
}

/// Allows to create a `ParameterStore` from a `RuntimeParameterStore`.
///
/// This concretization is useful when configuring pallets, since a pallet will require a parameter
/// store for its own KV type and not the aggregated runtime-wide KV type.
pub struct ParameterStoreAdapter<PS, KV>(core::marker::PhantomData<(PS, KV)>);

impl<PS, KV> ParameterStore<KV> for ParameterStoreAdapter<PS, KV>
where
	PS: RuntimeParameterStore,
	KV: AggregatedKeyValue,
	<KV as AggregatedKeyValue>::Key:
		IntoKey<<<PS as RuntimeParameterStore>::AggregatedKeyValue as AggregatedKeyValue>::Key>,
	<KV as AggregatedKeyValue>::Value: TryFromKey<
		<<PS as RuntimeParameterStore>::AggregatedKeyValue as AggregatedKeyValue>::Value,
	>,
{
	fn get<K>(key: K) -> Option<K::Value>
	where
		K: Key + Into<<KV as AggregatedKeyValue>::Key>,
		<KV as AggregatedKeyValue>::Value: TryInto<K::WrappedValue>,
	{
		PS::get::<KV, K>(key)
	}
}

// workaround for rust bug https://github.com/rust-lang/rust/issues/51445
mod workaround {
	pub trait FromKey<T>: Sized {
		#[must_use]
		fn from_key(value: T) -> Self;
	}

	pub trait IntoKey<T>: Sized {
		#[must_use]
		fn into_key(self) -> T;
	}

	impl<T, U> IntoKey<U> for T
	where
		U: FromKey<T>,
	{
		fn into_key(self) -> U {
			U::from_key(self)
		}
	}

	pub trait TryIntoKey<T>: Sized {
		type Error;

		fn try_into_key(self) -> Result<T, Self::Error>;
	}

	pub trait TryFromKey<T>: Sized {
		type Error;

		fn try_from_key(value: T) -> Result<Self, Self::Error>;
	}

	impl<T, U> TryIntoKey<U> for T
	where
		U: TryFromKey<T>,
	{
		type Error = U::Error;

		fn try_into_key(self) -> Result<U, U::Error> {
			U::try_from_key(self)
		}
	}
}
pub use workaround::*;