Skip to main content

bullet_exchange_interface/
schema.rs

1use std::collections::HashMap;
2
3// reexport to make it useable without thinking about the right dependencies
4pub use sov_universal_wallet::schema::Schema;
5use sov_universal_wallet::schema::{IndexLinking, Link};
6use sov_universal_wallet::ty::{NamedField, Ty, UnnamedField};
7
8#[derive(serde::Deserialize)]
9pub struct SchemaFile {
10    pub chain_hash: String,
11    pub schema: Schema,
12}
13
14/// Trim a given schema by only returning the types for the necessary variants.
15pub fn trim(input: &Schema, filter_variants: &dyn Fn(&str, &str) -> bool) -> Vec<Ty<IndexLinking>> {
16    let types = input.types();
17    let mut res = vec![];
18    let mut map = HashMap::new();
19    trim_internal(0, types, filter_variants, &mut map, &mut res);
20    res
21}
22
23fn trim_internal(
24    index: usize,
25    types: &[Ty<IndexLinking>],
26    filter_variants: &dyn Fn(&str, &str) -> bool,
27    map: &mut HashMap<usize, usize>,
28    res: &mut Vec<Ty<IndexLinking>>,
29) {
30    if map.contains_key(&index) {
31        return;
32    }
33    let ofs = res.len();
34    map.insert(index, ofs);
35    let mut elem = types.get(index).expect("type not found").clone();
36    res.push(elem.clone());
37
38    match elem {
39        Ty::Enum(ref mut value) => {
40            let type_name = value.type_name.as_str();
41            value.variants.retain(|x| filter_variants(type_name, x.name.as_str()));
42            for v in &mut value.variants {
43                if let Some(x) = &mut v.value {
44                    replace_link(x, types, filter_variants, map, res);
45                }
46            }
47        }
48        Ty::Tuple(ref mut value) => {
49            for f in &mut value.fields {
50                let UnnamedField::<IndexLinking> { value, silent: _, doc: _ } = f;
51                replace_link(value, types, filter_variants, map, res);
52            }
53        }
54        Ty::Struct(ref mut value) => {
55            for f in &mut value.fields {
56                let NamedField::<IndexLinking> { value, silent: _, doc: _, display_name: _ } = f;
57                replace_link(value, types, filter_variants, map, res);
58            }
59        }
60        Ty::Option { ref mut value }
61        | Ty::Vec { ref mut value }
62        | Ty::Array { ref mut value, len: _ } => {
63            replace_link(value, types, filter_variants, map, res);
64        }
65        Ty::Map { ref mut key, ref mut value } => {
66            replace_link(key, types, filter_variants, map, res);
67            replace_link(value, types, filter_variants, map, res);
68        }
69        Ty::String
70        | Ty::Boolean
71        | Ty::Float32
72        | Ty::Float64
73        | Ty::ByteVec { .. }
74        | Ty::Integer { .. }
75        | Ty::ByteArray { .. }
76        | Ty::Skip { .. } => {}
77    }
78    // overwrite the changed element
79    res[ofs] = elem;
80}
81
82fn replace_link(
83    v: &mut Link,
84    types: &[Ty<IndexLinking>],
85    filter_variants: &dyn Fn(&str, &str) -> bool,
86    map: &mut HashMap<usize, usize>,
87    res: &mut Vec<Ty<IndexLinking>>,
88) {
89    match v {
90        Link::ByIndex(index) => {
91            let old = *index;
92            *index = map.get(&old).copied().unwrap_or(res.len());
93            if *index == res.len() {
94                trim_internal(old, types, filter_variants, map, res);
95            }
96        }
97        Link::Immediate(_) => {}
98        Link::Placeholder | Link::IndexedPlaceholder(_) => {
99            panic!("constructed schemas must not contain placeholders");
100        }
101    }
102}