diff --git a/CHANGELOG.md b/CHANGELOG.md index 996043d380..569af46974 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,11 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [Unreleased] + +### Fixed +- Fixing `ManualKey<0>` to act properly - [#1670](https://github.com/paritytech/ink/pull/1670) + ## Version 4.0.0 The latest stable release of ink! is here 🥳 diff --git a/crates/storage/traits/src/impls/mod.rs b/crates/storage/traits/src/impls/mod.rs index e44d1e9f6d..bf19eb9736 100644 --- a/crates/storage/traits/src/impls/mod.rs +++ b/crates/storage/traits/src/impls/mod.rs @@ -27,6 +27,14 @@ use ink_primitives::{ KeyComposer, }; +/// The private trait helping identify the [`AutoKey`] key type. +trait KeyType { + /// It is `true` for [`AutoKey`] and `false` for [`ManualKey`]. + /// It helps the [`ResolverKey`] select between the user-specified (left key) + /// and the auto-generated (right key) keys. + const IS_AUTO_KEY: bool; +} + /// Auto key type means that the storage key should be calculated automatically. #[derive(Default, Copy, Clone, PartialEq, Eq, PartialOrd)] #[cfg_attr(feature = "std", derive(scale_info::TypeInfo))] @@ -36,6 +44,10 @@ impl StorageKey for AutoKey { const KEY: Key = 0; } +impl KeyType for AutoKey { + const IS_AUTO_KEY: bool = true; +} + impl Debug for AutoKey { fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { f.debug_struct("AutoKey") @@ -55,6 +67,10 @@ impl StorageKey for ManualKey KeyType for ManualKey { + const IS_AUTO_KEY: bool = false; +} + impl Debug for ManualKey { fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { f.debug_struct("ManualKey") @@ -67,11 +83,26 @@ impl Debug for ManualKey /// If the `L` type is `AutoKey` it returns auto-generated `R` else `L`. #[derive(Default, Copy, Clone, PartialEq, Eq, PartialOrd, Debug)] #[cfg_attr(feature = "std", derive(scale_info::TypeInfo))] -pub struct ResolverKey(PhantomData (L, R)>); +pub struct ResolverKey(PhantomData (L, R)>); -impl StorageKey for ResolverKey { - /// `KEY` of the `AutoKey` is zero. If left key is zero, then use right manual key. - const KEY: Key = if L::KEY == 0 { R::KEY } else { L::KEY }; +impl StorageKey for ResolverKey +where + L: StorageKey + KeyType, + R: StorageKey + KeyType, +{ + /// If the left key is [`AutoKey`], then use the right auto-generated storage key. + /// Otherwise use the left [`ManualKey`]. + const KEY: Key = if L::IS_AUTO_KEY { R::KEY } else { L::KEY }; +} + +impl KeyType for ResolverKey +where + L: KeyType, + R: KeyType, +{ + /// The right key is always an auto-generated key, the user can specify only the left key. + /// So the left key defines the [`KeyType::IS_AUTO_KEY`] of the [`ResolverKey`]. + const IS_AUTO_KEY: bool = L::IS_AUTO_KEY; } type FinalKey = @@ -84,6 +115,7 @@ type FinalKey = impl AutoStorableHint> for T where T: StorableHint, + >::PreferredKey: KeyType, T: StorableHint>, ParentKey: StorageKey, { @@ -111,6 +143,8 @@ where #[cfg(test)] mod tests { + use super::*; + /// Creates test to verify that the primitive types are packed. #[macro_export] macro_rules! storage_hint_works_for_primitive { @@ -174,4 +208,24 @@ mod tests { type TupleSix = (i32, u32, String, u8, bool, Box>); storage_hint_works_for_primitive!(TupleSix); } + + #[test] + fn storage_key_types_works() { + assert_eq!(::KEY, 0); + assert_eq!( as StorageKey>::KEY, 123); + assert_eq!( as StorageKey>::KEY, 0); + assert_eq!( as StorageKey>::KEY, 0); + assert_eq!( + > as StorageKey>::KEY, + 123 + ); + assert_eq!( + , ManualKey<123>> as StorageKey>::KEY, + 456 + ); + assert_eq!( + , ManualKey<123>> as StorageKey>::KEY, + 0 + ); + } }