From dee47e4261308cf92ffa3b5aff855f6ed7cb6b9a Mon Sep 17 00:00:00 2001 From: Tomasz Kurcz Date: Thu, 24 Oct 2024 20:20:21 +0200 Subject: [PATCH] prevent inconsistent PK in Index implementors --- macros/src/lib.rs | 24 +++++++++++++++---- src/indexed_map.rs | 53 +++++++++++++++++++++++++++++------------ src/indexed_snapshot.rs | 17 +++++++++---- src/indexes/mod.rs | 2 ++ src/indexes/multi.rs | 2 ++ src/indexes/unique.rs | 2 ++ src/lib.rs | 2 +- tests/index_list.rs | 4 ++-- 8 files changed, 80 insertions(+), 26 deletions(-) diff --git a/macros/src/lib.rs b/macros/src/lib.rs index 23ecc5c..5ad52cd 100644 --- a/macros/src/lib.rs +++ b/macros/src/lib.rs @@ -7,9 +7,9 @@ For more information on this package, please check out the use proc_macro::TokenStream; use syn::{ - Ident, + Ident, Type, TypePath, __private::{quote::quote, Span}, - parse_macro_input, ItemStruct, + parse_macro_input, ItemStruct, Lifetime, }; #[proc_macro_attribute] @@ -29,12 +29,28 @@ pub fn index_list(attr: TokenStream, item: TokenStream) -> TokenStream { }) .collect::>(); + let mut first_ix_type = input.fields.iter().next().unwrap().ty.clone(); + // change all lifetime params to 'static + if let Type::Path(TypePath { ref mut path, .. }) = first_ix_type { + path.segments.iter_mut().for_each(|seg| { + if let syn::PathArguments::AngleBracketed(ref mut args) = seg.arguments { + for arg in args.args.iter_mut() { + if let syn::GenericArgument::Lifetime(ref mut lt) = arg { + *lt = Lifetime::new("'static", Span::call_site()); + } + } + } + }); + } + 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),*]; + type PK = <#first_ix_type as ::cw_storage_plus::Index<#ty>>::PK; + + fn get_indexes(&'_ self) -> Box> + '_> { + let v: Vec<&dyn cw_storage_plus::Index<#ty, PK = Self::PK>> = vec![#(#names),*]; Box::new(v.into_iter()) } } diff --git a/src/indexed_map.rs b/src/indexed_map.rs index a391990..b7d5001 100644 --- a/src/indexed_map.rs +++ b/src/indexed_map.rs @@ -16,7 +16,9 @@ use crate::prefix::{namespaced_prefix_range, Prefix}; use crate::{Bound, Path}; pub trait IndexList { - fn get_indexes(&'_ self) -> Box> + '_>; + type PK; + + fn get_indexes(&'_ self) -> Box> + '_>; } /// `IndexedMap` works like a `Map` but has a secondary index @@ -335,8 +337,13 @@ mod test { // Future Note: this can likely be macro-derived impl<'a> IndexList for DataIndexes<'a> { - fn get_indexes(&'_ self) -> Box> + '_> { - let v: Vec<&dyn Index> = vec![&self.name, &self.age, &self.name_lastname]; + type PK = String; + + fn get_indexes( + &'_ self, + ) -> Box> + '_> { + let v: Vec<&dyn Index> = + vec![&self.name, &self.age, &self.name_lastname]; Box::new(v.into_iter()) } } @@ -349,8 +356,12 @@ mod test { // Future Note: this can likely be macro-derived impl<'a> IndexList for DataCompositeMultiIndex<'a> { - fn get_indexes(&'_ self) -> Box> + '_> { - let v: Vec<&dyn Index> = vec![&self.name_age]; + type PK = String; + + fn get_indexes( + &'_ self, + ) -> Box> + '_> { + let v: Vec<&dyn Index> = vec![&self.name_age]; Box::new(v.into_iter()) } } @@ -1453,13 +1464,17 @@ mod test { mod bounds_unique_index { use super::*; - struct Indexes<'a> { - secondary: UniqueIndex<'a, u64, u64, ()>, + struct Indexes<'a, 's> { + secondary: UniqueIndex<'a, u64, u64, &'s str>, } - impl<'a> IndexList for Indexes<'a> { - fn get_indexes(&'_ self) -> Box> + '_> { - let v: Vec<&dyn Index> = vec![&self.secondary]; + impl<'a, 's> IndexList for Indexes<'a, 's> { + type PK = &'s str; + + fn get_indexes( + &'_ self, + ) -> Box> + '_> { + let v: Vec<&dyn Index> = vec![&self.secondary]; Box::new(v.into_iter()) } } @@ -1498,7 +1513,7 @@ mod test { .collect::>() .unwrap(); - assert_eq!(items, vec![((), 3)]); + matches!(items.as_slice(), [(_, 3)]); } } @@ -1511,8 +1526,12 @@ mod test { } impl<'a> IndexList for Indexes<'a> { - fn get_indexes(&'_ self) -> Box> + '_> { - let v: Vec<&dyn Index> = vec![&self.secondary]; + type PK = &'a str; + + fn get_indexes( + &'_ self, + ) -> Box> + '_> { + let v: Vec<&dyn Index> = vec![&self.secondary]; Box::new(v.into_iter()) } } @@ -1584,8 +1603,12 @@ mod test { } impl<'a> IndexList for Indexes<'a> { - fn get_indexes(&'_ self) -> Box> + '_> { - let v: Vec<&dyn Index> = vec![&self.spender]; + type PK = (Addr, Addr); + + fn get_indexes( + &'_ self, + ) -> Box> + '_> { + let v: Vec<&dyn Index> = vec![&self.spender]; Box::new(v.into_iter()) } } diff --git a/src/indexed_snapshot.rs b/src/indexed_snapshot.rs index ebc5883..eb09ab4 100644 --- a/src/indexed_snapshot.rs +++ b/src/indexed_snapshot.rs @@ -326,8 +326,13 @@ mod test { // Future Note: this can likely be macro-derived impl<'a> IndexList for DataIndexes<'a> { - fn get_indexes(&'_ self) -> Box> + '_> { - let v: Vec<&dyn Index> = vec![&self.name, &self.age, &self.name_lastname]; + type PK = String; + + fn get_indexes( + &'_ self, + ) -> Box> + '_> { + let v: Vec<&dyn Index> = + vec![&self.name, &self.age, &self.name_lastname]; Box::new(v.into_iter()) } } @@ -340,8 +345,12 @@ mod test { // Future Note: this can likely be macro-derived impl<'a> IndexList for DataCompositeMultiIndex<'a> { - fn get_indexes(&'_ self) -> Box> + '_> { - let v: Vec<&dyn Index> = vec![&self.name_age]; + type PK = String; + + fn get_indexes( + &'_ self, + ) -> Box> + '_> { + let v: Vec<&dyn Index> = vec![&self.name_age]; Box::new(v.into_iter()) } } diff --git a/src/indexes/mod.rs b/src/indexes/mod.rs index 800d503..0471274 100644 --- a/src/indexes/mod.rs +++ b/src/indexes/mod.rs @@ -19,6 +19,8 @@ pub trait Index where T: Serialize + DeserializeOwned + Clone, { + type PK; + fn save(&self, store: &mut dyn Storage, pk: &[u8], data: &T) -> StdResult<()>; fn remove(&self, store: &mut dyn Storage, pk: &[u8], old_data: &T) -> StdResult<()>; } diff --git a/src/indexes/multi.rs b/src/indexes/multi.rs index 6044d17..c72e747 100644 --- a/src/indexes/multi.rs +++ b/src/indexes/multi.rs @@ -134,6 +134,8 @@ where T: Serialize + DeserializeOwned + Clone, IK: PrimaryKey<'a>, { + type PK = PK; + fn save(&self, store: &mut dyn Storage, pk: &[u8], data: &T) -> StdResult<()> { let idx = (self.index)(pk, data).joined_extra_key(pk); self.idx_map.save(store, idx, &(pk.len() as u32)) diff --git a/src/indexes/unique.rs b/src/indexes/unique.rs index de5a0a9..c84f3a8 100644 --- a/src/indexes/unique.rs +++ b/src/indexes/unique.rs @@ -67,6 +67,8 @@ where T: Serialize + DeserializeOwned + Clone, IK: PrimaryKey<'a>, { + type PK = PK; + fn save(&self, store: &mut dyn Storage, pk: &[u8], data: &T) -> StdResult<()> { let idx = (self.index)(data); // error if this is already set diff --git a/src/lib.rs b/src/lib.rs index 99f1718..e238cad 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -78,7 +78,7 @@ extern crate cw_storage_macro; /// #[index_list(TestStruct)] // <- Add this line right here. /// struct TestIndexes<'a> { /// id: MultiIndex<'a, u32, TestStruct, u64>, -/// addr: UniqueIndex<'a, Addr, TestStruct, ()>, +/// addr: UniqueIndex<'a, Addr, TestStruct, u64>, /// } /// ``` /// diff --git a/tests/index_list.rs b/tests/index_list.rs index 879bb5f..389d868 100644 --- a/tests/index_list.rs +++ b/tests/index_list.rs @@ -17,7 +17,7 @@ mod test { #[index_list(TestStruct)] struct TestIndexes<'a> { id: MultiIndex<'a, u32, TestStruct, u64>, - addr: UniqueIndex<'a, Addr, TestStruct, ()>, + addr: UniqueIndex<'a, Addr, TestStruct, u64>, } let _: IndexedMap = IndexedMap::new( @@ -41,7 +41,7 @@ mod test { #[index_list(TestStruct)] struct TestIndexes<'a> { id: MultiIndex<'a, u32, TestStruct, u64>, - addr: UniqueIndex<'a, Addr, TestStruct, ()>, + addr: UniqueIndex<'a, Addr, TestStruct, u64>, } let mut storage = MockStorage::new();