frame_decode/utils/
list_storage_entries.rs

1// Copyright (C) 2022-2023 Parity Technologies (UK) Ltd. (admin@parity.io)
2// This file is a part of the scale-value crate.
3//
4// Licensed under the Apache License, Version 2.0 (the "License");
5// you may not use this file except in compliance with the License.
6// You may obtain a copy of the License at
7//
8//         http://www.apache.org/licenses/LICENSE-2.0
9//
10// Unless required by applicable law or agreed to in writing, software
11// distributed under the License is distributed on an "AS IS" BASIS,
12// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13// See the License for the specific language governing permissions and
14// limitations under the License.
15
16use alloc::borrow::Cow;
17use alloc::boxed::Box;
18use frame_metadata::RuntimeMetadata;
19
20/// Returns an iterator listing the available storage entries in some metadata.
21///
22/// This can be handed any version of the metadata, for instance [`frame_metadata::v13::RuntimeMetadataV13`].
23pub fn list_storage_entries<Md: ToStorageEntriesList>(
24    metadata: &Md,
25) -> impl Iterator<Item = StorageEntry<'_>> {
26    metadata.storage_entries_list()
27}
28
29/// Returns an iterator listing the available storage entries in some metadata.
30///
31/// Unlike [`list_storage_entries`], this is handed the outer [`frame_metadata::RuntimeMetadata`] enum.
32pub fn list_storage_entries_any(
33    metadata: &RuntimeMetadata,
34) -> impl Iterator<Item = StorageEntry<'_>> {
35    match metadata {
36        RuntimeMetadata::V0(_deprecated_metadata)
37        | RuntimeMetadata::V1(_deprecated_metadata)
38        | RuntimeMetadata::V2(_deprecated_metadata)
39        | RuntimeMetadata::V3(_deprecated_metadata)
40        | RuntimeMetadata::V4(_deprecated_metadata)
41        | RuntimeMetadata::V5(_deprecated_metadata)
42        | RuntimeMetadata::V6(_deprecated_metadata)
43        | RuntimeMetadata::V7(_deprecated_metadata) => {
44            Box::new(core::iter::empty()) as Box<dyn Iterator<Item = StorageEntry<'_>>>
45        }
46        #[cfg(feature = "legacy")]
47        RuntimeMetadata::V8(m) => Box::new(m.storage_entries_list()),
48        #[cfg(not(feature = "legacy"))]
49        RuntimeMetadata::V8(_opaque) => Box::new(core::iter::empty()),
50        #[cfg(feature = "legacy")]
51        RuntimeMetadata::V9(m) => Box::new(m.storage_entries_list()),
52        #[cfg(not(feature = "legacy"))]
53        RuntimeMetadata::V9(_opaque) => Box::new(core::iter::empty()),
54        #[cfg(feature = "legacy")]
55        RuntimeMetadata::V10(m) => Box::new(m.storage_entries_list()),
56        #[cfg(not(feature = "legacy"))]
57        RuntimeMetadata::V10(_opaque) => Box::new(core::iter::empty()),
58        #[cfg(feature = "legacy")]
59        RuntimeMetadata::V11(m) => Box::new(m.storage_entries_list()),
60        #[cfg(not(feature = "legacy"))]
61        RuntimeMetadata::V11(_opaque) => Box::new(core::iter::empty()),
62        #[cfg(feature = "legacy")]
63        RuntimeMetadata::V12(m) => Box::new(m.storage_entries_list()),
64        #[cfg(not(feature = "legacy"))]
65        RuntimeMetadata::V12(_opaque) => Box::new(core::iter::empty()),
66        #[cfg(feature = "legacy")]
67        RuntimeMetadata::V13(m) => Box::new(m.storage_entries_list()),
68        #[cfg(not(feature = "legacy"))]
69        RuntimeMetadata::V13(_opaque) => Box::new(core::iter::empty()),
70        RuntimeMetadata::V14(m) => Box::new(m.storage_entries_list()),
71        RuntimeMetadata::V15(m) => Box::new(m.storage_entries_list()),
72        RuntimeMetadata::V16(m) => Box::new(m.storage_entries_list()),
73    }
74}
75
76/// Details about a single storage entry.
77#[derive(Debug, Clone)]
78pub struct StorageEntry<'a> {
79    pallet: Cow<'a, str>,
80    entry: Cow<'a, str>,
81}
82
83impl StorageEntry<'_> {
84    /// Take ownership of this storage entry, converting lifetimes to `'static`
85    pub fn into_owned(self) -> StorageEntry<'static> {
86        StorageEntry {
87            pallet: Cow::Owned(self.pallet.into_owned()),
88            entry: Cow::Owned(self.entry.into_owned()),
89        }
90    }
91
92    /// Name of the pallet containing the storage entry.
93    pub fn pallet(&self) -> &str {
94        &self.pallet
95    }
96
97    /// Name of the storage entry.
98    pub fn entry(&self) -> &str {
99        &self.entry
100    }
101}
102
103pub trait ToStorageEntriesList {
104    /// List all of the storage entries available in some metadata.
105    fn storage_entries_list(&self) -> impl Iterator<Item = StorageEntry<'_>>;
106}
107
108#[cfg(feature = "legacy")]
109const _: () = {
110    macro_rules! impl_storage_entries_list_for_v8_to_v13 {
111        ($path:path) => {
112            impl ToStorageEntriesList for $path {
113                fn storage_entries_list(&self) -> impl Iterator<Item = StorageEntry<'_>> {
114                    use crate::utils::as_decoded;
115                    as_decoded(&self.modules).iter().flat_map(|module| {
116                        let Some(storage) = &module.storage else {
117                            return Either::Left(core::iter::empty());
118                        };
119                        let pallet = as_decoded(&module.name);
120                        let storage = as_decoded(storage);
121                        let entries = as_decoded(&storage.entries);
122
123                        Either::Right(entries.iter().map(|entry_meta| {
124                            let entry = as_decoded(&entry_meta.name);
125                            StorageEntry {
126                                pallet: Cow::Borrowed(pallet.as_ref()),
127                                entry: Cow::Borrowed(entry.as_ref()),
128                            }
129                        }))
130                    })
131                }
132            }
133        };
134    }
135
136    impl_storage_entries_list_for_v8_to_v13!(frame_metadata::v8::RuntimeMetadataV8);
137    impl_storage_entries_list_for_v8_to_v13!(frame_metadata::v9::RuntimeMetadataV9);
138    impl_storage_entries_list_for_v8_to_v13!(frame_metadata::v10::RuntimeMetadataV10);
139    impl_storage_entries_list_for_v8_to_v13!(frame_metadata::v11::RuntimeMetadataV11);
140    impl_storage_entries_list_for_v8_to_v13!(frame_metadata::v12::RuntimeMetadataV12);
141    impl_storage_entries_list_for_v8_to_v13!(frame_metadata::v13::RuntimeMetadataV13);
142};
143
144macro_rules! impl_storage_entries_list_for_v14_to_v16 {
145    ($path:path) => {
146        impl ToStorageEntriesList for $path {
147            fn storage_entries_list(&self) -> impl Iterator<Item = StorageEntry<'_>> {
148                self.pallets.iter().flat_map(|pallet| {
149                    let Some(storage) = &pallet.storage else {
150                        return Either::Left(core::iter::empty());
151                    };
152
153                    Either::Right(storage.entries.iter().map(|entry_meta| {
154                        let entry = &entry_meta.name;
155                        StorageEntry {
156                            pallet: Cow::Borrowed(pallet.name.as_ref()),
157                            entry: Cow::Borrowed(entry.as_ref()),
158                        }
159                    }))
160                })
161            }
162        }
163    };
164}
165
166impl_storage_entries_list_for_v14_to_v16!(frame_metadata::v14::RuntimeMetadataV14);
167impl_storage_entries_list_for_v14_to_v16!(frame_metadata::v15::RuntimeMetadataV15);
168impl_storage_entries_list_for_v14_to_v16!(frame_metadata::v16::RuntimeMetadataV16);
169
170enum Either<L, R> {
171    Left(L),
172    Right(R),
173}
174
175impl<L, R> Iterator for Either<L, R>
176where
177    L: Iterator,
178    R: Iterator<Item = L::Item>,
179{
180    type Item = L::Item;
181    fn next(&mut self) -> Option<L::Item> {
182        match self {
183            Either::Left(l) => l.next(),
184            Either::Right(r) => r.next(),
185        }
186    }
187}