From 4337ab3b0783a3df12ba8ebde2c6c9ec667a86a5 Mon Sep 17 00:00:00 2001
From: Matthieu Vachon <matt@streamingfast.io>
Date: Fri, 29 Jul 2022 15:46:36 -0400
Subject: [PATCH] Updated store and state methods to accept `key` of type
 `AsRef<str>`

---
 docs/release-notes/change-log.md |  52 +++++++++++
 rust/substreams/src/state.rs     | 151 ++++++++++++++++---------------
 rust/substreams/src/store.rs     |  62 ++++++-------
 3 files changed, 159 insertions(+), 106 deletions(-)

diff --git a/docs/release-notes/change-log.md b/docs/release-notes/change-log.md
index f7a51011b..69b7476ad 100644
--- a/docs/release-notes/change-log.md
+++ b/docs/release-notes/change-log.md
@@ -8,6 +8,58 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
 
 **New updatePolicy `append`**, allows one to build a store that concatenates values and supports parallelism.  This affects the server, the manifest format (additive only), the substreams crate and the generated code therein.
 
+### Rust API
+
+- Store APIs methods now accept `key` of type `AsRef<str>` which means for example that both `String` an `&str` are accepted as inputs in:
+
+  - `StoreSet::set`
+  - `StoreSet::set_many`
+  - `StoreSet::set_if_not_exists`
+  - `StoreSet::set_if_not_exists_many`
+  - `StoreAddInt64::add`
+  - `StoreAddInt64::add_many`
+  - `StoreAddFloat64::add`
+  - `StoreAddFloat64::add_many`
+  - `StoreAddBigFloat::add`
+  - `StoreAddBigFloat::add_many`
+  - `StoreAddBigInt::add`
+  - `StoreAddBigInt::add_many`
+  - `StoreMaxInt64::max`
+  - `StoreMaxFloat64::max`
+  - `StoreMaxBigInt::max`
+  - `StoreMaxBigFloat::max`
+  - `StoreMinInt64::min`
+  - `StoreMinFloat64::min`
+  - `StoreMinBigInt::min`
+  - `StoreMinBigFloat::min`
+  - `StoreAppend::append`
+  - `StoreAppend::append_bytes`
+  - `StoreGet::get_at`
+  - `StoreGet::get_last`
+  - `StoreGet::get_first`
+
+- Low-level state methods now accept `key` of type `AsRef<str>` which means for example that both `String` an `&str` are accepted as inputs in:
+
+  - `state::get_at`
+  - `state::get_last`
+  - `state::get_first`
+  - `state::set`
+  - `state::set_if_not_exists`
+  - `state::append`
+  - `state::delete_prefix`
+  - `state::add_bigint`
+  - `state::add_int64`
+  - `state::add_float64`
+  - `state::add_bigfloat`
+  - `state::set_min_int64`
+  - `state::set_min_bigint`
+  - `state::set_min_float64`
+  - `state::set_min_bigfloat`
+  - `state::set_max_int64`
+  - `state::set_max_bigint`
+  - `state::set_max_float64`
+  - `state::set_max_bigfloat`
+
 ### CLI
 
 * Changed the output modes: `module-*` modes are gone and become the
diff --git a/rust/substreams/src/state.rs b/rust/substreams/src/state.rs
index 72c7332d6..a4e283354 100644
--- a/rust/substreams/src/state.rs
+++ b/rust/substreams/src/state.rs
@@ -1,9 +1,11 @@
 use crate::externs;
 use crate::memory;
-use num_bigint::{BigInt};
 use bigdecimal::BigDecimal;
