Skip to main content

frame_decode/methods/
mod.rs

1// Copyright (C) 2022-2025 Parity Technologies (UK) Ltd. (admin@parity.io)
2// This file is a part of the frame-decode 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
16pub mod constant_decoder;
17pub mod constant_type_info;
18pub mod custom_value_decoder;
19pub mod custom_value_type_info;
20pub mod extrinsic_decoder;
21pub mod extrinsic_encoder;
22pub mod extrinsic_type_info;
23pub mod runtime_api_decoder;
24pub mod runtime_api_encoder;
25pub mod runtime_api_type_info;
26pub mod storage_decoder;
27pub mod storage_encoder;
28pub mod storage_type_info;
29pub mod view_function_decoder;
30pub mod view_function_encoder;
31pub mod view_function_type_info;
32
33/// This represents either an entry name, or the name of the thing that the entry is
34/// in (for instance the name of a pallet or of a Runtime API trait).
35///
36/// Iterators returning this will iterate containers in order, first returning
37/// [`Entry::In`] to communicate which container (eg pallet or Runtime API trait) is being
38/// iterated over next, and then a [`Entry::Name`]s for the name of each of the entries in
39/// the given container.
40///
41/// A container name will not be handed back more than once.
42#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
43pub enum Entry<In, Name> {
44    /// The name of the thing that the following entries are in/under.
45    In(In),
46    /// The name of the entry in/under the last given [`Entry::In`].
47    Name(Name),
48}
49
50impl<T> Entry<T, T> {
51    /// Map the values in the entry, assuming they are the same.
52    pub fn map<R, F: FnOnce(T) -> R>(self, f: F) -> Entry<R, R> {
53        match self {
54            Entry::In(t) => Entry::In(f(t)),
55            Entry::Name(t) => Entry::Name(f(t)),
56        }
57    }
58}
59
60impl<In, Name> Entry<In, Name> {
61    /// Iterate over all of the entries in a specific container (ie all of the entries
62    /// which follow a specific [`Entry::In`]).
63    pub fn entries_in(
64        entries: impl Iterator<Item = Entry<In, Name>>,
65        container: impl PartialEq<In>,
66    ) -> impl Iterator<Item = Name>
67    where
68        In: PartialEq,
69        Name: PartialEq,
70    {
71        entries
72            .skip_while(move |c| !matches!(c, Entry::In(c) if &container == c))
73            .skip(1)
74            .take_while(|c| matches!(c, Entry::Name(_)))
75            .filter_map(|c| match c {
76                Entry::In(_) => None,
77                Entry::Name(name) => Some(name),
78            })
79    }
80
81    /// Iterate over all of the entries, returning tuples of `(entry_in, entry_name)`.
82    /// This can be easier to work with in some cases.
83    pub fn tuples_of(
84        entries: impl Iterator<Item = Entry<In, Name>>,
85    ) -> impl Iterator<Item = (In, Name)>
86    where
87        In: Clone,
88    {
89        let mut entry_in = None;
90        entries.filter_map(move |entry| match entry {
91            Entry::In(e_in) => {
92                entry_in = Some(e_in);
93                None
94            }
95            Entry::Name(e_name) => {
96                let e_in = entry_in.as_ref().unwrap().clone();
97                Some((e_in, e_name))
98            }
99        })
100    }
101}
102
103#[cfg(test)]
104mod test {
105    use super::*;
106
107    #[test]
108    fn test_entries_in() {
109        fn entries() -> impl Iterator<Item = Entry<&'static str, &'static str>> {
110            [
111                Entry::In("Baz"),
112                Entry::In("Foo"),
113                Entry::Name("foo_a"),
114                Entry::Name("foo_b"),
115                Entry::Name("foo_c"),
116                Entry::In("Bar"),
117                Entry::Name("bar_a"),
118                Entry::In("Wibble"),
119            ]
120            .into_iter()
121        }
122
123        assert!(Entry::entries_in(entries(), "Baz").next().is_none());
124        assert!(Entry::entries_in(entries(), "Wibble").next().is_none());
125
126        let foos: Vec<String> = Entry::entries_in(entries(), "Foo")
127            .map(|s| s.to_owned())
128            .collect();
129        assert_eq!(
130            foos,
131            Vec::from_iter(["foo_a".to_owned(), "foo_b".to_owned(), "foo_c".to_owned(),])
132        );
133
134        let bars: Vec<String> = Entry::entries_in(entries(), "Bar")
135            .map(|s| s.to_owned())
136            .collect();
137        assert_eq!(bars, Vec::from_iter(["bar_a".to_owned(),]));
138    }
139}