substreams/
store.rs

1//! Store Implementation for Substreams.
2//!
3//! This module is the heart of all your interactions with your Substreams store needs be it setting values via
4//! Store or retrieving value via StoreGet and Delta.
5//!
6//! The DeltaExt trait when imported in your code will bring in must-use functions on Deltas iterator for filtering
7//! deltas based on its key or operationt. The [key] module is also available for extracting segments of a key.
8//!
9//! In a lot of use cases, you will encode data into your keys for example `user:<address>` or `position:<pool>:<id>`.
10//! The `DeltaExt` trait exists to pick up deltas that matches a specific key pattern as well as extracting segment of a key.
11//!
12//! The `DeltaExt` trait expects keys to be of the form `<segment>[:<segment>]*` (just like the [key] module) so the `:` is
13//! the segment separator. The module is meant to be used like this for filtering specific deltas and extracting specific segments:
14//!
15//! ```rust
16//! use substreams::key;
17//! use substreams::store::{Delta, DeltaExt, Deltas, DeltaBigDecimal};
18//!
19//! fn db_out(store: Deltas<DeltaBigDecimal>) {
20//!     for delta in store.into_iter().key_first_segment_eq("user") {
21//!         let address = key::segment_at(delta.get_key(), 1);
22//!
23//!         // Do something for this delta where the key was in format `user:<address>`
24//!     }
25//! }
26//! ```
27//!
28//! Or when filtering for multiple segments:
29//!
30//! ```rust
31//! use substreams::key;
32//! use substreams::store::{Delta, DeltaExt, Deltas, DeltaBigDecimal};
33//!
34//! fn db_out(store: Deltas<DeltaBigDecimal>) {
35//!     for delta in store.into_iter().key_first_segment_in(["user", "contract"]) {
36//!         // Do something for this delta where the key was in format `(user|contract):...`
37//!     }
38//! }
39//! ```
40//!
41//! You can also filter per operations and merge all this together:
42//!
43//! ```rust
44//! use substreams::key;
45//! use substreams::pb::substreams::store_delta::Operation;
46//! use substreams::store::{Delta, DeltaExt, Deltas, DeltaBigDecimal};
47//!
48//! fn db_out(store: Deltas<DeltaBigDecimal>) {
49//!     for delta in store
50//!         .iter()
51//!         .operation_eq(Operation::Create)
52//!         .key_first_segment_in(["user", "contract"])
53//!         .key_last_segment_eq("token0")
54//!    {
55//!         // Do something for Create delta where the key was in format `(user|contract):...:token0`
56//!     }
57//! }
58//! ```
59use std::{convert::TryFrom, io::BufRead, str};
60
61use crate::{
62    key, operation,
63    pb::{
64        sf::substreams::foundational_store::v1::{GetAllResponse, GetResponse},
65        substreams::store_delta::Operation,
66    },
67};
68use {
69    crate::{
70        pb::substreams::StoreDelta,
71        scalar::{BigDecimal, BigInt},
72        state, {pb, proto},
73    },
74    prost,
75    std::i64,
76    std::marker::PhantomData,
77    std::str::FromStr,
78};
79
80/// `StoreSet` is a trait which is implemented on any type of typed StoreSet
81pub trait StoreSet<V>: StoreNew + StoreDelete {
82    /// Set a given key to a given value, if the key existed before, it will be replaced.
83    fn set<K: AsRef<str>>(&self, ord: u64, key: K, value: &V);
84    /// Set many keys to a given values, if the key existed before, it will be replaced.
85    fn set_many<K: AsRef<str>>(&self, ord: u64, keys: &Vec<K>, value: &V);
86}
87
88pub trait StoreDelete {
89    /// Delete values in a store given prefixed string
90    fn delete_prefix(&self, ord: i64, prefix: &String) {
91        state::delete_prefix(ord, prefix);
92    }
93}
94
95pub trait StoreNew {
96    /// Create an instance of trait implementation
97    fn new() -> Self;
98}
99
100/// `StoreSetRaw` is a struct representing a `store` with `updatePolicy` equal to `set` on a `valueType` equal to `bytes`
101///     `StoreSetRaw` implements AsRef<[u8]> to give the client the flexibility
102///     to either use the API with &Vec[...] or Vec[...].
103pub struct StoreSetRaw {}
104impl StoreNew for StoreSetRaw {
105    fn new() -> Self {
106        Self {}
107    }
108}
109
110impl StoreDelete for StoreSetRaw {}
111
112impl<V: AsRef<[u8]>> StoreSet<V> for StoreSetRaw {
113    /// Set a given key to a given value, if the key existed before, it will be replaced.
114    fn set<K: AsRef<str>>(&self, ord: u64, key: K, value: &V) {
115        state::set(ord as i64, key, value);
116    }
117
118    /// Set many keys to a given values, if the key existed before, it will be replaced.
119    fn set_many<K: AsRef<str>>(&self, ord: u64, keys: &Vec<K>, value: &V) {
120        for key in keys {
121            state::set(ord as i64, key, value);
122        }
123    }
124}
125
126/// `StoreSetString` is a struct representing a `store` with `updatePolicy` equal to `set` on a `valueType` equal to `string`
127/// `StoreSetString` implements `AsRef<str>` to give the client the flexibility
128/// to either use the API with &String or String.
129pub struct StoreSetString {}
130impl StoreNew for StoreSetString {
131    fn new() -> Self {
132        Self {}
133    }
134}
135
136impl StoreDelete for StoreSetString {}
137
138impl<V: AsRef<str>> StoreSet<V> for StoreSetString {
139    fn set<K: AsRef<str>>(&self, ord: u64, key: K, value: &V) {
140        state::set(ord as i64, key, value.as_ref());
141    }
142
143    fn set_many<K: AsRef<str>>(&self, ord: u64, keys: &Vec<K>, value: &V) {
144        let value = value.as_ref();
145
146        for key in keys {
147            state::set(ord as i64, key, value);
148        }
149    }
150}
151
152/// `StoreSetInt64` is a struct representing a `store` with `updatePolicy` equal to `set` on a `valueType` equal to `int64`
153pub struct StoreSetInt64 {}
154impl StoreNew for StoreSetInt64 {
155    fn new() -> Self {
156        Self {}
157    }
158}
159
160impl StoreDelete for StoreSetInt64 {}
161
162impl StoreSet<i64> for StoreSetInt64 {
163    /// Set a given key to a given value, if the key existed before, it will be replaced.
164    fn set<K: AsRef<str>>(&self, ord: u64, key: K, value: &i64) {
165        state::set(ord as i64, key, value.to_string().as_bytes());
166    }
167
168    /// Set many keys to a given values, if the key existed before, it will be replaced.
169    fn set_many<K: AsRef<str>>(&self, ord: u64, keys: &Vec<K>, value: &i64) {
170        let as_str = value.to_string();
171
172        for key in keys {
173            state::set(ord as i64, key, &as_str);
174        }
175    }
176}
177
178/// `StoreSetFloat64` is a struct representing a `store` with `updatePolicy` equal to `set` on a `valueType` equal to `float64`
179pub struct StoreSetFloat64 {}
180impl StoreNew for StoreSetFloat64 {
181    fn new() -> Self {
182        Self {}
183    }
184}
185
186impl StoreDelete for StoreSetFloat64 {}
187
188impl StoreSet<f64> for StoreSetFloat64 {
189    /// Set a given key to a given value, if the key existed before, it will be replaced.
190    fn set<K: AsRef<str>>(&self, ord: u64, key: K, value: &f64) {
191        state::set(ord as i64, key, value.to_string().as_bytes());
192    }
193
194    /// Set many keys to a given values, if the key existed before, it will be replaced.
195    fn set_many<K: AsRef<str>>(&self, ord: u64, keys: &Vec<K>, value: &f64) {
196        let as_str = value.to_string();
197
198        for key in keys {
199            state::set(ord as i64, key, &as_str);
200        }
201    }
202}
203
204/// `StoreSetBigDecimal` is a struct representing a `store` with `updatePolicy` equal to `set` on a `valueType` equal to `bigdecimal`
205pub struct StoreSetBigDecimal {}
206impl StoreNew for StoreSetBigDecimal {
207    fn new() -> Self {
208        Self {}
209    }
210}
211
212impl StoreDelete for StoreSetBigDecimal {}
213
214impl StoreSet<BigDecimal> for StoreSetBigDecimal {
215    fn set<K: AsRef<str>>(&self, ord: u64, key: K, value: &BigDecimal) {
216        state::set(ord as i64, key, value.to_string().as_bytes())
217    }
218
219    fn set_many<K: AsRef<str>>(&self, ord: u64, keys: &Vec<K>, value: &BigDecimal) {
220        let as_str = value.to_string();
221
222        for key in keys {
223            state::set(ord as i64, key, &as_str)
224        }
225    }
226}
227
228/// `StoreSetBigInt` is a struct representing a `store` with `updatePolicy` equal to `set` on a `valueType` equal to `bigint`
229pub struct StoreSetBigInt {}
230impl StoreNew for StoreSetBigInt {
231    fn new() -> Self {
232        Self {}
233    }
234}
235
236impl StoreDelete for StoreSetBigInt {}
237
238impl StoreSet<BigInt> for StoreSetBigInt {
239    fn set<K: AsRef<str>>(&self, ord: u64, key: K, value: &BigInt) {
240        state::set(ord as i64, key, value.as_ref().to_string().as_bytes());
241    }
242
243    fn set_many<K: AsRef<str>>(&self, ord: u64, keys: &Vec<K>, value: &BigInt) {
244        let as_str = value.as_ref().to_string();
245
246        for key in keys {
247            state::set(ord as i64, key, &as_str);
248        }
249    }
250}
251
252/// `StoreSetProto` is a struct representing a `store` with `updatePolicy` equal to `set` and a `valueType` equal to `proto:{your_proto_type}`
253#[allow(dead_code)]
254pub struct StoreSetProto<V: Default + prost::Message> {
255    casper: PhantomData<V>,
256}
257
258impl<V: Default + prost::Message> StoreDelete for StoreSetProto<V> {}
259
260impl<V: Default + prost::Message> StoreNew for StoreSetProto<V> {
261    fn new() -> Self {
262        Self {
263            // Adding a PhantomData<T> field to your type tells the compiler that
264            // your type acts as though it stores a value of type T, even though
265            // it doesn't really. This information is used when computing certain
266            // safety properties. For a more in-depth explanation of how to use
267            // PhantomData<T>
268            casper: PhantomData,
269        }
270    }
271}
272
273impl<V: Default + prost::Message> StoreSet<V> for StoreSetProto<V> {
274    fn set<K: AsRef<str>>(&self, ord: u64, key: K, value: &V) {
275        let bytes = proto::encode(value)
276            .unwrap_or_else(|_| panic!("Unable to encode store message's struct to Protobuf data"));
277
278        state::set(ord as i64, key, &bytes)
279    }
280
281    fn set_many<K: AsRef<str>>(&self, ord: u64, keys: &Vec<K>, value: &V) {
282        let bytes = proto::encode(value)
283            .unwrap_or_else(|_| panic!("Unable to encode store message's struct to Protobuf data"));
284
285        for key in keys {
286            state::set(ord as i64, key, &bytes)
287        }
288    }
289}
290
291/// `StoreSetIfNotExists` is a trait which is implemented on any type of typed StoreSetIfNotExists
292pub trait StoreSetIfNotExists<V>: StoreDelete + StoreNew {
293    /// Set a given key to a given value, if the key existed before, it will be ignored and not set.
294    fn set_if_not_exists<K: AsRef<str>>(&self, ord: u64, key: K, value: &V);
295    /// Set given keys to given values, if the key existed before, it will be ignored and not set.
296    fn set_if_not_exists_many<K: AsRef<str>>(&self, ord: u64, keys: &Vec<K>, value: &V);
297}
298
299/// `StoreSetIfNotExistsRaw` is a struct representing a `store` module with `updatePolicy` equal to `set_if_not_exists` and a `valueType` equal to `string`
300///     `StoreSetIfNotExistsRaw` implements AsRef<[u8]> to give the client the flexibility
301///     to either use the API with &Vec[...] or Vec[...].
302pub struct StoreSetIfNotExistsRaw {}
303impl StoreNew for StoreSetIfNotExistsRaw {
304    fn new() -> Self {
305        Self {}
306    }
307}
308
309impl StoreDelete for StoreSetIfNotExistsRaw {}
310
311impl<V: AsRef<[u8]>> StoreSetIfNotExists<V> for StoreSetIfNotExistsRaw {
312    fn set_if_not_exists<K: AsRef<str>>(&self, ord: u64, key: K, value: &V) {
313        state::set_if_not_exists(ord as i64, key, value.as_ref());
314    }
315
316    fn set_if_not_exists_many<K: AsRef<str>>(&self, ord: u64, keys: &Vec<K>, value: &V) {
317        let value = value.as_ref();
318
319        for key in keys {
320            state::set_if_not_exists(ord as i64, key, value);
321        }
322    }
323}
324
325/// `StoreSetIfNotExistsString` is a struct representing a `store` module with `updatePolicy` equal to `set_if_not_exists` and a `valueType` equal to `string`
326/// `StoreSetIfNotExistsString` implements `AsRef<str>` to give the client the flexibility
327/// to either use the API with &String or String.
328pub struct StoreSetIfNotExistsString {}
329impl StoreNew for StoreSetIfNotExistsString {
330    fn new() -> Self {
331        Self {}
332    }
333}
334
335impl StoreDelete for StoreSetIfNotExistsString {}
336
337impl<V: AsRef<str>> StoreSetIfNotExists<V> for StoreSetIfNotExistsString {
338    fn set_if_not_exists<K: AsRef<str>>(&self, ord: u64, key: K, value: &V) {
339        state::set_if_not_exists(ord as i64, key, value.as_ref().as_bytes());
340    }
341
342    fn set_if_not_exists_many<K: AsRef<str>>(&self, ord: u64, keys: &Vec<K>, value: &V) {
343        let value = value.as_ref();
344
345        for key in keys {
346            state::set_if_not_exists(ord as i64, key, value);
347        }
348    }
349}
350
351/// `StoreSetIfNotExistsBigDecimal` is a struct representing a `store` module with `updatePolicy` equal to `set_if_not_exists` and a `valueType` equal to `bigdecimal`
352pub struct StoreSetIfNotExistsBigDecimal {}
353impl StoreNew for StoreSetIfNotExistsBigDecimal {
354    fn new() -> Self {
355        Self {}
356    }
357}
358
359impl StoreDelete for StoreSetIfNotExistsBigDecimal {}
360
361impl StoreSetIfNotExists<BigDecimal> for StoreSetIfNotExistsBigDecimal {
362    fn set_if_not_exists<K: AsRef<str>>(&self, ord: u64, key: K, value: &BigDecimal) {
363        state::set_if_not_exists(ord as i64, key, value.as_ref().to_string().as_bytes());
364    }
365
366    fn set_if_not_exists_many<K: AsRef<str>>(&self, ord: u64, keys: &Vec<K>, value: &BigDecimal) {
367        let as_str = value.to_string();
368
369        for key in keys {
370            state::set_if_not_exists(ord as i64, key, &as_str);
371        }
372    }
373}
374
375/// `StoreSetIfNotExistsBigInt` is a struct representing a `store` module with `updatePolicy` equal to `set_if_not_exists` and a `valueType` equal to `bigint`
376pub struct StoreSetIfNotExistsBigInt {}
377impl StoreNew for StoreSetIfNotExistsBigInt {
378    fn new() -> Self {
379        Self {}
380    }
381}
382
383impl StoreDelete for StoreSetIfNotExistsBigInt {}
384
385impl StoreSetIfNotExists<BigInt> for StoreSetIfNotExistsBigInt {
386    fn set_if_not_exists<K: AsRef<str>>(&self, ord: u64, key: K, value: &BigInt) {
387        state::set_if_not_exists(ord as i64, key, value.to_string().as_bytes());
388    }
389
390    fn set_if_not_exists_many<K: AsRef<str>>(&self, ord: u64, keys: &Vec<K>, value: &BigInt) {
391        let as_str = value.to_string();
392
393        for key in keys {
394            state::set_if_not_exists(ord as i64, key, &as_str);
395        }
396    }
397}
398
399/// `StoreSetIfNotExistsInt64` is a struct representing a `store` module with `updatePolicy` equal to `set_if_not_exists` and a `valueType` equal to `int64`
400pub struct StoreSetIfNotExistsInt64 {}
401impl StoreNew for StoreSetIfNotExistsInt64 {
402    fn new() -> Self {
403        Self {}
404    }
405}
406
407impl StoreDelete for StoreSetIfNotExistsInt64 {}
408
409impl StoreSetIfNotExists<i64> for StoreSetIfNotExistsInt64 {
410    fn set_if_not_exists<K: AsRef<str>>(&self, ord: u64, key: K, value: &i64) {
411        state::set_if_not_exists(ord as i64, key, value.to_string().as_bytes());
412    }
413
414    fn set_if_not_exists_many<K: AsRef<str>>(&self, ord: u64, keys: &Vec<K>, value: &i64) {
415        let as_str = value.to_string();
416
417        for key in keys {
418            state::set_if_not_exists(ord as i64, key, &as_str);
419        }
420    }
421}
422
423/// `StoreSetIfNotExistsFloat64` is a struct representing a `store` module with `updatePolicy` equal to `set_if_not_exists` and a `valueType` equal to `float64`
424pub struct StoreSetIfNotExistsFloat64 {}
425impl StoreNew for StoreSetIfNotExistsFloat64 {
426    fn new() -> Self {
427        Self {}
428    }
429}
430
431impl StoreDelete for StoreSetIfNotExistsFloat64 {}
432
433impl StoreSetIfNotExists<f64> for StoreSetIfNotExistsFloat64 {
434    fn set_if_not_exists<K: AsRef<str>>(&self, ord: u64, key: K, value: &f64) {
435        state::set_if_not_exists(ord as i64, key, value.to_string().as_bytes());
436    }
437
438    fn set_if_not_exists_many<K: AsRef<str>>(&self, ord: u64, keys: &Vec<K>, value: &f64) {
439        let as_str = value.to_string();
440
441        for key in keys {
442            state::set_if_not_exists(ord as i64, key, &as_str);
443        }
444    }
445}
446
447/// `StoreSetIfNotExistsProto` is a struct representing a `store` module with `updatePolicy` equal to `set_if_not_exists` and a `valueType` equal to `proto:{your_proto_type}`
448#[allow(dead_code)]
449pub struct StoreSetIfNotExistsProto<T> {
450    store: StoreSetIfNotExistsRaw,
451    casper: PhantomData<T>,
452}
453
454impl<V: Default + prost::Message> StoreNew for StoreSetIfNotExistsProto<V> {
455    fn new() -> Self {
456        StoreSetIfNotExistsProto {
457            store: StoreSetIfNotExistsRaw {},
458            // Adding a PhantomData<T> field to your type tells the compiler that
459            // your type acts as though it stores a value of type T, even though
460            // it doesn't really. This information is used when computing certain
461            // safety properties. For a more in-depth explanation of how to use
462            // PhantomData<T>
463            casper: PhantomData,
464        }
465    }
466}
467
468impl<V: Default + prost::Message> StoreDelete for StoreSetIfNotExistsProto<V> {}
469
470impl<V: Default + prost::Message> StoreSetIfNotExists<V> for StoreSetIfNotExistsProto<V> {
471    fn set_if_not_exists<K: AsRef<str>>(&self, ord: u64, key: K, value: &V) {
472        let bytes = proto::encode(value)
473            .unwrap_or_else(|_| panic!("Unable to encode store message's struct to Protobuf data"));
474
475        self.store.set_if_not_exists(ord, key, &bytes)
476    }
477
478    fn set_if_not_exists_many<K: AsRef<str>>(&self, ord: u64, keys: &Vec<K>, value: &V) {
479        let bytes = proto::encode(value)
480            .unwrap_or_else(|_| panic!("Unable to encode store message's struct to Protobuf data"));
481
482        for key in keys {
483            self.store.set_if_not_exists(ord, key, &bytes)
484        }
485    }
486}
487
488/// `StoreAdd` is a trait which is implemented on any type of types StoreAdd
489pub trait StoreAdd<V>: StoreDelete + StoreNew {
490    /// Add a given value to an already existing key
491    fn add<K: AsRef<str>>(&self, ord: u64, key: K, value: V);
492    /// Add multiple values to an already existing key
493    fn add_many<K: AsRef<str>>(&self, ord: u64, keys: &Vec<K>, value: V);
494}
495
496/// `StoreAddInt64` is a struct representing a `store` module with `updatePolicy` equal to `add` and a valueType of `int64`
497pub struct StoreAddInt64 {}
498impl StoreNew for StoreAddInt64 {
499    fn new() -> Self {
500        Self {}
501    }
502}
503
504impl StoreDelete for StoreAddInt64 {}
505
506impl StoreAdd<i64> for StoreAddInt64 {
507    fn add<K: AsRef<str>>(&self, ord: u64, key: K, value: i64) {
508        state::add_int64(ord as i64, key, value);
509    }
510
511    fn add_many<K: AsRef<str>>(&self, ord: u64, keys: &Vec<K>, value: i64) {
512        for key in keys {
513            state::add_int64(ord as i64, key, value);
514        }
515    }
516}
517
518/// `StoreAddFloat64` is a struct representing a `store` module with `updatePolicy` equal to `add` and a valueType of `float64`
519pub struct StoreAddFloat64 {}
520impl StoreNew for StoreAddFloat64 {
521    fn new() -> Self {
522        Self {}
523    }
524}
525
526impl StoreDelete for StoreAddFloat64 {}
527
528impl StoreAdd<f64> for StoreAddFloat64 {
529    fn add<K: AsRef<str>>(&self, ord: u64, key: K, value: f64) {
530        state::add_float64(ord as i64, key, value);
531    }
532
533    fn add_many<K: AsRef<str>>(&self, ord: u64, keys: &Vec<K>, value: f64) {
534        for key in keys {
535            state::add_float64(ord as i64, key, value);
536        }
537    }
538}
539
540/// `StoreAddBigDecimal` is a struct representing a `store` module with `updatePolicy` equal to `add` and a valueType of `bigdecimal`
541/// `StoreAddBigDecimal` implements `AsRef<BigInt>` to give the client the flexibility
542/// to either use the API with &BigDecimal or BigDecimal.
543pub struct StoreAddBigDecimal {}
544impl StoreNew for StoreAddBigDecimal {
545    fn new() -> Self {
546        Self {}
547    }
548}
549
550impl StoreDelete for StoreAddBigDecimal {}
551
552impl<V: AsRef<BigDecimal>> StoreAdd<V> for StoreAddBigDecimal {
553    fn add<K: AsRef<str>>(&self, ord: u64, key: K, value: V) {
554        state::add_bigdecimal(ord as i64, key, value.as_ref());
555    }
556
557    fn add_many<K: AsRef<str>>(&self, ord: u64, keys: &Vec<K>, value: V) {
558        let value = value.as_ref();
559
560        for key in keys {
561            state::add_bigdecimal(ord as i64, key, value);
562        }
563    }
564}
565
566/// `StoreAddBigInt` is a struct representing a `store` module with `updatePolicy` equal to `add` and a valueType of `bigint`
567/// `StoreAddBigInt` implements `AsRef<BigInt>` to give the client the flexibility
568/// to either use the API with &BigInt or BigInt.
569pub struct StoreAddBigInt {}
570impl StoreNew for StoreAddBigInt {
571    fn new() -> Self {
572        Self {}
573    }
574}
575
576impl StoreDelete for StoreAddBigInt {}
577
578impl<V: AsRef<BigInt>> StoreAdd<V> for StoreAddBigInt {
579    fn add<K: AsRef<str>>(&self, ord: u64, key: K, value: V) {
580        state::add_bigint(ord as i64, key, value.as_ref());
581    }
582
583    fn add_many<K: AsRef<str>>(&self, ord: u64, keys: &Vec<K>, value: V) {
584        let value = value.as_ref();
585
586        for key in keys {
587            state::add_bigint(ord as i64, key, value);
588        }
589    }
590}
591
592/// `StoreMax` is a trait which is implemented on any type of typed StoreMax
593pub trait StoreMax<V>: StoreNew + StoreDelete {
594    /// max will set the provided key in the store only if the value received in
595    /// parameter is bigger than the one already present in the store, with
596    /// a default of the zero value when the key is absent.
597    fn max<K: AsRef<str>>(&self, ord: u64, key: K, value: V);
598}
599
600/// `StoreMaxInt64` is a struct representing a `store` module with `updatePolicy` equal to `max` and a valueType of `int64`
601pub struct StoreMaxInt64 {}
602impl StoreNew for StoreMaxInt64 {
603    fn new() -> Self {
604        Self {}
605    }
606}
607
608impl StoreDelete for StoreMaxInt64 {}
609
610impl StoreMax<i64> for StoreMaxInt64 {
611    fn max<K: AsRef<str>>(&self, ord: u64, key: K, value: i64) {
612        state::set_max_int64(ord as i64, key, value);
613    }
614}
615
616/// `StoreMaxBigInt` is a struct representing a `store` module with `updatePolicy` equal to `max` and a valueType of `bigint`
617/// `StoreMaxBigInt` implements `AsRef<BigInt>` to give the client the flexibility
618/// to either use the API with &BigInt or BigInt.
619pub struct StoreMaxBigInt {}
620impl StoreNew for StoreMaxBigInt {
621    fn new() -> Self {
622        Self {}
623    }
624}
625
626impl StoreDelete for StoreMaxBigInt {}
627
628impl<V: AsRef<BigInt>> StoreMax<V> for StoreMaxBigInt {
629    fn max<K: AsRef<str>>(&self, ord: u64, key: K, value: V) {
630        state::set_max_bigint(ord as i64, key, value.as_ref());
631    }
632}
633
634/// `StoreMaxFloat64` is a struct representing a `store` module with `updatePolicy` equal to `max` and a valueType of `float64`
635pub struct StoreMaxFloat64 {}
636impl StoreNew for StoreMaxFloat64 {
637    fn new() -> Self {
638        Self {}
639    }
640}
641
642impl StoreDelete for StoreMaxFloat64 {}
643
644impl StoreMax<f64> for StoreMaxFloat64 {
645    fn max<K: AsRef<str>>(&self, ord: u64, key: K, value: f64) {
646        state::set_max_float64(ord as i64, key, value);
647    }
648}
649
650/// `StoreMaxBigDecimal` is a struct representing a `store` module with `updatePolicy` equal to `max` and a valueType of `bigdecimal`
651/// `StoreMaxBigDecimal` implements `AsRef<BigDecimal>` to give the client the flexibility
652/// to either use the API with &BigDecimal or BigDecimal.
653pub struct StoreMaxBigDecimal {}
654impl StoreNew for StoreMaxBigDecimal {
655    fn new() -> Self {
656        Self {}
657    }
658}
659
660impl StoreDelete for StoreMaxBigDecimal {}
661
662impl<V: AsRef<BigDecimal>> StoreMax<V> for StoreMaxBigDecimal {
663    fn max<K: AsRef<str>>(&self, ord: u64, key: K, value: V) {
664        state::set_max_bigdecimal(ord as i64, key, value.as_ref());
665    }
666}
667
668/// `StoreMin` is a trait which is implemented on any typed StoreMin
669pub trait StoreMin<V>: StoreNew + StoreDelete {
670    /// Will set the provided key in the store only if the value received in
671    /// parameter is smaller than the one already present in the store, with
672    /// a default of the zero value when the key is absent.
673    fn min<K: AsRef<str>>(&self, ord: u64, key: K, value: V);
674}
675
676/// `StoreMinInt64` is a struct representing a `store` module with `updatePolicy` equal to `min` and a valueType of `int64`
677pub struct StoreMinInt64 {}
678impl StoreNew for StoreMinInt64 {
679    fn new() -> Self {
680        Self {}
681    }
682}
683
684impl StoreDelete for StoreMinInt64 {}
685
686impl StoreMin<i64> for StoreMinInt64 {
687    fn min<K: AsRef<str>>(&self, ord: u64, key: K, value: i64) {
688        state::set_min_int64(ord as i64, key, value);
689    }
690}
691
692/// `StoreMinBigInt` is a struct representing a `store` module with `updatePolicy` equal to `min` and a valueType of `bigint`
693/// `StoreMinBigInt` implements `AsRef<BigInt>` to give the client the flexibility
694/// to either use the API with &BigInt or BigInt.
695pub struct StoreMinBigInt {}
696impl StoreNew for StoreMinBigInt {
697    fn new() -> Self {
698        Self {}
699    }
700}
701
702impl StoreDelete for StoreMinBigInt {}
703
704impl<V: AsRef<BigInt>> StoreMin<V> for StoreMinBigInt {
705    fn min<K: AsRef<str>>(&self, ord: u64, key: K, value: V) {
706        state::set_min_bigint(ord as i64, key, value.as_ref());
707    }
708}
709
710/// `StoreMinFloat64` is a struct representing a `store` module with `updatePolicy` equal to `min` and a valueType of `float64`
711pub struct StoreMinFloat64 {}
712impl StoreNew for StoreMinFloat64 {
713    fn new() -> Self {
714        Self {}
715    }
716}
717
718impl StoreDelete for StoreMinFloat64 {}
719
720impl StoreMin<f64> for StoreMinFloat64 {
721    fn min<K: AsRef<str>>(&self, ord: u64, key: K, value: f64) {
722        state::set_min_float64(ord as i64, key, value);
723    }
724}
725
726/// `StoreMinBigDecimal` is a struct representing a `store` module with `updatePolicy` equal to `min` and a valueType of `bigdecimal`
727/// `StoreMinBigDecimal` implements `AsRef<BigDecimal>` to give the client the flexibility to either use
728/// the API with &BigDecimal or BigDecimal.
729pub struct StoreMinBigDecimal {}
730impl StoreNew for StoreMinBigDecimal {
731    fn new() -> Self {
732        Self {}
733    }
734}
735
736impl StoreDelete for StoreMinBigDecimal {}
737
738impl<V: AsRef<BigDecimal>> StoreMin<V> for StoreMinBigDecimal {
739    fn min<K: AsRef<str>>(&self, ord: u64, key: K, value: V) {
740        state::set_min_bigdecimal(ord as i64, key, value.as_ref());
741    }
742}
743
744// -------------------- Appender -------------------- //
745pub trait Appender<T> {
746    fn new() -> Self;
747    fn append<K: AsRef<str>>(&self, ord: u64, key: K, item: T);
748    fn append_all<K: AsRef<str>>(&self, ord: u64, key: K, items: Vec<T>);
749}
750
751/// StoreAppend is a struct representing a `store` with
752/// `updatePolicy` equal to `append`
753pub struct StoreAppend<T> {
754    casper: PhantomData<T>,
755}
756
757impl<T> Appender<T> for StoreAppend<T>
758where
759    T: Into<String>,
760{
761    fn new() -> Self {
762        StoreAppend {
763            casper: PhantomData,
764        }
765    }
766
767    /// Concatenates a given value at the end of the key's current value
768    fn append<K: AsRef<str>>(&self, ord: u64, key: K, item: T) {
769        let item: String = item.into();
770        state::append(ord as i64, &key, &format!("{};", &item).as_bytes());
771    }
772
773    fn append_all<K: AsRef<str>>(&self, ord: u64, key: K, items: Vec<T>) {
774        for item in items {
775            self.append(ord, &key, item);
776        }
777    }
778}
779
780// -------------------- StoreSetSum -------------------- //
781pub trait StoreSetSum<T> {
782    fn new() -> Self;
783    fn set<K: AsRef<str>>(&self, ord: u64, key: K, value: T);
784    fn sum<K: AsRef<str>>(&self, ord: u64, key: K, value: T);
785}
786
787pub struct StoreSetSumInt64 {}
788
789impl StoreSetSum<i64> for StoreSetSumInt64 {
790    fn new() -> Self {
791        StoreSetSumInt64 {}
792    }
793
794    fn set<K: AsRef<str>>(&self, ord: u64, key: K, value: i64) {
795        let v = format!("set:{}", value.to_string());
796        state::set_sum_int64(ord as i64, key, v);
797    }
798
799    fn sum<K: AsRef<str>>(&self, ord: u64, key: K, value: i64) {
800        let v = format!("sum:{}", value.to_string());
801        state::set_sum_int64(ord as i64, key, v);
802    }
803}
804
805pub struct StoreSetSumFloat64 {}
806
807impl StoreSetSum<f64> for StoreSetSumFloat64 {
808    fn new() -> Self {
809        StoreSetSumFloat64 {}
810    }
811
812    fn set<K: AsRef<str>>(&self, ord: u64, key: K, value: f64) {
813        let v = format!("set:{}", value.to_string());
814        state::set_sum_float64(ord as i64, key, v);
815    }
816
817    fn sum<K: AsRef<str>>(&self, ord: u64, key: K, value: f64) {
818        let v = format!("sum:{}", value.to_string());
819        state::set_sum_float64(ord as i64, key, v);
820    }
821}
822
823pub struct StoreSetSumBigInt {}
824
825impl StoreSetSum<BigInt> for StoreSetSumBigInt {
826    fn new() -> Self {
827        StoreSetSumBigInt {}
828    }
829
830    fn set<K: AsRef<str>>(&self, ord: u64, key: K, value: BigInt) {
831        let v = format!("set:{}", value.to_string());
832        state::set_sum_bigint(ord as i64, key, v);
833    }
834
835    fn sum<K: AsRef<str>>(&self, ord: u64, key: K, value: BigInt) {
836        let v = format!("sum:{}", value.to_string());
837        state::set_sum_bigint(ord as i64, key, v);
838    }
839}
840
841pub struct StoreSetSumBigDecimal {}
842
843impl StoreSetSum<BigDecimal> for StoreSetSumBigDecimal {
844    fn new() -> Self {
845        StoreSetSumBigDecimal {}
846    }
847
848    fn set<K: AsRef<str>>(&self, ord: u64, key: K, value: BigDecimal) {
849        let v = format!("set:{}", value.to_string());
850        state::set_sum_bigdecimal(ord as i64, key, v);
851    }
852
853    fn sum<K: AsRef<str>>(&self, ord: u64, key: K, value: BigDecimal) {
854        let v = format!("sum:{}", value.to_string());
855        state::set_sum_bigdecimal(ord as i64, key, v);
856    }
857}
858
859// -------------------- StoreGet -------------------- //
860/// StoreGet is a trait which is implemented on any type of typed StoreGet
861pub trait StoreGet<T> {
862    fn new(idx: u32) -> Self;
863    fn get_at<K: AsRef<str>>(&self, ord: u64, key: K) -> Option<T>;
864    fn get_last<K: AsRef<str>>(&self, key: K) -> Option<T>;
865    fn get_first<K: AsRef<str>>(&self, key: K) -> Option<T>;
866    fn has_at<K: AsRef<str>>(&self, ord: u64, key: K) -> bool;
867    fn has_last<K: AsRef<str>>(&self, key: K) -> bool;
868    fn has_first<K: AsRef<str>>(&self, key: K) -> bool;
869}
870
871/// RawStoreGet is a struct representing a read only store `store`
872pub struct StoreGetRaw {
873    idx: u32,
874}
875
876impl StoreGet<Vec<u8>> for StoreGetRaw {
877    /// Return a StoreGet object with a store index set
878    fn new(idx: u32) -> StoreGetRaw {
879        StoreGetRaw { idx }
880    }
881
882    /// Allows you to read a single key from the store. The type
883    /// of its value can be anything, and is usually declared in
884    /// the output section of the manifest. The ordinal is used here
885    /// to go query a key that might have changed mid-block by
886    /// the store module that built it.
887    fn get_at<K: AsRef<str>>(&self, ord: u64, key: K) -> Option<Vec<u8>> {
888        state::get_at(self.idx, ord as i64, key)
889    }
890
891    /// Retrieves a key from the store, like `get_at`, but querying the state of
892    /// the store as of the end of the block being processed, after all changes
893    /// were applied within the current block. It does not need to rewind any changes
894    /// as the store's state we work with is the state at the end of block already.
895    fn get_last<K: AsRef<str>>(&self, key: K) -> Option<Vec<u8>> {
896        state::get_last(self.idx, key)
897    }
898
899    /// Retrieves a key from the store, like `get_at`, but querying the state of
900    /// the store as of the beginning of the block being processed, before any changes
901    /// were applied within the current block. However, it needs to unwind any keys that
902    /// would have changed in the block, so will be slightly less performant.
903    fn get_first<K: AsRef<str>>(&self, key: K) -> Option<Vec<u8>> {
904        state::get_first(self.idx, key)
905    }
906
907    /// Checks if a key exists in the store. The ordinal is used here
908    /// to check if a key that might have changed mid-block by
909    /// the store module that built it exists.
910    fn has_at<K: AsRef<str>>(&self, ord: u64, key: K) -> bool {
911        state::has_at(self.idx, ord as i64, key)
912    }
913
914    /// Checks if a key exists in the store, like `has_at`, but querying the state of
915    /// the store as of the beginning of the block being processed, before any changes
916    /// were applied within the current block. It does not need to rewind any changes
917    /// in the middle of the block.
918    fn has_last<K: AsRef<str>>(&self, key: K) -> bool {
919        state::has_last(self.idx, key)
920    }
921
922    /// Checks if a key exists in the store, like `has_at`, but querying the state of
923    /// the store as of the beginning of the block being processed, before any changes
924    /// were applied within the current block. However, it needs to unwind any keys that
925    /// would have changed mid-block, so will be slightly less performant.
926    fn has_first<K: AsRef<str>>(&self, key: K) -> bool {
927        state::has_first(self.idx, key)
928    }
929}
930
931/// StoreGetString is as struct representing a read only store `store`
932pub struct StoreGetString {
933    idx: u32,
934}
935
936impl StoreGet<String> for StoreGetString {
937    fn new(idx: u32) -> Self {
938        StoreGetString { idx }
939    }
940
941    fn get_at<K: AsRef<str>>(&self, ord: u64, key: K) -> Option<String> {
942        let key_ref = key.as_ref();
943
944        state::get_at(self.idx, ord as i64, key_ref).map(|bytes| {
945            String::from_utf8(bytes).unwrap_or_else(|_| {
946                panic!("Invalid UTF-8 sequence in store value for key: {}", key_ref)
947            })
948        })
949    }
950
951    fn get_last<K: AsRef<str>>(&self, key: K) -> Option<String> {
952        let key_ref = key.as_ref();
953
954        state::get_last(self.idx, key_ref).map(|bytes| {
955            String::from_utf8(bytes).unwrap_or_else(|_| {
956                panic!("Invalid UTF-8 sequence in store value for key: {}", key_ref)
957            })
958        })
959    }
960
961    fn get_first<K: AsRef<str>>(&self, key: K) -> Option<String> {
962        let key_ref = key.as_ref();
963
964        state::get_first(self.idx, key_ref).map(|bytes| {
965            String::from_utf8(bytes).unwrap_or_else(|_| {
966                panic!("Invalid UTF-8 sequence in store value for key: {}", key_ref)
967            })
968        })
969    }
970
971    fn has_at<K: AsRef<str>>(&self, ord: u64, key: K) -> bool {
972        state::has_at(self.idx, ord as i64, key)
973    }
974
975    fn has_last<K: AsRef<str>>(&self, key: K) -> bool {
976        state::has_last(self.idx, key)
977    }
978
979    fn has_first<K: AsRef<str>>(&self, key: K) -> bool {
980        state::has_first(self.idx, key)
981    }
982}
983
984pub struct StoreGetInt64(StoreGetRaw);
985impl StoreGet<i64> for StoreGetInt64 {
986    fn new(idx: u32) -> Self {
987        Self {
988            0: StoreGetRaw { idx },
989        }
990    }
991
992    fn get_at<K: AsRef<str>>(&self, ord: u64, key: K) -> Option<i64> {
993        state::get_at(self.0.idx, ord as i64, key)
994            .as_ref()
995            .map(decode_bytes_to_i64)
996    }
997
998    fn get_last<K: AsRef<str>>(&self, key: K) -> Option<i64> {
999        state::get_last(self.0.idx, key)
1000            .as_ref()
1001            .map(decode_bytes_to_i64)
1002    }
1003
1004    fn get_first<K: AsRef<str>>(&self, key: K) -> Option<i64> {
1005        state::get_first(self.0.idx, key)
1006            .as_ref()
1007            .map(decode_bytes_to_i64)
1008    }
1009
1010    fn has_at<K: AsRef<str>>(&self, ord: u64, key: K) -> bool {
1011        state::has_at(self.0.idx, ord as i64, key)
1012    }
1013
1014    fn has_last<K: AsRef<str>>(&self, key: K) -> bool {
1015        state::has_last(self.0.idx, key)
1016    }
1017
1018    fn has_first<K: AsRef<str>>(&self, key: K) -> bool {
1019        state::has_first(self.0.idx, key)
1020    }
1021}
1022
1023pub struct StoreGetFloat64(StoreGetRaw);
1024impl StoreGet<f64> for StoreGetFloat64 {
1025    fn new(idx: u32) -> Self {
1026        Self {
1027            0: StoreGetRaw { idx },
1028        }
1029    }
1030
1031    fn get_at<K: AsRef<str>>(&self, ord: u64, key: K) -> Option<f64> {
1032        state::get_at(self.0.idx, ord as i64, key)
1033            .as_ref()
1034            .map(decode_bytes_to_f64)
1035    }
1036
1037    fn get_last<K: AsRef<str>>(&self, key: K) -> Option<f64> {
1038        state::get_last(self.0.idx, key)
1039            .as_ref()
1040            .map(decode_bytes_to_f64)
1041    }
1042
1043    fn get_first<K: AsRef<str>>(&self, key: K) -> Option<f64> {
1044        state::get_first(self.0.idx, key)
1045            .as_ref()
1046            .map(decode_bytes_to_f64)
1047    }
1048
1049    fn has_at<K: AsRef<str>>(&self, ord: u64, key: K) -> bool {
1050        state::has_at(self.0.idx, ord as i64, key)
1051    }
1052
1053    fn has_last<K: AsRef<str>>(&self, key: K) -> bool {
1054        state::has_last(self.0.idx, key)
1055    }
1056
1057    fn has_first<K: AsRef<str>>(&self, key: K) -> bool {
1058        state::has_first(self.0.idx, key)
1059    }
1060}
1061
1062pub struct StoreGetBigDecimal(StoreGetRaw);
1063impl StoreGet<BigDecimal> for StoreGetBigDecimal {
1064    fn new(idx: u32) -> Self {
1065        Self {
1066            0: StoreGetRaw { idx },
1067        }
1068    }
1069
1070    fn get_at<K: AsRef<str>>(&self, ord: u64, key: K) -> Option<BigDecimal> {
1071        state::get_at(self.0.idx, ord as i64, key).map(|bytes| BigDecimal::from_store_bytes(&bytes))
1072    }
1073
1074    fn get_last<K: AsRef<str>>(&self, key: K) -> Option<BigDecimal> {
1075        state::get_last(self.0.idx, key).map(|bytes| BigDecimal::from_store_bytes(&bytes))
1076    }
1077
1078    fn get_first<K: AsRef<str>>(&self, key: K) -> Option<BigDecimal> {
1079        state::get_first(self.0.idx, key).map(|bytes| BigDecimal::from_store_bytes(&bytes))
1080    }
1081
1082    fn has_at<K: AsRef<str>>(&self, ord: u64, key: K) -> bool {
1083        state::has_at(self.0.idx, ord as i64, key)
1084    }
1085
1086    fn has_last<K: AsRef<str>>(&self, key: K) -> bool {
1087        state::has_last(self.0.idx, key)
1088    }
1089
1090    fn has_first<K: AsRef<str>>(&self, key: K) -> bool {
1091        state::has_first(self.0.idx, key)
1092    }
1093}
1094
1095pub struct StoreGetBigInt(StoreGetRaw);
1096impl StoreGet<BigInt> for StoreGetBigInt {
1097    fn new(idx: u32) -> Self {
1098        Self {
1099            0: StoreGetRaw { idx },
1100        }
1101    }
1102
1103    fn get_at<K: AsRef<str>>(&self, ord: u64, key: K) -> Option<BigInt> {
1104        state::get_at(self.0.idx, ord as i64, key).map(|bytes| BigInt::from_store_bytes(&bytes))
1105    }
1106
1107    fn get_last<K: AsRef<str>>(&self, key: K) -> Option<BigInt> {
1108        state::get_last(self.0.idx, key).map(|bytes| BigInt::from_store_bytes(&bytes))
1109    }
1110
1111    fn get_first<K: AsRef<str>>(&self, key: K) -> Option<BigInt> {
1112        state::get_first(self.0.idx, key).map(|bytes| BigInt::from_store_bytes(&bytes))
1113    }
1114
1115    fn has_at<K: AsRef<str>>(&self, ord: u64, key: K) -> bool {
1116        state::has_at(self.0.idx, ord as i64, key)
1117    }
1118
1119    fn has_last<K: AsRef<str>>(&self, key: K) -> bool {
1120        state::has_last(self.0.idx, key)
1121    }
1122
1123    fn has_first<K: AsRef<str>>(&self, key: K) -> bool {
1124        state::has_first(self.0.idx, key)
1125    }
1126}
1127
1128#[allow(dead_code)]
1129pub struct StoreGetArray<T> {
1130    store: StoreGetRaw,
1131    casper: PhantomData<T>,
1132}
1133
1134impl<T: Into<String> + From<String>> StoreGet<Vec<T>> for StoreGetArray<T> {
1135    fn new(idx: u32) -> Self {
1136        Self {
1137            store: StoreGetRaw { idx },
1138            casper: PhantomData,
1139        }
1140    }
1141
1142    fn get_at<K: AsRef<str>>(&self, ord: u64, key: K) -> Option<Vec<T>> {
1143        self.store.get_at(ord, key).and_then(split_array)
1144    }
1145
1146    fn get_last<K: AsRef<str>>(&self, key: K) -> Option<Vec<T>> {
1147        self.store.get_last(key).and_then(split_array)
1148    }
1149
1150    fn get_first<K: AsRef<str>>(&self, key: K) -> Option<Vec<T>> {
1151        self.store.get_first(key).and_then(split_array)
1152    }
1153
1154    fn has_at<K: AsRef<str>>(&self, ord: u64, key: K) -> bool {
1155        self.store.has_at(ord, key)
1156    }
1157
1158    fn has_last<K: AsRef<str>>(&self, key: K) -> bool {
1159        self.store.has_last(key)
1160    }
1161
1162    fn has_first<K: AsRef<str>>(&self, key: K) -> bool {
1163        self.store.has_first(key)
1164    }
1165}
1166
1167fn split_array<T: Into<String> + From<String>>(bytes: Vec<u8>) -> Option<Vec<T>> {
1168    let parts = std::io::Cursor::new(bytes).split(b';');
1169    let chunks: Vec<_> = parts
1170        .map(|x| x.expect("Cursor is infallible"))
1171        .filter(|x| x.len() > 0)
1172        .map(|part| {
1173            String::from_utf8(part)
1174                .unwrap_or_else(|_| panic!("Invalid UTF-8 sequence in store value"))
1175                .into()
1176        })
1177        .collect();
1178
1179    match chunks.len() {
1180        0 => None,
1181        _ => Some(chunks),
1182    }
1183}
1184
1185#[allow(dead_code)]
1186pub struct StoreGetProto<T> {
1187    store: StoreGetRaw,
1188    casper: PhantomData<T>,
1189}
1190
1191impl<T: Default + prost::Message> StoreGetProto<T> {
1192    pub fn must_get_last<K: AsRef<str>>(&self, key: K) -> T {
1193        self.get_last(&key)
1194            .unwrap_or_else(|| panic!("cannot get_last value: key {} not found", key.as_ref()))
1195    }
1196}
1197
1198impl<T> StoreGet<T> for StoreGetProto<T>
1199where
1200    T: Default + prost::Message,
1201{
1202    /// Return a StoreGet object with a store index set
1203    fn new(idx: u32) -> StoreGetProto<T> {
1204        StoreGetProto {
1205            store: StoreGetRaw { idx },
1206            casper: PhantomData,
1207        }
1208    }
1209
1210    fn get_at<K: AsRef<str>>(&self, ord: u64, key: K) -> Option<T> {
1211        self.store
1212            .get_at(ord, key)
1213            .and_then(|bytes| proto::decode::<T>(&bytes).ok())
1214    }
1215
1216    fn get_last<K: AsRef<str>>(&self, key: K) -> Option<T> {
1217        self.store
1218            .get_last(key)
1219            .and_then(|bytes| proto::decode::<T>(&bytes).ok())
1220    }
1221
1222    fn get_first<K: AsRef<str>>(&self, key: K) -> Option<T> {
1223        self.store
1224            .get_first(key)
1225            .and_then(|bytes| proto::decode::<T>(&bytes).ok())
1226    }
1227
1228    fn has_at<K: AsRef<str>>(&self, ord: u64, key: K) -> bool {
1229        self.store.has_at(ord, key)
1230    }
1231
1232    fn has_last<K: AsRef<str>>(&self, key: K) -> bool {
1233        self.store.has_last(key)
1234    }
1235
1236    fn has_first<K: AsRef<str>>(&self, key: K) -> bool {
1237        self.store.has_first(key)
1238    }
1239}
1240
1241pub trait Delta: PartialEq {
1242    fn get_key(&self) -> &String;
1243    fn get_operation(&self) -> pb::substreams::store_delta::Operation;
1244}
1245
1246pub trait DeltaExt: Iterator {
1247    /// Equivalent to `filter(|x| segment(x.get_key(), index) == value)`.
1248    fn key_segment_at_eq<S: AsRef<str>>(self, index: usize, value: S) -> key::SegmentAtEq<Self, S>
1249    where
1250        Self::Item: Delta,
1251        Self: Sized,
1252    {
1253        key::SegmentAtEq::new(value, Some(index), self)
1254    }
1255
1256    /// Equivalent to `filter(|x| first_segment(x.get_key(), index) == value)`.
1257    fn key_first_segment_eq<S: AsRef<str>>(self, value: S) -> key::SegmentAtEq<Self, S>
1258    where
1259        Self::Item: Delta,
1260        Self: Sized,
1261    {
1262        key::SegmentAtEq::new(value, Some(0), self)
1263    }
1264
1265    /// Equivalent to `filter(|x| last_segment(x.get_key(), index) == value)`.
1266    fn key_last_segment_eq<S: AsRef<str>>(self, value: S) -> key::SegmentAtEq<Self, S>
1267    where
1268        Self::Item: Delta,
1269        Self: Sized,
1270    {
1271        key::SegmentAtEq::new(value, None, self)
1272    }
1273
1274    /// Equivalent to `filter(|x| values.contains(first_segment(x.get_key(), index)))`.
1275    fn key_first_segment_in<S: AsRef<str>, V: AsRef<[S]>>(
1276        self,
1277        values: V,
1278    ) -> key::SegmentAtIn<Self, S, V>
1279    where
1280        Self::Item: Delta,
1281        Self: Sized,
1282    {
1283        key::SegmentAtIn::new(values, Some(0), self)
1284    }
1285
1286    /// Equivalent to `filter(|x| values.contains(last_segment(x.get_key(), index)))`.
1287    fn key_last_segment_in<S: AsRef<str>, V: AsRef<[S]>>(
1288        self,
1289        values: V,
1290    ) -> key::SegmentAtIn<Self, S, V>
1291    where
1292        Self::Item: Delta,
1293        Self: Sized,
1294    {
1295        key::SegmentAtIn::new(values, None, self)
1296    }
1297
1298    /// Equivalent to `filter(|x| x.get_operation() == operation)`.
1299    fn operation_eq(self, operation: Operation) -> operation::OperationIs<Self>
1300    where
1301        Self::Item: Delta,
1302        Self: Sized,
1303    {
1304        operation::OperationIs::new(operation, false, self)
1305    }
1306
1307    /// Equivalent to `filter(|x| x.get_operation() != operation)`.
1308    fn operation_not_eq(self, operation: Operation) -> operation::OperationIs<Self>
1309    where
1310        Self::Item: Delta,
1311        Self: Sized,
1312    {
1313        operation::OperationIs::new(operation, true, self)
1314    }
1315}
1316
1317impl<I: Iterator> DeltaExt for I {}
1318
1319#[derive(Debug, Clone, PartialEq)]
1320pub struct Deltas<T: Delta> {
1321    pub deltas: Vec<T>,
1322}
1323
1324impl<T: Delta + From<StoreDelta>> Deltas<T> {
1325    pub fn new(store_deltas: Vec<StoreDelta>) -> Self {
1326        Deltas {
1327            deltas: store_deltas.into_iter().map(Into::into).collect(),
1328        }
1329    }
1330
1331    /// Shortcut for `self.deltas.iter()`.
1332    pub fn iter(&self) -> impl Iterator<Item = &T> {
1333        self.deltas.iter()
1334    }
1335
1336    /// Shortcut for `self.deltas.into_iter()`.
1337    pub fn into_iter(self) -> impl Iterator<Item = T> {
1338        self.deltas.into_iter()
1339    }
1340}
1341
1342#[derive(Debug, Clone, PartialEq)]
1343pub struct DeltaBigDecimal {
1344    pub operation: pb::substreams::store_delta::Operation,
1345    pub ordinal: u64,
1346    pub key: String,
1347    pub old_value: BigDecimal,
1348    pub new_value: BigDecimal,
1349}
1350
1351impl From<StoreDelta> for DeltaBigDecimal {
1352    fn from(d: StoreDelta) -> Self {
1353        Self {
1354            operation: convert_i32_to_operation(d.operation),
1355            ordinal: d.ordinal,
1356            key: d.key,
1357            old_value: BigDecimal::from_store_bytes(&d.old_value),
1358            new_value: BigDecimal::from_store_bytes(&d.new_value),
1359        }
1360    }
1361}
1362
1363#[derive(Debug, Clone, PartialEq)]
1364pub struct DeltaBigInt {
1365    pub operation: pb::substreams::store_delta::Operation,
1366    pub ordinal: u64,
1367    pub key: String,
1368    pub old_value: BigInt,
1369    pub new_value: BigInt,
1370}
1371
1372impl From<StoreDelta> for DeltaBigInt {
1373    fn from(d: StoreDelta) -> Self {
1374        Self {
1375            operation: convert_i32_to_operation(d.operation),
1376            ordinal: d.ordinal,
1377            key: d.key,
1378            old_value: BigInt::from_store_bytes(&d.old_value),
1379            new_value: BigInt::from_store_bytes(&d.new_value),
1380        }
1381    }
1382}
1383
1384#[derive(Debug, Clone, PartialEq)]
1385pub struct DeltaInt32 {
1386    pub operation: pb::substreams::store_delta::Operation,
1387    pub ordinal: u64,
1388    pub key: String,
1389    pub old_value: i32,
1390    pub new_value: i32,
1391}
1392
1393impl From<StoreDelta> for DeltaInt32 {
1394    fn from(d: StoreDelta) -> Self {
1395        Self {
1396            operation: convert_i32_to_operation(d.operation),
1397            ordinal: d.ordinal,
1398            key: d.key,
1399            old_value: decode_bytes_to_i32(&d.old_value),
1400            new_value: decode_bytes_to_i32(&d.new_value),
1401        }
1402    }
1403}
1404
1405#[derive(Debug, Clone, PartialEq)]
1406pub struct DeltaInt64 {
1407    pub operation: pb::substreams::store_delta::Operation,
1408    pub ordinal: u64,
1409    pub key: String,
1410    pub old_value: i64,
1411    pub new_value: i64,
1412}
1413
1414impl From<StoreDelta> for DeltaInt64 {
1415    fn from(d: StoreDelta) -> Self {
1416        Self {
1417            operation: convert_i32_to_operation(d.operation),
1418            ordinal: d.ordinal,
1419            key: d.key,
1420            old_value: decode_bytes_to_i64(&d.old_value),
1421            new_value: decode_bytes_to_i64(&d.new_value),
1422        }
1423    }
1424}
1425
1426#[derive(Debug, Clone, PartialEq)]
1427pub struct DeltaFloat64 {
1428    pub operation: pb::substreams::store_delta::Operation,
1429    pub ordinal: u64,
1430    pub key: String,
1431    pub old_value: f64,
1432    pub new_value: f64,
1433}
1434
1435impl From<StoreDelta> for DeltaFloat64 {
1436    fn from(d: StoreDelta) -> Self {
1437        Self {
1438            operation: convert_i32_to_operation(d.operation),
1439            ordinal: d.ordinal,
1440            key: d.key,
1441            old_value: decode_bytes_to_f64(&d.old_value),
1442            new_value: decode_bytes_to_f64(&d.new_value),
1443        }
1444    }
1445}
1446
1447#[derive(Debug, Clone, PartialEq)]
1448pub struct DeltaBool {
1449    pub operation: pb::substreams::store_delta::Operation,
1450    pub ordinal: u64,
1451    pub key: String,
1452    pub old_value: bool,
1453    pub new_value: bool,
1454}
1455
1456impl From<StoreDelta> for DeltaBool {
1457    fn from(d: StoreDelta) -> Self {
1458        Self {
1459            operation: convert_i32_to_operation(d.operation),
1460            ordinal: d.ordinal,
1461            key: d.key,
1462            old_value: !d.old_value.contains(&0),
1463            new_value: !d.new_value.contains(&0),
1464        }
1465    }
1466}
1467
1468#[derive(Debug, Clone, PartialEq)]
1469pub struct DeltaBytes {
1470    pub operation: pb::substreams::store_delta::Operation,
1471    pub ordinal: u64,
1472    pub key: String,
1473    pub old_value: Vec<u8>,
1474    pub new_value: Vec<u8>,
1475}
1476
1477impl From<StoreDelta> for DeltaBytes {
1478    fn from(d: StoreDelta) -> Self {
1479        Self {
1480            operation: convert_i32_to_operation(d.operation),
1481            ordinal: d.ordinal,
1482            key: d.key,
1483            old_value: d.old_value,
1484            new_value: d.new_value,
1485        }
1486    }
1487}
1488
1489#[derive(Debug, Clone, PartialEq)]
1490pub struct DeltaString {
1491    pub operation: pb::substreams::store_delta::Operation,
1492    pub ordinal: u64,
1493    pub key: String,
1494    pub old_value: String,
1495    pub new_value: String,
1496}
1497
1498impl From<StoreDelta> for DeltaString {
1499    fn from(d: StoreDelta) -> Self {
1500        Self {
1501            operation: convert_i32_to_operation(d.operation),
1502            ordinal: d.ordinal,
1503            key: d.key,
1504            old_value: String::from_utf8(d.old_value).unwrap_or_else(|_| {
1505                panic!("Invalid UTF-8 sequence in Store DeltaString old value")
1506            }),
1507            new_value: String::from_utf8(d.new_value).unwrap_or_else(|_| {
1508                panic!("Invalid UTF-8 sequence in Store DeltaString new value")
1509            }),
1510        }
1511    }
1512}
1513
1514#[derive(Debug, Clone, PartialEq)]
1515pub struct DeltaProto<T> {
1516    pub operation: pb::substreams::store_delta::Operation,
1517    pub ordinal: u64,
1518    pub key: String,
1519    pub old_value: T,
1520    pub new_value: T,
1521}
1522
1523impl<T: Default + prost::Message + PartialEq> From<StoreDelta> for DeltaProto<T> {
1524    fn from(d: StoreDelta) -> Self {
1525        let nv: T = prost::Message::decode(d.new_value.as_ref())
1526            .unwrap_or_else(|_| panic!("Unable to decode Store DeltaProto for new value"));
1527        let ov: T = prost::Message::decode(d.old_value.as_ref())
1528            .unwrap_or_else(|_| panic!("Unable to decode Store DeltaProto for old value"));
1529
1530        Self {
1531            operation: convert_i32_to_operation(d.operation),
1532            ordinal: d.ordinal,
1533            key: d.key,
1534            old_value: ov,
1535            new_value: nv,
1536        }
1537    }
1538}
1539
1540impl<T: Default + prost::Message + PartialEq> Delta for DeltaProto<T> {
1541    fn get_key(&self) -> &String {
1542        &self.key
1543    }
1544    fn get_operation(&self) -> pb::substreams::store_delta::Operation {
1545        return self.operation;
1546    }
1547}
1548
1549impl<T: Default + prost::Message + PartialEq> Delta for &DeltaProto<T> {
1550    fn get_key(&self) -> &String {
1551        &self.key
1552    }
1553    fn get_operation(&self) -> pb::substreams::store_delta::Operation {
1554        return self.operation;
1555    }
1556}
1557
1558#[derive(Debug, Clone, PartialEq)]
1559pub struct DeltaArray<T> {
1560    pub operation: pb::substreams::store_delta::Operation,
1561    pub ordinal: u64,
1562    pub key: String,
1563    pub old_value: Vec<T>,
1564    pub new_value: Vec<T>,
1565}
1566
1567impl<T: Into<String> + From<String> + PartialEq> From<StoreDelta> for DeltaArray<T> {
1568    fn from(d: StoreDelta) -> Self {
1569        let old = split_array::<T>(d.old_value).unwrap_or_default();
1570        let new = split_array::<T>(d.new_value).unwrap_or_default();
1571
1572        Self {
1573            operation: convert_i32_to_operation(d.operation),
1574            ordinal: d.ordinal,
1575            key: d.key,
1576            old_value: old,
1577            new_value: new,
1578        }
1579    }
1580}
1581
1582impl<T: Into<String> + From<String> + PartialEq> Delta for DeltaArray<T> {
1583    fn get_key(&self) -> &String {
1584        &self.key
1585    }
1586    fn get_operation(&self) -> pb::substreams::store_delta::Operation {
1587        return self.operation;
1588    }
1589}
1590
1591impl<T: Into<String> + From<String> + PartialEq> Delta for &DeltaArray<T> {
1592    fn get_key(&self) -> &String {
1593        &self.key
1594    }
1595    fn get_operation(&self) -> pb::substreams::store_delta::Operation {
1596        return self.operation;
1597    }
1598}
1599
1600macro_rules! impl_delta_ref {
1601    ($name:ty) => {
1602        impl Delta for $name {
1603            fn get_key(&self) -> &String {
1604                &self.key
1605            }
1606            fn get_operation(&self) -> pb::substreams::store_delta::Operation {
1607                self.operation
1608            }
1609        }
1610    };
1611}
1612
1613macro_rules! impl_delta {
1614    ($name:ty) => {
1615        impl Delta for $name {
1616            fn get_key(&self) -> &String {
1617                &self.key
1618            }
1619            fn get_operation(&self) -> pb::substreams::store_delta::Operation {
1620                self.operation
1621            }
1622        }
1623        impl $name {
1624            pub fn get_key(&self) -> &String {
1625                &self.key
1626            }
1627            pub fn get_operation(&self) -> pb::substreams::store_delta::Operation {
1628                self.operation
1629            }
1630        }
1631    };
1632}
1633
1634// Returns a `u64` whose high 32 bits are the pointer and low 32 bits are the length.
1635fn unpack_ptr_len(packed: u64) -> (*mut u8, u32) {
1636    let ptr32 = (packed >> 32) as u32;
1637    let len32 = packed as u32;
1638    let ptr = ptr32 as usize as *mut u8;
1639    (ptr, len32)
1640}
1641
1642// Interface to query data from foundational stores within Substreams modules
1643pub struct FoundationalStore {
1644    store_index: u32,
1645}
1646
1647impl FoundationalStore {
1648    pub fn new(store_index: u32) -> Self {
1649        Self { store_index }
1650    }
1651
1652    // Retrieves a single value by key from the foundational store
1653    // Returns a GetResponse with status code indicating if the key was found
1654    pub fn get<K: AsRef<[u8]>>(&self, key: K) -> GetResponse {
1655        if cfg!(not(target_arch = "wasm32")) {
1656            panic!("foundational_store::get called outside wasm32 target");
1657        }
1658        let key_ref = key.as_ref();
1659
1660        let req = pb::sf::substreams::foundational_store::v1::GetRequest {
1661            block_number: 0,
1662            block_hash: vec![],
1663            key: key_ref.to_vec(),
1664        };
1665
1666        let (ptr, len, _buf) = proto::encode_to_ptr(&req).unwrap();
1667
1668        // Call host function to query foundational store
1669        let packed = state::foundational_store_get(self.store_index, ptr as u32, len as u32);
1670
1671        let (resp_ptr, resp_len) = unpack_ptr_len(packed);
1672
1673        // Decode response from memory
1674        let msg: GetResponse = proto::decode_ptr(resp_ptr, resp_len as usize).unwrap();
1675
1676        msg
1677    }
1678
1679    // Retrieves multiple values by their keys in a single batch operation
1680    // More efficient than multiple get() calls when querying multiple keys
1681    pub fn get_all<K: AsRef<[u8]>>(&self, keys: &[K]) -> GetAllResponse {
1682
1683        if keys.is_empty() {
1684            return GetAllResponse {
1685                entries: Vec::new(),
1686                block_reached: true,
1687            };
1688        }
1689        if cfg!(not(target_arch = "wasm32")) {
1690            panic!("foundational_store::get_all called outside wasm32 target");
1691        }
1692
1693        // Build batch request with all keys
1694        let req = pb::sf::substreams::foundational_store::v1::GetAllRequest {
1695            block_number: 0,
1696            block_hash: vec![],
1697            keys: keys.iter().map(|k| k.as_ref().to_vec()).collect(),
1698        };
1699
1700        let (ptr, len, _buf) = proto::encode_to_ptr(&req).unwrap();
1701
1702        // Call host function to query multiple keys at once
1703        let packed = state::foundational_store_get_all(self.store_index, ptr as u32, len as u32);
1704
1705        let (resp_ptr, resp_len) = unpack_ptr_len(packed);
1706
1707        // Decode batch response from host memory
1708        let msg: GetAllResponse = proto::decode_ptr(resp_ptr, resp_len as usize).unwrap();
1709
1710        msg
1711    }
1712}
1713
1714impl_delta!(DeltaBigDecimal);
1715impl_delta!(DeltaBigInt);
1716impl_delta!(DeltaInt32);
1717impl_delta!(DeltaInt64);
1718impl_delta!(DeltaFloat64);
1719impl_delta!(DeltaBool);
1720impl_delta!(DeltaBytes);
1721impl_delta!(DeltaString);
1722
1723impl_delta_ref!(&DeltaBigDecimal);
1724impl_delta_ref!(&DeltaBigInt);
1725impl_delta_ref!(&DeltaInt32);
1726impl_delta_ref!(&DeltaInt64);
1727impl_delta_ref!(&DeltaFloat64);
1728impl_delta_ref!(&DeltaBool);
1729impl_delta_ref!(&DeltaBytes);
1730impl_delta_ref!(&DeltaString);
1731
1732fn convert_i32_to_operation(operation: i32) -> pb::substreams::store_delta::Operation {
1733    Operation::try_from(operation).unwrap_or_else(|_| panic!("unhandled operation: {}", operation))
1734}
1735
1736// We accept &Vec<u8> instead of &[u8] because use internally and makes it easier to chain
1737fn decode_bytes_to_i32(bytes: &Vec<u8>) -> i32 {
1738    if bytes.is_empty() {
1739        return 0;
1740    }
1741
1742    // FIXME: If we are ready to accept the fact that `bytes` is always valid UTF-8, we could even use
1743    //        the unsafe `from_utf8_unchecked` version, we would need first to measure the impact and
1744    //        better understand implication of an invalid UTF-8 &str with `from_str` call.
1745    let int_as_str =
1746        std::str::from_utf8(bytes).expect("received bytes expected to be valid UTF-8 string");
1747
1748    i32::from_str(int_as_str).unwrap_or_else(|_| {
1749        panic!(
1750            "value {} is not a valid representation of an i32",
1751            int_as_str
1752        )
1753    })
1754}
1755
1756// We accept &Vec<u8> instead of &[u8] because use internally and makes it easier to chain
1757fn decode_bytes_to_i64(bytes: &Vec<u8>) -> i64 {
1758    if bytes.is_empty() {
1759        return 0;
1760    }
1761
1762    // FIXME: If we are ready to accept the fact that `bytes` is always valid UTF-8, we could even use
1763    //        the unsafe `from_utf8_unchecked` version, we would need first to measure the impact and
1764    //        better understand implication of an invalid UTF-8 &str with `from_str` call.
1765    let int_as_str =
1766        std::str::from_utf8(bytes).expect("received bytes expected to be valid UTF-8 string");
1767
1768    i64::from_str(int_as_str).unwrap_or_else(|_| {
1769        panic!(
1770            "value {} is not a valid representation of an i64",
1771            int_as_str
1772        )
1773    })
1774}
1775
1776// We accept &Vec<u8> instead of &[u8] because use internally and makes it easier to chain
1777fn decode_bytes_to_f64(bytes: &Vec<u8>) -> f64 {
1778    if bytes.is_empty() {
1779        return 0.0;
1780    }
1781
1782    // FIXME: If we are ready to accept the fact that `bytes` is always valid UTF-8, we could even use
1783    //        the unsafe `from_utf8_unchecked` version, we would need first to measure the impact and
1784    //        better understand implication of an invalid UTF-8 &str with `from_str` call.
1785    let float64_as_str =
1786        std::str::from_utf8(bytes).expect("received bytes expected to be valid UTF-8 string");
1787
1788    f64::from_str(float64_as_str).unwrap_or_else(|_| {
1789        panic!(
1790            "value {} is not a valid representation of an f64",
1791            float64_as_str
1792        )
1793    })
1794}
1795
1796#[cfg(test)]
1797mod tests {
1798    use crate::{
1799        pb::{
1800            sf::substreams::foundational_store::v1::GetAllResponse,
1801            substreams::{store_delta::Operation, StoreDelta},
1802        },
1803        store::{
1804            decode_bytes_to_f64, decode_bytes_to_i32, decode_bytes_to_i64, split_array,
1805            unpack_ptr_len, DeltaArray, Deltas, FoundationalStore,
1806        },
1807    };
1808
1809    #[test]
1810    fn valid_int64_decode_bytes_to_i32() {
1811        let bytes: Vec<u8> = "1".as_bytes().to_vec();
1812        assert_eq!(1, decode_bytes_to_i32(&bytes))
1813    }
1814
1815    #[test]
1816    fn valid_int64_max_value_decode_bytes_to_i32() {
1817        let bytes: Vec<u8> = i32::MAX.to_string().as_bytes().to_vec();
1818        assert_eq!(i32::MAX, decode_bytes_to_i32(&bytes))
1819    }
1820
1821    #[test]
1822    #[should_panic]
1823    fn invalid_bytes_decode_bytes_to_i32() {
1824        let bytes: Vec<u8> = "invalid".as_bytes().to_vec();
1825        decode_bytes_to_i32(&bytes);
1826    }
1827
1828    #[test]
1829    fn no_bytes_decode_bytes_to_i32() {
1830        let bytes: Vec<u8> = vec![];
1831        decode_bytes_to_i32(&bytes);
1832    }
1833
1834    #[test]
1835    fn valid_int64_decode_bytes_to_i64() {
1836        let bytes: Vec<u8> = "1".as_bytes().to_vec();
1837        assert_eq!(1, decode_bytes_to_i64(&bytes))
1838    }
1839
1840    #[test]
1841    fn valid_int64_max_value_decode_bytes_to_i64() {
1842        let bytes: Vec<u8> = i64::MAX.to_string().as_bytes().to_vec();
1843        assert_eq!(i64::MAX, decode_bytes_to_i64(&bytes))
1844    }
1845
1846    #[test]
1847    #[should_panic]
1848    fn invalid_bytes_decode_bytes_to_i64() {
1849        let bytes: Vec<u8> = "invalid".as_bytes().to_vec();
1850        decode_bytes_to_i64(&bytes);
1851    }
1852
1853    #[test]
1854    fn no_bytes_decode_bytes_to_i64() {
1855        let bytes: Vec<u8> = vec![];
1856        decode_bytes_to_i64(&bytes);
1857    }
1858
1859    #[test]
1860    fn valid_f64_decode_bytes_to_f64() {
1861        let bytes: Vec<u8> = "1.00".as_bytes().to_vec();
1862        assert_eq!(1.00, decode_bytes_to_f64(&bytes))
1863    }
1864
1865    #[test]
1866    fn valid_f64_max_value_decode_bytes_to_f64() {
1867        let bytes: Vec<u8> = f64::MAX.to_string().as_bytes().to_vec();
1868        assert_eq!(f64::MAX, decode_bytes_to_f64(&bytes))
1869    }
1870
1871    #[test]
1872    #[should_panic]
1873    fn invalid_bytes_decode_bytes_to_f64() {
1874        let bytes: Vec<u8> = "invalid".as_bytes().to_vec();
1875        decode_bytes_to_f64(&bytes);
1876    }
1877
1878    #[test]
1879    fn no_bytes_decode_bytes_to_f64() {
1880        let bytes: Vec<u8> = vec![];
1881        decode_bytes_to_f64(&bytes);
1882    }
1883
1884    #[test]
1885    fn delta_array_strring() {
1886        let deltas = Deltas::<DeltaArray<String>>::new(vec![StoreDelta {
1887            operation: 1,
1888            ordinal: 0,
1889            key: "".to_string(),
1890            old_value: ";".as_bytes().to_vec(),
1891            new_value: "1.1;2.2;3.3;".as_bytes().to_vec(),
1892        }]);
1893
1894        assert_eq!(
1895            Deltas::<DeltaArray<String>> {
1896                deltas: vec![DeltaArray::<String> {
1897                    operation: Operation::Create,
1898                    ordinal: 0,
1899                    key: "".to_string(),
1900                    old_value: vec![],
1901                    new_value: vec!["1.1".to_string(), "2.2".to_string(), "3.3".to_string(),]
1902                }]
1903            },
1904            deltas
1905        );
1906    }
1907
1908    #[test]
1909    fn split_arrays_no_elements() {
1910        let value = "";
1911        let bytes = value.as_bytes();
1912
1913        let expected_value = None;
1914        let actual_value = split_array::<String>(bytes.to_vec());
1915
1916        assert_eq!(expected_value, actual_value)
1917    }
1918
1919    #[test]
1920    fn split_arrays_one_string_element() {
1921        let value = "1;";
1922        let bytes = value.as_bytes();
1923
1924        let expected_value = Some(vec!["1".to_string()]);
1925        let actual_value = split_array::<String>(bytes.to_vec());
1926
1927        assert_eq!(expected_value, actual_value)
1928    }
1929
1930    #[test]
1931    fn split_arrays_multiple_string_elements() {
1932        let value = "1;2;3;";
1933        let bytes = value.as_bytes();
1934
1935        let expected_value = Some(vec!["1".to_string(), "2".to_string(), "3".to_string()]);
1936        let actual_value = split_array::<String>(bytes.to_vec());
1937
1938        assert_eq!(expected_value, actual_value)
1939    }
1940
1941    #[test]
1942    fn unpack_ptr_len_roundtrip() {
1943        // random pointer
1944        let ptr_orig = 0x1234_5678usize as *mut u8;
1945        let len_orig: usize = 0x9ABC_DEFusize;
1946
1947        let packed: u64 = ((ptr_orig as u64) << 32) | (len_orig as u64 & 0xFFFF_FFFF);
1948
1949        let (ptr_unpacked, len_unpacked) = unpack_ptr_len(packed);
1950
1951        assert_eq!(ptr_unpacked, ptr_orig);
1952        assert_eq!(len_unpacked, len_orig as u32);
1953    }
1954
1955    #[test]
1956    fn unpack_ptr_len_zero() {
1957        let packed = 0u64;
1958        let (ptr, len) = unpack_ptr_len(packed);
1959        assert!(ptr.is_null());
1960        assert_eq!(len, 0);
1961    }
1962
1963    #[test]
1964    #[should_panic]
1965    fn get_non_wasm_returns_none() {
1966        let store = FoundationalStore::new(999);
1967        // now panics on non-wasm
1968        let _ = store.get(b"some_key");
1969    }
1970
1971    #[test]
1972    #[should_panic]
1973    fn get_all_non_wasm_returns_none() {
1974        let store = FoundationalStore::new(0);
1975        let keys = &[b"test1", b"test2", b"test3"];
1976        // now panics on non-wasm
1977        let _ = store.get_all(keys);
1978    }
1979
1980    #[test]
1981    fn get_all_empty_keys() {
1982        let store = FoundationalStore::new(42);
1983        let empty: &[&[u8]] = &[];
1984        let out = store.get_all(empty);
1985        // returns a real value before the wasm guard
1986        assert_eq!(
1987            out,
1988            GetAllResponse {
1989                entries: Vec::new(),
1990                block_reached: true,
1991            }
1992        );
1993    }
1994
1995    #[test]
1996    #[should_panic]
1997    fn test_with_vec_u8() {
1998        let store = FoundationalStore::new(123);
1999        let key = vec![0x01, 0x02, 0x03, 0x04];
2000        // now panics on non-wasm
2001        let _ = store.get(&key);
2002    }
2003
2004    #[test]
2005    #[should_panic]
2006    fn test_with_string_bytes() {
2007        let store = FoundationalStore::new(456);
2008        let key = "test_key";
2009        // now panics on non-wasm
2010        let _ = store.get(key);
2011    }
2012
2013    #[test]
2014    #[should_panic]
2015    fn get_all_with_mixed_key_types() {
2016        let store = FoundationalStore::new(789);
2017        let vec_key = vec![0x01, 0x02];
2018        let keys = &[&b"string_key"[..], &vec_key[..], &b"byte_string"[..]];
2019        // now panics on non-wasm
2020        let _ = store.get_all(keys);
2021    }
2022
2023    #[test]
2024    #[should_panic]
2025    fn get_all_single_key() {
2026        let store = FoundationalStore::new(100);
2027        let keys = &[b"single_key"];
2028        // now panics on non-wasm
2029        let _ = store.get_all(keys);
2030    }
2031
2032    #[test]
2033    #[should_panic]
2034    fn get_all_multiple_string_keys() {
2035        let store = FoundationalStore::new(200);
2036        let keys = &["key1", "key2", "key3", "key4"];
2037        // now panics on non-wasm
2038        let _ = store.get_all(keys);
2039    }
2040
2041    #[test]
2042    #[should_panic]
2043    fn get_all_with_different_block_numbers() {
2044        let store = FoundationalStore::new(300);
2045        let keys = &[b"test_key"];
2046
2047        // any of these calls should panic on non-wasm; the first panic satisfies #[should_panic]
2048        let _ = store.get_all(keys);
2049    }
2050
2051    #[test]
2052    #[should_panic]
2053    fn get_all_preserves_order() {
2054        let store = FoundationalStore::new(400);
2055        let keys = &[b"key_z", b"key_a", b"key_m"];
2056        // now panics on non-wasm
2057        let _ = store.get_all(keys);
2058    }
2059
2060    #[test]
2061    #[should_panic]
2062    fn get_all_with_duplicate_keys() {
2063        let store = FoundationalStore::new(500);
2064        let keys = &[&b"duplicate"[..], &b"duplicate"[..], &b"unique"[..]];
2065        // now panics on non-wasm
2066        let _ = store.get_all(keys);
2067    }
2068
2069    #[test]
2070    #[should_panic]
2071    fn get_all_with_empty_key() {
2072        let store = FoundationalStore::new(600);
2073        let keys = &[&b""[..], &b"non_empty"[..]];
2074        // now panics on non-wasm
2075        let _ = store.get_all(keys);
2076    }
2077
2078    #[test]
2079    #[should_panic]
2080    fn get_all_large_number_of_keys() {
2081        let store = FoundationalStore::new(700);
2082        let keys: Vec<Vec<u8>> = (0..1000)
2083            .map(|i| format!("key_{}", i).into_bytes())
2084            .collect();
2085        let key_refs: Vec<&Vec<u8>> = keys.iter().collect();
2086
2087        // now panics on non-wasm
2088        let _ = store.get_all(&key_refs);
2089    }
2090}