From 5ec9dbee0705c3188e36da143cb9445549a79afa Mon Sep 17 00:00:00 2001 From: Daniel Shiposha Date: Wed, 11 Oct 2023 19:45:51 +0000 Subject: [PATCH] refactor: LazyValue without generic Fn --- --- a/pallets/common/src/lib.rs +++ b/pallets/common/src/lib.rs @@ -53,10 +53,12 @@ #![cfg_attr(not(feature = "std"), no_std)] extern crate alloc; +use alloc::boxed::Box; use core::{ marker::PhantomData, ops::{Deref, DerefMut}, slice::from_ref, + unreachable, }; use evm_coder::ToLog; @@ -871,63 +873,81 @@ >; } +enum LazyValueState<'a, T> { + Pending(Box T + 'a>), + InProgress(PhantomData>), + Computed(T), +} + /// Value representation with delayed initialization time. -pub struct LazyValue { - value: Option, - f: Option, +pub struct LazyValue<'a, T> { + state: LazyValueState<'a, T>, } -impl T> LazyValue { +impl<'a, T> LazyValue<'a, T> { /// Create a new LazyValue. - pub fn new(f: F) -> Self { + pub fn new(f: impl FnOnce() -> T + 'a) -> Self { Self { - value: None, - f: Some(f), + state: LazyValueState::Pending(Box::new(f)), } } /// Get the value. If it is called the first time, the value will be initialized. pub fn value(&mut self) -> &T { self.force_value(); - self.value.as_ref().unwrap() + self.value_mut() } /// Get the value. If it is called the first time, the value will be initialized. pub fn value_mut(&mut self) -> &mut T { self.force_value(); - self.value.as_mut().unwrap() + + if let LazyValueState::Computed(value) = &mut self.state { + value + } else { + unreachable!() + } } fn into_inner(mut self) -> T { self.force_value(); - self.value.unwrap() + if let LazyValueState::Computed(value) = self.state { + value + } else { + unreachable!() + } } /// Is value initialized? pub fn has_value(&self) -> bool { - self.value.is_some() + matches!(self.state, LazyValueState::Computed(_)) } fn force_value(&mut self) { - if self.value.is_none() { - self.value = Some(self.f.take().unwrap()()) + use LazyValueState::*; + + if self.has_value() { + return; + } + + match sp_std::mem::replace(&mut self.state, InProgress(PhantomData)) { + Pending(f) => self.state = Computed(f()), + _ => { + // Computed is ruled out by the above condition + // InProgress is ruled out by not implementing Sync and absence of recursion + unreachable!() + } } } } -fn check_token_permissions( +fn check_token_permissions( collection_admin_permitted: bool, token_owner_permitted: bool, - is_collection_admin: &mut LazyValue, - is_token_owner: &mut LazyValue, FTO>, - is_token_exist: &mut LazyValue, -) -> DispatchResult -where - T: Config, - FCA: FnOnce() -> bool, - FTO: FnOnce() -> Result, - FTE: FnOnce() -> bool, -{ + is_collection_admin: &mut LazyValue, + is_token_owner: &mut LazyValue>, + is_token_exist: &mut LazyValue, +) -> DispatchResult { if !(collection_admin_permitted && *is_collection_admin.value() || token_owner_permitted && (*is_token_owner.value())?) { @@ -2346,36 +2366,24 @@ /// This type utilizes the lazy evaluation to avoid repeating the computation /// of several performance-heavy or PoV-heavy tasks, /// such as checking the indirect ownership or reading the token property permissions. -pub struct PropertyWriter<'a, WriterVariant, T, Handle, FIsAdmin, FPropertyPermissions> { +pub struct PropertyWriter<'a, WriterVariant, T, Handle> { collection: &'a Handle, - collection_lazy_info: PropertyWriterLazyCollectionInfo, + collection_lazy_info: PropertyWriterLazyCollectionInfo<'a>, _phantom: PhantomData<(T, WriterVariant)>, } -impl<'a, T, Handle, WriterVariant, FIsAdmin, FPropertyPermissions> - PropertyWriter<'a, WriterVariant, T, Handle, FIsAdmin, FPropertyPermissions> +impl<'a, T, Handle, WriterVariant> PropertyWriter<'a, WriterVariant, T, Handle> where T: Config, Handle: CommonCollectionOperations + Deref>, - FIsAdmin: FnOnce() -> bool, - FPropertyPermissions: FnOnce() -> PropertiesPermissionMap, { - fn internal_write_token_properties( + fn internal_write_token_properties( &mut self, token_id: TokenId, - mut token_lazy_info: PropertyWriterLazyTokenInfo< - FCheckTokenExist, - FCheckTokenOwner, - FGetProperties, - >, + mut token_lazy_info: PropertyWriterLazyTokenInfo, properties_updates: impl Iterator)>, log: evm_coder::ethereum::Log, - ) -> DispatchResult - where - FCheckTokenExist: FnOnce() -> bool, - FCheckTokenOwner: FnOnce() -> Result, - FGetProperties: FnOnce() -> TokenProperties, - { + ) -> DispatchResult { for (key, value) in properties_updates { let permission = self .collection_lazy_info @@ -2400,7 +2408,7 @@ collection_admin, token_owner, .. - } => check_token_permissions::( + } => check_token_permissions::( collection_admin, token_owner, &mut self.collection_lazy_info.is_collection_admin, @@ -2454,31 +2462,25 @@ /// A helper structure for the [`PropertyWriter`] that holds /// the collection-related info. The info is loaded using lazy evaluation. /// This info is common for any token for which we write properties. -pub struct PropertyWriterLazyCollectionInfo { - is_collection_admin: LazyValue, - property_permissions: LazyValue, +pub struct PropertyWriterLazyCollectionInfo<'a> { + is_collection_admin: LazyValue<'a, bool>, + property_permissions: LazyValue<'a, PropertiesPermissionMap>, } /// A helper structure for the [`PropertyWriter`] that holds /// the token-related info. The info is loaded using lazy evaluation. -pub struct PropertyWriterLazyTokenInfo { - is_token_exist: LazyValue, - is_token_owner: LazyValue, FCheckTokenOwner>, - stored_properties: LazyValue, +pub struct PropertyWriterLazyTokenInfo<'a> { + is_token_exist: LazyValue<'a, bool>, + is_token_owner: LazyValue<'a, Result>, + stored_properties: LazyValue<'a, TokenProperties>, } -impl - PropertyWriterLazyTokenInfo -where - FCheckTokenExist: FnOnce() -> bool, - FCheckTokenOwner: FnOnce() -> Result, - FGetProperties: FnOnce() -> TokenProperties, -{ +impl<'a> PropertyWriterLazyTokenInfo<'a> { /// Create a lazy token info. pub fn new( - check_token_exist: FCheckTokenExist, - check_token_owner: FCheckTokenOwner, - get_token_properties: FGetProperties, + check_token_exist: impl FnOnce() -> bool + 'a, + check_token_owner: impl FnOnce() -> Result + 'a, + get_token_properties: impl FnOnce() -> TokenProperties + 'a, ) -> Self { Self { is_token_exist: LazyValue::new(check_token_exist), @@ -2496,14 +2498,7 @@ pub fn new<'a, Handle>( collection: &'a Handle, sender: &'a T::CrossAccountId, - ) -> PropertyWriter< - 'a, - Self, - T, - Handle, - impl FnOnce() -> bool + 'a, - impl FnOnce() -> PropertiesPermissionMap + 'a, - > + ) -> PropertyWriter<'a, Self, T, Handle> where T: Config, Handle: CommonCollectionOperations + Deref>, @@ -2521,13 +2516,10 @@ } } -impl<'a, T, Handle, FIsAdmin, FPropertyPermissions> - PropertyWriter<'a, NewTokenPropertyWriter, T, Handle, FIsAdmin, FPropertyPermissions> +impl<'a, T, Handle> PropertyWriter<'a, NewTokenPropertyWriter, T, Handle> where T: Config, Handle: CommonCollectionOperations + Deref>, - FIsAdmin: FnOnce() -> bool, - FPropertyPermissions: FnOnce() -> PropertiesPermissionMap, { /// A function to write properties to a **newly created** token. pub fn write_token_properties( @@ -2570,14 +2562,7 @@ pub fn new<'a, Handle>( collection: &'a Handle, sender: &'a T::CrossAccountId, - ) -> PropertyWriter< - 'a, - Self, - T, - Handle, - impl FnOnce() -> bool + 'a, - impl FnOnce() -> PropertiesPermissionMap + 'a, - > + ) -> PropertyWriter<'a, Self, T, Handle> where Handle: CommonCollectionOperations + Deref>, { @@ -2594,13 +2579,10 @@ } } -impl<'a, T, Handle, FIsAdmin, FPropertyPermissions> - PropertyWriter<'a, ExistingTokenPropertyWriter, T, Handle, FIsAdmin, FPropertyPermissions> +impl<'a, T, Handle> PropertyWriter<'a, ExistingTokenPropertyWriter, T, Handle> where T: Config, Handle: CommonCollectionOperations + Deref>, - FIsAdmin: FnOnce() -> bool, - FPropertyPermissions: FnOnce() -> PropertiesPermissionMap, { /// A function to write properties to an **already existing** token. pub fn write_token_properties( @@ -2643,14 +2625,12 @@ #[cfg(feature = "runtime-benchmarks")] impl BenchmarkPropertyWriter { /// Creates a [`PropertyWriter`] for benchmarking tokens properties writing. - pub fn new<'a, Handle, FIsAdmin, FPropertyPermissions>( + pub fn new<'a, Handle>( collection: &Handle, - collection_lazy_info: PropertyWriterLazyCollectionInfo, - ) -> PropertyWriter + collection_lazy_info: PropertyWriterLazyCollectionInfo, + ) -> PropertyWriter<'a, Self, T, Handle> where Handle: CommonCollectionOperations + Deref>, - FIsAdmin: FnOnce() -> bool, - FPropertyPermissions: FnOnce() -> PropertiesPermissionMap, { PropertyWriter { collection, @@ -2663,10 +2643,7 @@ pub fn load_collection_info( collection_handle: &Handle, sender: &T::CrossAccountId, - ) -> PropertyWriterLazyCollectionInfo< - impl FnOnce() -> bool, - impl FnOnce() -> PropertiesPermissionMap, - > + ) -> PropertyWriterLazyCollectionInfo<'static> where Handle: Deref>, { @@ -2683,11 +2660,7 @@ pub fn load_token_properties( collection: &Handle, token_id: TokenId, - ) -> PropertyWriterLazyTokenInfo< - impl FnOnce() -> bool, - impl FnOnce() -> Result, - impl FnOnce() -> TokenProperties, - > + ) -> PropertyWriterLazyTokenInfo where Handle: CommonCollectionOperations, { @@ -2704,13 +2677,10 @@ } #[cfg(feature = "runtime-benchmarks")] -impl<'a, T, Handle, FIsAdmin, FPropertyPermissions> - PropertyWriter<'a, BenchmarkPropertyWriter, T, Handle, FIsAdmin, FPropertyPermissions> +impl<'a, T, Handle> PropertyWriter<'a, BenchmarkPropertyWriter, T, Handle> where T: Config, Handle: CommonCollectionOperations + Deref>, - FIsAdmin: FnOnce() -> bool, - FPropertyPermissions: FnOnce() -> PropertiesPermissionMap, { /// A function to benchmark the writing of token properties. pub fn write_token_properties( @@ -2826,20 +2796,14 @@ /* 15*/ TestCase::new(1, 1, 1, 1, 0), ]; - pub fn check_token_permissions( + pub fn check_token_permissions( collection_admin_permitted: bool, token_owner_permitted: bool, - is_collection_admin: &mut LazyValue, - check_token_ownership: &mut LazyValue, FTO>, - check_token_existence: &mut LazyValue, - ) -> DispatchResult - where - T: Config, - FCA: FnOnce() -> bool, - FTO: FnOnce() -> Result, - FTE: FnOnce() -> bool, - { - crate::check_token_permissions::( + is_collection_admin: &mut LazyValue, + check_token_ownership: &mut LazyValue>, + check_token_existence: &mut LazyValue, + ) -> DispatchResult { + crate::check_token_permissions::( collection_admin_permitted, token_owner_permitted, is_collection_admin, -- gitstuff