Skip to content

Commit

Permalink
(dirty): make a mismatch of PK in an IndexedMap impossible
Browse files Browse the repository at this point in the history
  • Loading branch information
uint committed Sep 12, 2024
1 parent c1b1008 commit 4c2aed4
Show file tree
Hide file tree
Showing 5 changed files with 43 additions and 37 deletions.
50 changes: 27 additions & 23 deletions src/indexed_map.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@ use crate::map::Map;
use crate::prefix::{namespaced_prefix_range, Prefix};
use crate::{Bound, Path};

pub trait IndexList<T> {
fn get_indexes(&'_ self) -> Box<dyn Iterator<Item = &'_ dyn Index<T>> + '_>;
pub trait IndexList<PK, T> {
fn get_indexes(&'_ self) -> Box<dyn Iterator<Item = &'_ dyn Index<PK, T>> + '_>;
}

/// `IndexedMap` works like a `Map` but has a secondary index
Expand All @@ -32,7 +32,7 @@ impl<'a, K, T, I> IndexedMap<K, T, I>
where
K: PrimaryKey<'a>,
T: Serialize + DeserializeOwned + Clone,
I: IndexList<T>,
I: IndexList<K, T>,
{
/// Creates a new [`IndexedMap`] with the given storage key. This is a constant function only suitable
/// when you have a prefix in the form of a static string slice.
Expand Down Expand Up @@ -65,7 +65,7 @@ impl<'a, K, T, I> IndexedMap<K, T, I>
where
K: PrimaryKey<'a>,
T: Serialize + DeserializeOwned + Clone,
I: IndexList<T>,
I: IndexList<K, T>,
{
/// save will serialize the model and store, returns an error on serialization issues.
/// this must load the old value to update the indexes properly
Expand Down Expand Up @@ -182,7 +182,7 @@ impl<'a, K, T, I> IndexedMap<K, T, I>
where
K: PrimaryKey<'a>,
T: Serialize + DeserializeOwned + Clone,
I: IndexList<T>,
I: IndexList<K, T>,
{
/// While `range_raw` over a `prefix` fixes the prefix to one element and iterates over the
/// remaining, `prefix_range_raw` accepts bounds for the lowest and highest elements of the `Prefix`
Expand Down Expand Up @@ -211,7 +211,7 @@ impl<'a, K, T, I> IndexedMap<K, T, I>
where
T: Serialize + DeserializeOwned + Clone,
K: PrimaryKey<'a>,
I: IndexList<T>,
I: IndexList<K, T>,
{
pub fn sub_prefix(&self, p: K::SubPrefix) -> Prefix<K::SuperSuffix, T, K::SuperSuffix> {
Prefix::new(self.pk_namespace.as_slice(), &p.prefix())
Expand All @@ -227,7 +227,7 @@ impl<'a, K, T, I> IndexedMap<K, T, I>
where
T: Serialize + DeserializeOwned + Clone,
K: PrimaryKey<'a> + KeyDeserialize,
I: IndexList<T>,
I: IndexList<K, T>,
{
/// While `range` over a `prefix` fixes the prefix to one element and iterates over the
/// remaining, `prefix_range` accepts bounds for the lowest and highest elements of the
Expand Down Expand Up @@ -334,9 +334,10 @@ mod test {
}

// Future Note: this can likely be macro-derived
impl<'a> IndexList<Data> for DataIndexes<'a> {
fn get_indexes(&'_ self) -> Box<dyn Iterator<Item = &'_ dyn Index<Data>> + '_> {
let v: Vec<&dyn Index<Data>> = vec![&self.name, &self.age, &self.name_lastname];
impl<'a, 's> IndexList<&'s str, Data> for DataIndexes<'a> {
fn get_indexes(&'_ self) -> Box<dyn Iterator<Item = &'_ dyn Index<&'s str, Data>> + '_> {
let v: Vec<&dyn Index<&'s str, Data>> =
vec![&self.name, &self.age, &self.name_lastname];
Box::new(v.into_iter())
}
}
Expand All @@ -348,9 +349,9 @@ mod test {
}

// Future Note: this can likely be macro-derived
impl<'a> IndexList<Data> for DataCompositeMultiIndex<'a> {
fn get_indexes(&'_ self) -> Box<dyn Iterator<Item = &'_ dyn Index<Data>> + '_> {
let v: Vec<&dyn Index<Data>> = vec![&self.name_age];
impl<'a, 's> IndexList<&'s str, Data> for DataCompositeMultiIndex<'a> {
fn get_indexes(&'_ self) -> Box<dyn Iterator<Item = &'_ dyn Index<&'s str, Data>> + '_> {
let v: Vec<&dyn Index<&'s str, Data>> = vec![&self.name_age];
Box::new(v.into_iter())
}
}
Expand Down Expand Up @@ -740,6 +741,7 @@ mod test {
}

#[test]
#[ignore]
fn range_composite_key_by_multi_index() {
let mut store = MockStorage::new();

Expand Down Expand Up @@ -1454,12 +1456,12 @@ mod test {
use super::*;

struct Indexes<'a> {
secondary: UniqueIndex<'a, u64, u64, ()>,
secondary: UniqueIndex<'a, u64, u64, String>,
}

impl<'a> IndexList<u64> for Indexes<'a> {
fn get_indexes(&'_ self) -> Box<dyn Iterator<Item = &'_ dyn Index<u64>> + '_> {
let v: Vec<&dyn Index<u64>> = vec![&self.secondary];
impl<'a, 's> IndexList<&'s str, u64> for Indexes<'a> {
fn get_indexes(&'_ self) -> Box<dyn Iterator<Item = &'_ dyn Index<&'s str, u64>> + '_> {
let v: Vec<&dyn Index<&'s str, u64>> = vec![&self.secondary];
Box::new(v.into_iter())
}
}
Expand Down Expand Up @@ -1510,9 +1512,9 @@ mod test {
secondary: MultiIndex<'a, u64, u64, &'a str>,
}

impl<'a> IndexList<u64> for Indexes<'a> {
fn get_indexes(&'_ self) -> Box<dyn Iterator<Item = &'_ dyn Index<u64>> + '_> {
let v: Vec<&dyn Index<u64>> = vec![&self.secondary];
impl<'a> IndexList<&'a str, u64> for Indexes<'a> {
fn get_indexes(&'_ self) -> Box<dyn Iterator<Item = &'_ dyn Index<&'a str, u64>> + '_> {
let v: Vec<&dyn Index<&'a str, u64>> = vec![&self.secondary];
Box::new(v.into_iter())
}
}
Expand Down Expand Up @@ -1583,9 +1585,11 @@ mod test {
spender: MultiIndex<'a, Addr, Uint128, (Addr, Addr)>,
}

impl<'a> IndexList<Uint128> for Indexes<'a> {
fn get_indexes(&'_ self) -> Box<dyn Iterator<Item = &'_ dyn Index<Uint128>> + '_> {
let v: Vec<&dyn Index<Uint128>> = vec![&self.spender];
impl<'a> IndexList<(Addr, Addr), Uint128> for Indexes<'a> {
fn get_indexes(
&'_ self,
) -> Box<dyn Iterator<Item = &'_ dyn Index<(Addr, Addr), Uint128>> + '_> {
let v: Vec<&dyn Index<(Addr, Addr), Uint128>> = vec![&self.spender];
Box::new(v.into_iter())
}
}
Expand Down
22 changes: 11 additions & 11 deletions src/indexed_snapshot.rs
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ impl<'a, K, T, I> IndexedSnapshotMap<K, T, I>
where
T: Serialize + DeserializeOwned + Clone,
K: PrimaryKey<'a> + Prefixer<'a> + KeyDeserialize,
I: IndexList<T>,
I: IndexList<K, T>,
{
pub fn add_checkpoint(&self, store: &mut dyn Storage, height: u64) -> StdResult<()> {
self.primary.add_checkpoint(store, height)
Expand Down Expand Up @@ -101,7 +101,7 @@ impl<'a, K, T, I> IndexedSnapshotMap<K, T, I>
where
K: PrimaryKey<'a> + Prefixer<'a> + KeyDeserialize,
T: Serialize + DeserializeOwned + Clone,
I: IndexList<T>,
I: IndexList<K, T>,
{
/// save will serialize the model and store, returns an error on serialization issues.
/// this must load the old value to update the indexes properly
Expand Down Expand Up @@ -192,7 +192,7 @@ impl<'a, K, T, I> IndexedSnapshotMap<K, T, I>
where
K: PrimaryKey<'a> + Prefixer<'a> + KeyDeserialize,
T: Serialize + DeserializeOwned + Clone,
I: IndexList<T>,
I: IndexList<K, T>,
{
// I would prefer not to copy code from Prefix, but no other way
// with lifetimes (create Prefix inside function and return ref = no no)
Expand Down Expand Up @@ -225,7 +225,7 @@ impl<'a, K, T, I> IndexedSnapshotMap<K, T, I>
where
T: Serialize + DeserializeOwned + Clone,
K: PrimaryKey<'a>,
I: IndexList<T>,
I: IndexList<K, T>,
{
pub fn sub_prefix(&self, p: K::SubPrefix) -> Prefix<K::SuperSuffix, T, K::SuperSuffix> {
Prefix::new(self.pk_namespace.as_slice(), &p.prefix())
Expand All @@ -241,7 +241,7 @@ impl<'a, K, T, I> IndexedSnapshotMap<K, T, I>
where
T: Serialize + DeserializeOwned + Clone,
K: PrimaryKey<'a> + KeyDeserialize,
I: IndexList<T>,
I: IndexList<K, T>,
{
/// While `range` over a `prefix` fixes the prefix to one element and iterates over the
/// remaining, `prefix_range` accepts bounds for the lowest and highest elements of the
Expand Down Expand Up @@ -325,9 +325,9 @@ mod test {
}

// Future Note: this can likely be macro-derived
impl<'a> IndexList<Data> for DataIndexes<'a> {
fn get_indexes(&'_ self) -> Box<dyn Iterator<Item = &'_ dyn Index<Data>> + '_> {
let v: Vec<&dyn Index<Data>> = vec![&self.name, &self.age, &self.name_lastname];
impl<'a> IndexList<String, Data> for DataIndexes<'a> {
fn get_indexes(&'_ self) -> Box<dyn Iterator<Item = &'_ dyn Index<String, Data>> + '_> {
let v: Vec<&dyn Index<String, Data>> = vec![&self.name, &self.age, &self.name_lastname];
Box::new(v.into_iter())
}
}
Expand All @@ -339,9 +339,9 @@ mod test {
}

// Future Note: this can likely be macro-derived
impl<'a> IndexList<Data> for DataCompositeMultiIndex<'a> {
fn get_indexes(&'_ self) -> Box<dyn Iterator<Item = &'_ dyn Index<Data>> + '_> {
let v: Vec<&dyn Index<Data>> = vec![&self.name_age];
impl<'a> IndexList<String, Data> for DataCompositeMultiIndex<'a> {
fn get_indexes(&'_ self) -> Box<dyn Iterator<Item = &'_ dyn Index<String, Data>> + '_> {
let v: Vec<&dyn Index<String, Data>> = vec![&self.name_age];
Box::new(v.into_iter())
}
}
Expand Down
2 changes: 1 addition & 1 deletion src/indexes/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ use cosmwasm_std::{StdResult, Storage};

// Note: we cannot store traits with generic functions inside `Box<dyn Index>`,
// so I pull S: Storage to a top-level
pub trait Index<T>
pub trait Index<K, T>
where
T: Serialize + DeserializeOwned + Clone,
{
Expand Down
3 changes: 2 additions & 1 deletion src/indexes/multi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -129,10 +129,11 @@ fn deserialize_multi_kv<K: KeyDeserialize, T: DeserializeOwned>(
Ok((K::from_slice(pk)?, v))
}

impl<'a, IK, T, PK> Index<T> for MultiIndex<'a, IK, T, PK>
impl<'a, IK, T, PK, ALTPK> Index<ALTPK, T> for MultiIndex<'a, IK, T, PK>
where
T: Serialize + DeserializeOwned + Clone,
IK: PrimaryKey<'a>,
ALTPK: Into<PK>,
{
fn save(&self, store: &mut dyn Storage, pk: &[u8], data: &T) -> StdResult<()> {
let idx = (self.index)(pk, data).joined_extra_key(pk);
Expand Down
3 changes: 2 additions & 1 deletion src/indexes/unique.rs
Original file line number Diff line number Diff line change
Expand Up @@ -62,10 +62,11 @@ impl<'a, IK, T, PK> UniqueIndex<'a, IK, T, PK> {
}
}

impl<'a, IK, T, PK> Index<T> for UniqueIndex<'a, IK, T, PK>
impl<'a, IK, T, PK, ALTPK> Index<ALTPK, T> for UniqueIndex<'a, IK, T, PK>
where
T: Serialize + DeserializeOwned + Clone,
IK: PrimaryKey<'a>,
ALTPK: Into<PK>,
{
fn save(&self, store: &mut dyn Storage, pk: &[u8], data: &T) -> StdResult<()> {
let idx = (self.index)(data);
Expand Down

0 comments on commit 4c2aed4

Please sign in to comment.