diff --git a/Cargo.lock b/Cargo.lock index b7cb3c849..2d69171e8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -406,12 +406,23 @@ dependencies = [ "thiserror", ] +[[package]] +name = "cw-storage-macro" +version = "0.13.4" +dependencies = [ + "cosmwasm-std", + "cw-storage-plus", + "serde", + "syn", +] + [[package]] name = "cw-storage-plus" version = "0.13.4" dependencies = [ "cosmwasm-std", "criterion", + "cw-storage-macro", "rand", "schemars", "serde", @@ -1022,11 +1033,11 @@ checksum = "eb9f9e6e233e5c4a35559a617bf40a4ec447db2e84c20b55a6f83167b7e57872" [[package]] name = "proc-macro2" -version = "1.0.38" +version = "1.0.39" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9027b48e9d4c9175fa2218adf3557f91c1137021739951d4932f5f8268ac48aa" +checksum = "c54b25569025b7fc9651de43004ae593a75ad88543b17178aa5e1b9c4f15f56f" dependencies = [ - "unicode-xid", + "unicode-ident", ] [[package]] @@ -1343,13 +1354,13 @@ checksum = "6bdef32e8150c2a081110b42772ffe7d7c9032b606bc226c8260fd97e0976601" [[package]] name = "syn" -version = "1.0.94" +version = "1.0.96" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a07e33e919ebcd69113d5be0e4d70c5707004ff45188910106854f38b960df4a" +checksum = "0748dd251e24453cb8717f0354206b91557e4ec8703673a4b30208f2abaf1ebf" dependencies = [ "proc-macro2", "quote", - "unicode-xid", + "unicode-ident", ] [[package]] @@ -1410,16 +1421,16 @@ dependencies = [ ] [[package]] -name = "unicode-width" -version = "0.1.9" +name = "unicode-ident" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3ed742d4ea2bd1176e236172c8429aaf54486e7ac098db29ffe6529e0ce50973" +checksum = "5bd2fe26506023ed7b5e1e315add59d6f584c621d037f9368fea9cfb988f368c" [[package]] -name = "unicode-xid" -version = "0.2.3" +name = "unicode-width" +version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "957e51f3646910546462e67d5f7599b9e4fb8acdd304b087a6494730f9eebf04" +checksum = "3ed742d4ea2bd1176e236172c8429aaf54486e7ac098db29ffe6529e0ce50973" [[package]] name = "version_check" diff --git a/packages/storage-macro/Cargo.toml b/packages/storage-macro/Cargo.toml new file mode 100644 index 000000000..b29a59f10 --- /dev/null +++ b/packages/storage-macro/Cargo.toml @@ -0,0 +1,21 @@ +[package] +name = "cw-storage-macro" +version = "0.13.4" +authors = ["yoisha <48324733+y-pakorn@users.noreply.github.com>"] +edition = "2018" +description = "Macro helpers for storage-plus" +license = "Apache-2.0" +repository = "https://github.com/CosmWasm/cw-plus" +homepage = "https://cosmwasm.com" +documentation = "https://docs.cosmwasm.com" + +[lib] +proc-macro = true + +[dependencies] +syn = { version = "1.0.96", features = ["full"] } + +[dev-dependencies] +cw-storage-plus = { version = "0.13.4", path = "../storage-plus" } +cosmwasm-std = { version = "1.0.0", default-features = false } +serde = { version = "1.0.103", default-features = false, features = ["derive"] } diff --git a/packages/storage-macro/NOTICE b/packages/storage-macro/NOTICE new file mode 100644 index 000000000..4ae1ccfe5 --- /dev/null +++ b/packages/storage-macro/NOTICE @@ -0,0 +1,14 @@ +CW-Storage-Macro: Macro helpers for storage-plus +Copyright (C) 2022 Confio GmbH + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/packages/storage-macro/README.md b/packages/storage-macro/README.md new file mode 100644 index 000000000..d21d9f571 --- /dev/null +++ b/packages/storage-macro/README.md @@ -0,0 +1,22 @@ +# CW-Storage-Plus: Macro helpers for storage-plus + +Procedural macros helper for interacting with cw-storage-plus and cosmwasm-storage. + +## Current features + +Auto generate an `IndexList` impl for your indexes struct. + +```rust +#[derive(Serialize, Deserialize, Clone, Debug, PartialEq)] +struct TestStruct { + id: u64, + id2: u32, + addr: Addr, +} + +#[index_list(TestStruct)] // <- Add this line right here. +struct TestIndexes<'a> { + id: MultiIndex<'a, u32, TestStruct, u64>, + addr: UniqueIndex<'a, Addr, TestStruct>, +} +``` diff --git a/packages/storage-macro/src/lib.rs b/packages/storage-macro/src/lib.rs new file mode 100644 index 000000000..366723ca5 --- /dev/null +++ b/packages/storage-macro/src/lib.rs @@ -0,0 +1,37 @@ +use proc_macro::TokenStream; +use syn::{ + Ident, + __private::{quote::quote, Span}, + parse_macro_input, ItemStruct, +}; + +#[proc_macro_attribute] +pub fn index_list(attr: TokenStream, item: TokenStream) -> TokenStream { + let input = parse_macro_input!(item as ItemStruct); + + let ty = Ident::new(&attr.to_string(), Span::call_site()); + let struct_ty = input.ident.clone(); + + let names = input + .fields + .clone() + .into_iter() + .map(|e| { + let name = e.ident.unwrap(); + quote! { &self.#name } + }) + .collect::>(); + + let expanded = quote! { + #input + + impl cw_storage_plus::IndexList<#ty> for #struct_ty<'_> { + fn get_indexes(&'_ self) -> Box> + '_> { + let v: Vec<&dyn cw_storage_plus::Index<#ty>> = vec![#(#names),*]; + Box::new(v.into_iter()) + } + } + }; + + TokenStream::from(expanded) +} diff --git a/packages/storage-macro/tests/index_list.rs b/packages/storage-macro/tests/index_list.rs new file mode 100644 index 000000000..57eff5685 --- /dev/null +++ b/packages/storage-macro/tests/index_list.rs @@ -0,0 +1,76 @@ +#[cfg(test)] +mod test { + use cosmwasm_std::{testing::MockStorage, Addr}; + use cw_storage_macro::index_list; + use cw_storage_plus::{IndexedMap, MultiIndex, UniqueIndex}; + use serde::{Deserialize, Serialize}; + + #[test] + fn index_list_compiles() { + #[derive(Serialize, Deserialize, Clone, Debug, PartialEq)] + struct TestStruct { + id: u64, + id2: u32, + addr: Addr, + } + + #[index_list(TestStruct)] + struct TestIndexes<'a> { + id: MultiIndex<'a, u32, TestStruct, u64>, + addr: UniqueIndex<'a, Addr, TestStruct>, + } + + let _: IndexedMap = IndexedMap::new( + "t", + TestIndexes { + id: MultiIndex::new(|t| t.id2, "t", "t_id2"), + addr: UniqueIndex::new(|t| t.addr.clone(), "t_addr"), + }, + ); + } + + #[test] + fn index_list_works() { + #[derive(Serialize, Deserialize, Clone, Debug, PartialEq)] + struct TestStruct { + id: u64, + id2: u32, + addr: Addr, + } + + #[index_list(TestStruct)] + struct TestIndexes<'a> { + id: MultiIndex<'a, u32, TestStruct, u64>, + addr: UniqueIndex<'a, Addr, TestStruct>, + } + + let mut storage = MockStorage::new(); + let idm: IndexedMap = IndexedMap::new( + "t", + TestIndexes { + id: MultiIndex::new(|t| t.id2, "t", "t_2"), + addr: UniqueIndex::new(|t| t.addr.clone(), "t_addr"), + }, + ); + + idm.save( + &mut storage, + 0, + &TestStruct { + id: 0, + id2: 100, + addr: Addr::unchecked("1"), + }, + ) + .unwrap(); + + assert_eq!( + idm.load(&storage, 0).unwrap(), + TestStruct { + id: 0, + id2: 100, + addr: Addr::unchecked("1"), + } + ); + } +} diff --git a/packages/storage-plus/Cargo.toml b/packages/storage-plus/Cargo.toml index 5370e5eb2..524890ef1 100644 --- a/packages/storage-plus/Cargo.toml +++ b/packages/storage-plus/Cargo.toml @@ -11,6 +11,7 @@ homepage = "https://cosmwasm.com" [features] default = ["iterator"] iterator = ["cosmwasm-std/iterator"] +macro = ["cw-storage-macro"] [lib] # See https://bheisler.github.io/criterion.rs/book/faq.html#cargo-bench-gives-unrecognized-option-errors-for-valid-command-line-options @@ -20,6 +21,7 @@ bench = false cosmwasm-std = { version = "1.0.0", default-features = false } schemars = "0.8.1" serde = { version = "1.0.103", default-features = false, features = ["derive"] } +cw-storage-macro = { version = "0.13.4", optional = true, path = "../storage-macro" } [dev-dependencies] criterion = { version = "0.3", features = [ "html_reports" ] } diff --git a/packages/storage-plus/src/lib.rs b/packages/storage-plus/src/lib.rs index 5562073c0..d6f93efb3 100644 --- a/packages/storage-plus/src/lib.rs +++ b/packages/storage-plus/src/lib.rs @@ -40,3 +40,10 @@ pub use path::Path; pub use prefix::{range_with_prefix, Prefix}; #[cfg(feature = "iterator")] pub use snapshot::{SnapshotItem, SnapshotMap, Strategy}; + +#[cfg(all(feature = "iterator", feature = "macro"))] +#[macro_use] +extern crate cw_storage_macro; +#[cfg(all(feature = "iterator", feature = "macro"))] +#[doc(hidden)] +pub use cw_storage_macro::*;