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
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
/// Sometimes a received blockhash is not valid so this macro tries to perform additional calls
/// with different blockhashes.
#[macro_export]
#[cfg(feature = "solana")]
macro_rules! try_with_solana_blockhashes {
  (
    let $local_blockhash:ident = $initial_blockhash:expr;

    $additional_tries:expr,
    $pair:expr,
    $procedure:expr $(,)?
  ) => {{
    let initial_try = {
      let $local_blockhash = $initial_blockhash;
      $procedure
    };
    match initial_try {
      Err(err) => {
        let inferred_additional_tries: u8 = $additional_tries;
        if let Some(n) = inferred_additional_tries.checked_sub(1) {
          let mut opt = None;
          for _ in 0..n {
            let $local_blockhash = {
              let pair_mut = &mut $pair;
              let (pkgs_aux, trans) = pair_mut.parts_mut();
              let res = trans
                .send_retrieve_and_decode_contained(
                  &mut pkgs_aux.get_latest_blockhash().data(None).build(),
                  pkgs_aux,
                )
                .await?;
              res.result?.value.blockhash
            };
            if let Ok(elem) = $procedure {
              opt = Some((elem, Some($local_blockhash)));
              break;
            }
          }
          if let Some(elem) = opt {
            Ok(elem)
          } else {
            let $local_blockhash = {
              let pair_mut = &mut $pair;
              let (pkgs_aux, trans) = pair_mut.parts_mut();
              let res = trans
                .send_retrieve_and_decode_contained(
                  &mut pkgs_aux.get_latest_blockhash().data(None).build(),
                  pkgs_aux,
                )
                .await?;
              res.result?.value.blockhash
            };
            let last = $procedure?;
            Ok((last, Some($local_blockhash)))
          }
        } else {
          Err(err)
        }
      }
      Ok(elem) => Ok((elem, None)),
    }
  }};
}

macro_rules! _create_blockchain_constants {
  (
    $address_hash_vis:vis address_hash: $address_hash:ident = $_1:literal,
    $address_hash_str_vis:vis address_hash_str: $address_hash_str:ident = $_2:literal,
    $block_hash_vis:vis block_hash: $block_hash:ident = $_3:literal,
    $block_hash_str_vis:vis block_hash_str: $block_hash_str:ident = $_4:literal,
    $signature_hash_vis:vis signature_hash: $signature_hash:ident = $_5:literal,
    $signature_hash_str_vis:vis signature_hash_str: $signature_hash_str:ident = $_6:literal,
    $transaction_hash_vis:vis transaction_hash: $transaction_hash:ident = $_7:literal,
    $transaction_hash_str_vis:vis transaction_hash_str: $transaction_hash_str:ident = $_8:literal
  ) => {
    /// Address hash as bytes
    $address_hash_vis type $address_hash = [u8; $_1];
    /// Address hash as an encoded string
    $address_hash_str_vis type $address_hash_str = ::arrayvec::ArrayString<$_2>;

    /// Block hash as bytes
    $block_hash_vis type $block_hash = [u8; $_3];
    /// Block hash as an encoded string
    $block_hash_str_vis type $block_hash_str = ::arrayvec::ArrayString<$_4>;

    /// Signature hash as bytes
    $signature_hash_vis type $signature_hash = ::cl_aux::ArrayWrapper<u8, $_5>;
    /// Signature hash as an encoded string
    $signature_hash_str_vis type $signature_hash_str = ::arrayvec::ArrayString<$_6>;

    /// Transaction hash as bytes
    $transaction_hash_vis type $transaction_hash = ::cl_aux::ArrayWrapper<u8, $_7>;
    /// Transaction hash as an encoded string
    $transaction_hash_str_vis type $transaction_hash_str = ::arrayvec::ArrayString<$_8>;
  };
}

macro_rules! _generic_api_doc {
  () => {
    "Used to group a set of packages related to this API as well as any additional instance parameters."
  };
}

macro_rules! _generic_res_data_elem_doc {
  () => {
    "Element that makes up most of the expected data response returned by the server."
  };
}

#[cfg(test)]
macro_rules! _create_generic_test {
  ($executor:ident, $test:ident, $pair:expr, $parts_cb:expr, $rslt_cb:expr) => {
    #[$executor::test]
    async fn $test() {
      fn parts_cb_infer<'pair, API, DRSR, O, T>(
        pkgs_aux: &'pair mut crate::misc::PkgsAux<API, DRSR, T::Params>,
        trans: &'pair mut T,
        cb: impl FnOnce(
          &'pair mut crate::misc::PkgsAux<API, DRSR, T::Params>,
          &'pair mut T
        ) -> O,
      ) -> O
      where
        T: Transport<DRSR>
      {
        cb(pkgs_aux, trans)
      }
      fn rslt_cb_infer<'pair, API, DRSR, O, R, T>(
        pkgs_aux: &'pair mut crate::misc::PkgsAux<API, DRSR, T::Params>,
        trans: &'pair mut T,
        rslt: R,
        cb: impl FnOnce(
          &'pair mut crate::misc::PkgsAux<API, DRSR, T::Params>,
          &'pair mut T,
          R
        ) -> O,
      ) -> O
      where
      T: Transport<DRSR>
      {
        cb(pkgs_aux, trans, rslt)
      }
      crate::misc::_init_tracing();
      let _opt = dotenv::dotenv().ok();
      let mut pair = $pair;
      let (pkg, pkgs_aux) = pair.parts_mut();
      let rslt = parts_cb_infer(pkg, pkgs_aux, $parts_cb).await;
      rslt_cb_infer(pkg, pkgs_aux, rslt, $rslt_cb).await;
    }
  };
}

#[cfg(test)]
macro_rules! _create_http_test {
  ($api:expr, $drsr_erp:expr, $test:ident, $cb:expr) => {
    _create_generic_test! {
      tokio,
      $test,
      {
        let (drsr, ext_req_params) = $drsr_erp;
        lucia::misc::Pair::new(
          crate::misc::PkgsAux::from_minimum($api, drsr, ext_req_params),
          reqwest::Client::default()
        )
      },
      $cb,
      |_, _, _| async {}
    }
  };
}

#[cfg(test)]
macro_rules! _create_ws_test {
  (
    $url:expr,
    $api:expr,
    $drsr_erp:expr,
    $sub:ident,
    ($($unsub:ident),+),
    $cb:expr
  ) => {
    _create_generic_test! {
      tokio,
      $sub,
      {
        let (drsr, ext_req_params) = $drsr_erp;
        let (trans, _) = tokio_tungstenite::connect_async($url).await.unwrap();
        lucia::misc::Pair::new(
          crate::misc::PkgsAux::from_minimum($api, drsr, ext_req_params),
          trans
        )
      },
      $cb,
      |pkgs_aux, trans, subs| async move {
        let mut iter = subs.into_iter();
        let ids = &mut [$( pkgs_aux.$unsub().data(iter.next().unwrap()).build(), )+][..];
        let _res = trans.send(&mut lucia::pkg::BatchPkg::new(ids), pkgs_aux).await.unwrap();
      }
    }
  };
}