+use num_bigint::BigInt;
+
+pub fn get_at<K: AsRef<str>>(store_idx: u32, ord: i64, key: K) -> Option<Vec<u8>> {
+    let key = key.as_ref();
 
-pub fn get_at(store_idx: u32, ord: i64, key: &String) -> Option<Vec<u8>> {
     unsafe {
         let key_bytes = key.as_bytes();
         let output_ptr = memory::alloc(8);
@@ -21,7 +23,9 @@ pub fn get_at(store_idx: u32, ord: i64, key: &String) -> Option<Vec<u8>> {
         };
     }
 }
-pub fn get_last(store_idx: u32, key: &String) -> Option<Vec<u8>> {
+pub fn get_last<K: AsRef<str>>(store_idx: u32, key: K) -> Option<Vec<u8>> {
+    let key = key.as_ref();
+
     unsafe {
         let key_bytes = key.as_bytes();
         let output_ptr = memory::alloc(8);
@@ -39,7 +43,9 @@ pub fn get_last(store_idx: u32, key: &String) -> Option<Vec<u8>> {
         };
     }
 }
-pub fn get_first(store_idx: u32, key: &String) -> Option<Vec<u8>> {
+pub fn get_first<K: AsRef<str>>(store_idx: u32, key: K) -> Option<Vec<u8>> {
+    let key = key.as_ref();
+
     unsafe {
         let key_bytes = key.as_bytes();
         let output_ptr = memory::alloc(8);
@@ -57,7 +63,9 @@ pub fn get_first(store_idx: u32, key: &String) -> Option<Vec<u8>> {
         };
     }
 }
-pub fn set(ord: i64, key: String, value: &Vec<u8>) {
+pub fn set<K: AsRef<str>>(ord: i64, key: K, value: &Vec<u8>) {
+    let key = key.as_ref();
+
     unsafe {
         externs::state::set(
             ord,
@@ -68,7 +76,9 @@ pub fn set(ord: i64, key: String, value: &Vec<u8>) {
         )
     }
 }
-pub fn set_if_not_exists(ord: i64, key: String, value: &Vec<u8>) {
+pub fn set_if_not_exists<K: AsRef<str>>(ord: i64, key: K, value: &Vec<u8>) {
+    let key = key.as_ref();
+
     unsafe {
         externs::state::set_if_not_exists(
             ord,
@@ -80,7 +90,9 @@ pub fn set_if_not_exists(ord: i64, key: String, value: &Vec<u8>) {
     }
 }
 
-pub fn append(ord: i64, key: String, value: &Vec<u8>) {
+pub fn append<K: AsRef<str>>(ord: i64, key: K, value: &Vec<u8>) {
+    let key = key.as_ref();
+
     unsafe {
         externs::state::append(
             ord,
@@ -92,17 +104,16 @@ pub fn append(ord: i64, key: String, value: &Vec<u8>) {
     }
 }
 
-pub fn delete_prefix(ord: i64, prefix: &String){
-    unsafe {
-        externs::state::delete_prefix(
-            ord,
-            prefix.as_ptr(),
-            prefix.len() as u32,
-        )
-    }
+pub fn delete_prefix<K: AsRef<str>>(ord: i64, prefix: K) {
+    let prefix = prefix.as_ref();
+
+    unsafe { externs::state::delete_prefix(ord, prefix.as_ptr(), prefix.len() as u32) }
 }
-pub fn add_bigint(ord: i64, key: String, value: &BigInt) {
+
+pub fn add_bigint<K: AsRef<str>>(ord: i64, key: K, value: &BigInt) {
+    let key = key.as_ref();
     let data = value.to_string();
+
     unsafe {
         externs::state::add_bigint(
             ord,
@@ -113,28 +124,22 @@ pub fn add_bigint(ord: i64, key: String, value: &BigInt) {
         )
     }
 }
-pub fn add_int64(ord: i64, key: String, value: i64) {
-    unsafe {
-        externs::state::add_int64(
-            ord,
-            key.as_ptr(),
-            key.len() as u32,
-	        value,
-        )
-    }
+pub fn add_int64<K: AsRef<str>>(ord: i64, key: K, value: i64) {
+    let key = key.as_ref();
+
+    unsafe { externs::state::add_int64(ord, key.as_ptr(), key.len() as u32, value) }
 }
-pub fn add_float64(ord: i64, key: String, value: f64) {
-    unsafe {
-        externs::state::add_float64(
-            ord,
-            key.as_ptr(),
-            key.len() as u32,
-            value
-        )
-    }
+
+pub fn add_float64<K: AsRef<str>>(ord: i64, key: K, value: f64) {
+    let key = key.as_ref();
+
+    unsafe { externs::state::add_float64(ord, key.as_ptr(), key.len() as u32, value) }
 }
-pub fn add_bigfloat(ord: i64, key: String, value: &BigDecimal) {
+
+pub fn add_bigfloat<K: AsRef<str>>(ord: i64, key: K, value: &BigDecimal) {
+    let key = key.as_ref();
     let data = value.to_string();
+
     unsafe {
         externs::state::add_bigfloat(
             ord,
@@ -145,18 +150,17 @@ pub fn add_bigfloat(ord: i64, key: String, value: &BigDecimal) {
         )
     }
 }
-pub fn set_min_int64(ord: i64, key: String, value: i64) {
-    unsafe {
-        externs::state::set_min_int64(
-            ord,
-            key.as_ptr(),
-            key.len() as u32,
-            value,
-        )
-    }
+
+pub fn set_min_int64<K: AsRef<str>>(ord: i64, key: K, value: i64) {
+    let key = key.as_ref();
+
+    unsafe { externs::state::set_min_int64(ord, key.as_ptr(), key.len() as u32, value) }
 }
-pub fn set_min_bigint(ord: i64, key: String, value: &BigInt) {
+
+pub fn set_min_bigint<K: AsRef<str>>(ord: i64, key: K, value: &BigInt) {
+    let key = key.as_ref();
     let data = value.to_string();
+
     unsafe {
         externs::state::set_min_bigint(
             ord,
@@ -167,18 +171,17 @@ pub fn set_min_bigint(ord: i64, key: String, value: &BigInt) {
         )
     }
 }
-pub fn set_min_float64(ord: i64, key: String, value: f64) {
-    unsafe {
-        externs::state::set_min_float64(
-            ord,
-            key.as_ptr(),
-            key.len() as u32,
-            value,
-        )
-    }
+
+pub fn set_min_float64<K: AsRef<str>>(ord: i64, key: K, value: f64) {
+    let key = key.as_ref();
+
+    unsafe { externs::state::set_min_float64(ord, key.as_ptr(), key.len() as u32, value) }
 }
-pub fn set_min_bigfloat(ord: i64, key: String, value: &BigDecimal) {
+
+pub fn set_min_bigfloat<K: AsRef<str>>(ord: i64, key: K, value: &BigDecimal) {
+    let key = key.as_ref();
     let data = value.to_string();
+
     unsafe {
         externs::state::set_min_bigfloat(
             ord,
@@ -189,18 +192,17 @@ pub fn set_min_bigfloat(ord: i64, key: String, value: &BigDecimal) {
         )
     }
 }
-pub fn set_max_int64(ord: i64, key: String, value: i64) {
-    unsafe {
-        externs::state::set_max_int64(
-            ord,
-            key.as_ptr(),
-            key.len() as u32,
-            value,
-        )
-    }
+
+pub fn set_max_int64<K: AsRef<str>>(ord: i64, key: K, value: i64) {
+    let key = key.as_ref();
+
+    unsafe { externs::state::set_max_int64(ord, key.as_ptr(), key.len() as u32, value) }
 }
-pub fn set_max_bigint(ord: i64, key: String, value: &BigInt) {
+
+pub fn set_max_bigint<K: AsRef<str>>(ord: i64, key: K, value: &BigInt) {
+    let key = key.as_ref();
     let data = value.to_string();
+
     unsafe {
         externs::state::set_max_bigint(
             ord,
@@ -211,18 +213,17 @@ pub fn set_max_bigint(ord: i64, key: String, value: &BigInt) {
         )
     }
 }
-pub fn set_max_float64(ord: i64, key: String, value: f64) {
-    unsafe {
-        externs::state::set_max_float64(
-            ord,
-            key.as_ptr(),
-            key.len() as u32,
-            value,
-        )
-    }
+
+pub fn set_max_float64<K: AsRef<str>>(ord: i64, key: K, value: f64) {
+    let key = key.as_ref();
+
+    unsafe { externs::state::set_max_float64(ord, key.as_ptr(), key.len() as u32, value) }
 }
-pub fn set_max_bigfloat(ord: i64, key: String, value: &BigDecimal) {
+
+pub fn set_max_bigfloat<K: AsRef<str>>(ord: i64, key: K, value: &BigDecimal) {
+    let key = key.as_ref();
     let data = value.to_string();
+
     unsafe {
         externs::state::set_max_bigfloat(
             ord,
diff --git a/rust/substreams/src/store.rs b/rust/substreams/src/store.rs
index dbf296788..2c260bf06 100644
--- a/rust/substreams/src/store.rs
+++ b/rust/substreams/src/store.rs
@@ -19,14 +19,14 @@ pub type Deltas = Vec<pb::substreams::StoreDelta>;
 pub struct StoreSet {}
 impl StoreSet {
     /// Set a given key to a given value, if the key existed before, it will be replaced.
-    pub fn set(&self, ord: u64, key: String, value: &Vec<u8>) {
+    pub fn set<K: AsRef<str>>(&self, ord: u64, key: K, value: &Vec<u8>) {
         state::set(ord as i64, key, value);
     }
 
     /// Set many keys to a given values, if the key existed before, it will be replaced.
-    pub fn set_many(&self, ord: u64, keys: &Vec<String>, value: &Vec<u8>) {
+    pub fn set_many<K: AsRef<str>>(&self, ord: u64, keys: &Vec<K>, value: &Vec<u8>) {
         for key in keys {
-            state::set(ord as i64, key.to_string(), value);
+            state::set(ord as i64, key, value);
         }
     }
 }
@@ -37,14 +37,14 @@ impl StoreSet {
 pub struct StoreSetIfNotExists {}
 impl StoreSetIfNotExists {
     /// Set a given key to a given value, if the key existed before, it will be ignored and not set.
-    pub fn set_if_not_exists(&self, ord: u64, key: String, value: &Vec<u8>) {
+    pub fn set_if_not_exists<K: AsRef<str>>(&self, ord: u64, key: K, value: &Vec<u8>) {
         state::set_if_not_exists(ord as i64, key, value);
     }
 
     /// Set given keys to given values, if the key existed before, it will be ignored and not set.
-    pub fn set_if_not_exists_many(&self, ord: u64, keys: &Vec<String>, value: &Vec<u8>) {
+    pub fn set_if_not_exists_many<K: AsRef<str>>(&self, ord: u64, keys: &Vec<K>, value: &Vec<u8>) {
         for key in keys {
-            state::set_if_not_exists(ord as i64, key.to_string(), value);
+            state::set_if_not_exists(ord as i64, key, value);
         }
     }
 }
@@ -56,15 +56,15 @@ pub struct StoreAddInt64 {}
 impl StoreAddInt64 {
     /// Will add the value to the already present value at the key (or default to
     /// zero if the key was not set)
-    pub fn add(&self, ord: u64, key: String, value: i64) {
+    pub fn add<K: AsRef<str>>(&self, ord: u64, key: K, value: i64) {
         state::add_int64(ord as i64, key, value);
     }
 
     /// Will add the value to the already present value of the keys (or default to
     /// zero if the key was not set)
-    pub fn add_many(&self, ord: u64, keys: &Vec<String>, value: i64) {
+    pub fn add_many<K: AsRef<str>>(&self, ord: u64, keys: &Vec<K>, value: i64) {
         for key in keys {
-            state::add_int64(ord as i64, key.to_string(), value);
+            state::add_int64(ord as i64, key, value);
         }
     }
 }
@@ -76,15 +76,15 @@ pub struct StoreAddFloat64 {}
 impl StoreAddFloat64 {
     /// Will add the value to the already present value at the key (or default to
     /// zero if the key was not set)
-    pub fn add(&self, ord: u64, key: String, value: f64) {
+    pub fn add<K: AsRef<str>>(&self, ord: u64, key: K, value: f64) {
         state::add_float64(ord as i64, key, value);
     }
 
     /// Will add the value to the already present value of the keys (or default to
     /// zero if the key was not set)
-    pub fn add_many(&self, ord: u64, keys: &Vec<String>, value: f64) {
+    pub fn add_many<K: AsRef<str>>(&self, ord: u64, keys: &Vec<K>, value: f64) {
         for key in keys {
-            state::add_float64(ord as i64, key.to_string(), value);
+            state::add_float64(ord as i64, key, value);
         }
     }
 }
@@ -96,15 +96,15 @@ pub struct StoreAddBigFloat {}
 impl StoreAddBigFloat {
     /// Will add the value to the already present value at the key (or default to
     /// zero if the key was not set)
-    pub fn add(&self, ord: u64, key: String, value: &BigDecimal) {
+    pub fn add<K: AsRef<str>>(&self, ord: u64, key: K, value: &BigDecimal) {
         state::add_bigfloat(ord as i64, key, value);
     }
 
     /// Will add the value to the already present value of the keys (or default to
     /// zero if the key was not set)
-    pub fn add_many(&self, ord: u64, keys: &Vec<String>, value: &BigDecimal) {
+    pub fn add_many<K: AsRef<str>>(&self, ord: u64, keys: &Vec<K>, value: &BigDecimal) {
         for key in keys {
-            state::add_bigfloat(ord as i64, key.to_string(), value);
+            state::add_bigfloat(ord as i64, key, value);
         }
     }
 }
@@ -116,15 +116,15 @@ pub struct StoreAddBigInt {}
 impl StoreAddBigInt {
     /// Will add the value to the already present value of the keys (or default to
     /// zero if the key was not set)
-    pub fn add(&self, ord: u64, key: String, value: &BigInt) {
+    pub fn add<K: AsRef<str>>(&self, ord: u64, key: K, value: &BigInt) {
         state::add_bigint(ord as i64, key, value);
     }
 
     /// Will add the value to the already present value of the keys (or default to
     /// zero if the key was not set)
-    pub fn add_many(&self, ord: u64, keys: &Vec<String>, value: &BigInt) {
+    pub fn add_many<K: AsRef<str>>(&self, ord: u64, keys: &Vec<K>, value: &BigInt) {
         for key in keys {
-            state::add_bigint(ord as i64, key.to_string(), value);
+            state::add_bigint(ord as i64, key, value);
         }
     }
 }
@@ -137,7 +137,7 @@ impl StoreMaxInt64 {
     /// max will set the provided key in the store only if the value received in
     /// parameter is bigger than the one already present in the store, with
     /// a default of the zero value when the key is absent.
-    pub fn max(&self, ord: u64, key: String, value: i64) {
+    pub fn max<K: AsRef<str>>(&self, ord: u64, key: K, value: i64) {
         state::set_max_int64(ord as i64, key, value);
     }
 }
@@ -150,7 +150,7 @@ impl StoreMaxBigInt {
     /// Will set the provided key in the store only if the value received in
     /// parameter is bigger than the one already present in the store, with
     /// a default of the zero value when the key is absent.
-    pub fn max(&self, ord: u64, key: String, value: &BigInt) {
+    pub fn max<K: AsRef<str>>(&self, ord: u64, key: K, value: &BigInt) {
         state::set_max_bigint(ord as i64, key, value);
     }
 }
@@ -163,7 +163,7 @@ impl StoreMaxFloat64 {
     /// Will set the provided key in the store only if the value received in
     /// parameter is bigger than the one already present in the store, with
     /// a default of the zero value when the key is absent.
-    pub fn max(&self, ord: u64, key: String, value: f64) {
+    pub fn max<K: AsRef<str>>(&self, ord: u64, key: K, value: f64) {
         state::set_max_float64(ord as i64, key, value);
     }
 }
@@ -176,7 +176,7 @@ impl StoreMaxBigFloat {
     /// Will set the provided key in the store only if the value received in
     /// parameter is bigger than the one already present in the store, with
     /// a default of the zero value when the key is absent.
-    pub fn max(&self, ord: u64, key: String, value: &BigDecimal) {
+    pub fn max<K: AsRef<str>>(&self, ord: u64, key: K, value: &BigDecimal) {
         state::set_max_bigfloat(ord as i64, key, value);
     }
 }
@@ -189,7 +189,7 @@ impl StoreMinInt64 {
     /// Will set the provided key in the store only if the value received in
     /// parameter is smaller than the one already present in the store, with
     /// a default of the zero value when the key is absent.
-    pub fn min(&self, ord: u64, key: String, value: i64) {
+    pub fn min<K: AsRef<str>>(&self, ord: u64, key: K, value: i64) {
         state::set_min_int64(ord as i64, key, value);
     }
 }
@@ -202,7 +202,7 @@ impl StoreMinBigInt {
     /// Will set the provided key in the store only if the value received in
     /// parameter is smaller than the one already present in the store, with
     /// a default of the zero value when the key is absent.
-    pub fn min(&self, ord: u64, key: String, value: &BigInt) {
+    pub fn min<K: AsRef<str>>(&self, ord: u64, key: K, value: &BigInt) {
         state::set_min_bigint(ord as i64, key, value);
     }
 }
@@ -215,7 +215,7 @@ impl StoreMinFloat64 {
     /// Will set the provided key in the store only if the value received in
     /// parameter is smaller than the one already present in the store, with
     /// a default of the zero value when the key is absent.
-    pub fn min(&self, ord: u64, key: String, value: f64) {
+    pub fn min<K: AsRef<str>>(&self, ord: u64, key: K, value: f64) {
         state::set_min_float64(ord as i64, key, value);
     }
 }
@@ -228,7 +228,7 @@ impl StoreMinBigFloat {
     /// Will set the provided key in the store only if the value received in
     /// parameter is smaller than the one already present in the store, with
     /// a default of the zero value when the key is absent.
-    pub fn min(&self, ord: u64, key: String, value: &BigDecimal) {
+    pub fn min<K: AsRef<str>>(&self, ord: u64, key: K, value: &BigDecimal) {
         state::set_min_bigfloat(ord as i64, key, value);
     }
 }
@@ -239,12 +239,12 @@ impl StoreMinBigFloat {
 pub struct StoreAppend {}
 impl StoreAppend {
     /// Concatenates a given value at the end of the key's current value
-    pub fn append(&self, ord: u64, key: String, value: &String) {
+    pub fn append<K: AsRef<str>>(&self, ord: u64, key: K, value: &String) {
         state::append(ord as i64, key, &value.as_bytes().to_vec());
     }
 
     /// Concatenates a given value at the end of the key's current value
-    pub fn append_bytes(&self, ord: u64, key: String, value: &Vec<u8>) {
+    pub fn append_bytes<K: AsRef<str>>(&self, ord: u64, key: K, value: &Vec<u8>) {
         state::append(ord as i64, key, value);
     }
 }
@@ -265,7 +265,7 @@ impl StoreGet {
     /// the output section of the manifest. The ordinal is used here
     /// to go query a key that might have changed mid-block by
     /// the store module that built it.
-    pub fn get_at(&self, ord: u64, key: &String) -> Option<Vec<u8>> {
+    pub fn get_at<K: AsRef<str>>(&self, ord: u64, key: K) -> Option<Vec<u8>> {
         return state::get_at(self.idx, ord as i64, key);
     }
 
@@ -273,7 +273,7 @@ impl StoreGet {
     /// the store as of the beginning of the block being processed, before any changes
     /// were applied within the current block. Tt does not need to rewind any changes
     /// in the middle of the block.
-    pub fn get_last(&self, key: &String) -> Option<Vec<u8>> {
+    pub fn get_last<K: AsRef<str>>(&self, key: K) -> Option<Vec<u8>> {
         return state::get_last(self.idx, key);
     }
 
@@ -281,7 +281,7 @@ impl StoreGet {
     /// the store as of the beginning of the block being processed, before any changes
     /// were applied within the current block. However, it needs to unwind any keys that
     /// would have changed mid-block, so will be slightly less performant.
-    pub fn get_first(&self, key: &String) -> Option<Vec<u8>> {
+    pub fn get_first<K: AsRef<str>>(&self, key: K) -> Option<Vec<u8>> {
         return state::get_first(self.idx, key);
     }
 }