difftreelog
refactor LazyValue without generic Fn
in: master
1 file changed
pallets/common/src/lib.rsdiffbeforeafterboth53#![cfg_attr(not(feature = "std"), no_std)]53#![cfg_attr(not(feature = "std"), no_std)]54extern crate alloc;54extern crate alloc;555556use alloc::boxed::Box;56use core::{57use core::{57 marker::PhantomData,58 marker::PhantomData,58 ops::{Deref, DerefMut},59 ops::{Deref, DerefMut},59 slice::from_ref,60 slice::from_ref,61 unreachable,60};62};616362use evm_coder::ToLog;64use evm_coder::ToLog;871 >;873 >;872}874}875876enum LazyValueState<'a, T> {877 Pending(Box<dyn FnOnce() -> T + 'a>),878 InProgress(PhantomData<sp_std::cell::Cell<T>>),879 Computed(T),880}873881874/// Value representation with delayed initialization time.882/// Value representation with delayed initialization time.875pub struct LazyValue<T, F> {883pub struct LazyValue<'a, T> {876 value: Option<T>,884 state: LazyValueState<'a, T>,877 f: Option<F>,878}885}879886880impl<T, F: FnOnce() -> T> LazyValue<T, F> {887impl<'a, T> LazyValue<'a, T> {881 /// Create a new LazyValue.888 /// Create a new LazyValue.882 pub fn new(f: F) -> Self {889 pub fn new(f: impl FnOnce() -> T + 'a) -> Self {883 Self {890 Self {884 value: None,885 f: Some(f),891 state: LazyValueState::Pending(Box::new(f)),886 }892 }887 }893 }888894889 /// Get the value. If it is called the first time, the value will be initialized.895 /// Get the value. If it is called the first time, the value will be initialized.890 pub fn value(&mut self) -> &T {896 pub fn value(&mut self) -> &T {891 self.force_value();897 self.force_value();892 self.value.as_ref().unwrap()898 self.value_mut()893 }899 }894900895 /// Get the value. If it is called the first time, the value will be initialized.901 /// Get the value. If it is called the first time, the value will be initialized.896 pub fn value_mut(&mut self) -> &mut T {902 pub fn value_mut(&mut self) -> &mut T {897 self.force_value();903 self.force_value();904898 self.value.as_mut().unwrap()905 if let LazyValueState::Computed(value) = &mut self.state {906 value907 } else {908 unreachable!()909 }899 }910 }900911901 fn into_inner(mut self) -> T {912 fn into_inner(mut self) -> T {902 self.force_value();913 self.force_value();903 self.value.unwrap()914 if let LazyValueState::Computed(value) = self.state {915 value916 } else {917 unreachable!()918 }904 }919 }905920906 /// Is value initialized?921 /// Is value initialized?907 pub fn has_value(&self) -> bool {922 pub fn has_value(&self) -> bool {908 self.value.is_some()923 matches!(self.state, LazyValueState::Computed(_))909 }924 }910925911 fn force_value(&mut self) {926 fn force_value(&mut self) {927 use LazyValueState::*;928912 if self.value.is_none() {929 if self.has_value() {930 return;931 }932933 match sp_std::mem::replace(&mut self.state, InProgress(PhantomData)) {913 self.value = Some(self.f.take().unwrap()())934 Pending(f) => self.state = Computed(f()),935 _ => {936 // Computed is ruled out by the above condition937 // InProgress is ruled out by not implementing Sync and absence of recursion938 unreachable!()939 }914 }940 }915 }941 }916}942}917943918fn check_token_permissions<T, FCA, FTO, FTE>(944fn check_token_permissions<T: Config>(919 collection_admin_permitted: bool,945 collection_admin_permitted: bool,920 token_owner_permitted: bool,946 token_owner_permitted: bool,921 is_collection_admin: &mut LazyValue<bool, FCA>,947 is_collection_admin: &mut LazyValue<bool>,922 is_token_owner: &mut LazyValue<Result<bool, DispatchError>, FTO>,948 is_token_owner: &mut LazyValue<Result<bool, DispatchError>>,923 is_token_exist: &mut LazyValue<bool, FTE>,949 is_token_exist: &mut LazyValue<bool>,924) -> DispatchResult950) -> DispatchResult {925where926 T: Config,927 FCA: FnOnce() -> bool,928 FTO: FnOnce() -> Result<bool, DispatchError>,929 FTE: FnOnce() -> bool,930{931 if !(collection_admin_permitted && *is_collection_admin.value()951 if !(collection_admin_permitted && *is_collection_admin.value()932 || token_owner_permitted && (*is_token_owner.value())?)952 || token_owner_permitted && (*is_token_owner.value())?)2346/// This type utilizes the lazy evaluation to avoid repeating the computation2366/// This type utilizes the lazy evaluation to avoid repeating the computation2347/// of several performance-heavy or PoV-heavy tasks,2367/// of several performance-heavy or PoV-heavy tasks,2348/// such as checking the indirect ownership or reading the token property permissions.2368/// such as checking the indirect ownership or reading the token property permissions.2349pub struct PropertyWriter<'a, WriterVariant, T, Handle, FIsAdmin, FPropertyPermissions> {2369pub struct PropertyWriter<'a, WriterVariant, T, Handle> {2350 collection: &'a Handle,2370 collection: &'a Handle,2351 collection_lazy_info: PropertyWriterLazyCollectionInfo<FIsAdmin, FPropertyPermissions>,2371 collection_lazy_info: PropertyWriterLazyCollectionInfo<'a>,2352 _phantom: PhantomData<(T, WriterVariant)>,2372 _phantom: PhantomData<(T, WriterVariant)>,2353}2373}235423742355impl<'a, T, Handle, WriterVariant, FIsAdmin, FPropertyPermissions>2375impl<'a, T, Handle, WriterVariant> PropertyWriter<'a, WriterVariant, T, Handle>2356 PropertyWriter<'a, WriterVariant, T, Handle, FIsAdmin, FPropertyPermissions>2357where2376where2358 T: Config,2377 T: Config,2359 Handle: CommonCollectionOperations<T> + Deref<Target = CollectionHandle<T>>,2378 Handle: CommonCollectionOperations<T> + Deref<Target = CollectionHandle<T>>,2360 FIsAdmin: FnOnce() -> bool,2361 FPropertyPermissions: FnOnce() -> PropertiesPermissionMap,2362{2379{2363 fn internal_write_token_properties<FCheckTokenExist, FCheckTokenOwner, FGetProperties>(2380 fn internal_write_token_properties(2364 &mut self,2381 &mut self,2365 token_id: TokenId,2382 token_id: TokenId,2366 mut token_lazy_info: PropertyWriterLazyTokenInfo<2383 mut token_lazy_info: PropertyWriterLazyTokenInfo,2367 FCheckTokenExist,2368 FCheckTokenOwner,2369 FGetProperties,2370 >,2371 properties_updates: impl Iterator<Item = (PropertyKey, Option<PropertyValue>)>,2384 properties_updates: impl Iterator<Item = (PropertyKey, Option<PropertyValue>)>,2372 log: evm_coder::ethereum::Log,2385 log: evm_coder::ethereum::Log,2373 ) -> DispatchResult2386 ) -> DispatchResult {2374 where2375 FCheckTokenExist: FnOnce() -> bool,2376 FCheckTokenOwner: FnOnce() -> Result<bool, DispatchError>,2377 FGetProperties: FnOnce() -> TokenProperties,2378 {2379 for (key, value) in properties_updates {2387 for (key, value) in properties_updates {2380 let permission = self2388 let permission = self2400 collection_admin,2408 collection_admin,2401 token_owner,2409 token_owner,2402 ..2410 ..2403 } => check_token_permissions::<T, _, _, _>(2411 } => check_token_permissions::<T>(2404 collection_admin,2412 collection_admin,2405 token_owner,2413 token_owner,2406 &mut self.collection_lazy_info.is_collection_admin,2414 &mut self.collection_lazy_info.is_collection_admin,2454/// A helper structure for the [`PropertyWriter`] that holds2462/// A helper structure for the [`PropertyWriter`] that holds2455/// the collection-related info. The info is loaded using lazy evaluation.2463/// the collection-related info. The info is loaded using lazy evaluation.2456/// This info is common for any token for which we write properties.2464/// This info is common for any token for which we write properties.2457pub struct PropertyWriterLazyCollectionInfo<FIsAdmin, FPropertyPermissions> {2465pub struct PropertyWriterLazyCollectionInfo<'a> {2458 is_collection_admin: LazyValue<bool, FIsAdmin>,2466 is_collection_admin: LazyValue<'a, bool>,2459 property_permissions: LazyValue<PropertiesPermissionMap, FPropertyPermissions>,2467 property_permissions: LazyValue<'a, PropertiesPermissionMap>,2460}2468}246124692462/// A helper structure for the [`PropertyWriter`] that holds2470/// A helper structure for the [`PropertyWriter`] that holds2463/// the token-related info. The info is loaded using lazy evaluation.2471/// the token-related info. The info is loaded using lazy evaluation.2464pub struct PropertyWriterLazyTokenInfo<FCheckTokenExist, FCheckTokenOwner, FGetProperties> {2472pub struct PropertyWriterLazyTokenInfo<'a> {2465 is_token_exist: LazyValue<bool, FCheckTokenExist>,2473 is_token_exist: LazyValue<'a, bool>,2466 is_token_owner: LazyValue<Result<bool, DispatchError>, FCheckTokenOwner>,2474 is_token_owner: LazyValue<'a, Result<bool, DispatchError>>,2467 stored_properties: LazyValue<TokenProperties, FGetProperties>,2475 stored_properties: LazyValue<'a, TokenProperties>,2468}2476}246924772470impl<FCheckTokenExist, FCheckTokenOwner, FGetProperties>2478impl<'a> PropertyWriterLazyTokenInfo<'a> {2471 PropertyWriterLazyTokenInfo<FCheckTokenExist, FCheckTokenOwner, FGetProperties>2472where2473 FCheckTokenExist: FnOnce() -> bool,2474 FCheckTokenOwner: FnOnce() -> Result<bool, DispatchError>,2475 FGetProperties: FnOnce() -> TokenProperties,2476{2477 /// Create a lazy token info.2479 /// Create a lazy token info.2478 pub fn new(2480 pub fn new(2479 check_token_exist: FCheckTokenExist,2481 check_token_exist: impl FnOnce() -> bool + 'a,2480 check_token_owner: FCheckTokenOwner,2482 check_token_owner: impl FnOnce() -> Result<bool, DispatchError> + 'a,2481 get_token_properties: FGetProperties,2483 get_token_properties: impl FnOnce() -> TokenProperties + 'a,2482 ) -> Self {2484 ) -> Self {2483 Self {2485 Self {2484 is_token_exist: LazyValue::new(check_token_exist),2486 is_token_exist: LazyValue::new(check_token_exist),2500 'a,2501 Self,2502 T,2503 Handle,2504 impl FnOnce() -> bool + 'a,2505 impl FnOnce() -> PropertiesPermissionMap + 'a,2506 >2507 where2502 where2508 T: Config,2503 T: Config,2521 }2516 }2522}2517}252325182524impl<'a, T, Handle, FIsAdmin, FPropertyPermissions>2519impl<'a, T, Handle> PropertyWriter<'a, NewTokenPropertyWriter<T>, T, Handle>2525 PropertyWriter<'a, NewTokenPropertyWriter<T>, T, Handle, FIsAdmin, FPropertyPermissions>2526where2520where2527 T: Config,2521 T: Config,2528 Handle: CommonCollectionOperations<T> + Deref<Target = CollectionHandle<T>>,2522 Handle: CommonCollectionOperations<T> + Deref<Target = CollectionHandle<T>>,2529 FIsAdmin: FnOnce() -> bool,2530 FPropertyPermissions: FnOnce() -> PropertiesPermissionMap,2531{2523{2532 /// A function to write properties to a **newly created** token.2524 /// A function to write properties to a **newly created** token.2533 pub fn write_token_properties(2525 pub fn write_token_properties(2574 'a,2575 Self,2576 T,2577 Handle,2578 impl FnOnce() -> bool + 'a,2579 impl FnOnce() -> PropertiesPermissionMap + 'a,2580 >2581 where2566 where2582 Handle: CommonCollectionOperations<T> + Deref<Target = CollectionHandle<T>>,2567 Handle: CommonCollectionOperations<T> + Deref<Target = CollectionHandle<T>>,2594 }2579 }2595}2580}259625812597impl<'a, T, Handle, FIsAdmin, FPropertyPermissions>2582impl<'a, T, Handle> PropertyWriter<'a, ExistingTokenPropertyWriter<T>, T, Handle>2598 PropertyWriter<'a, ExistingTokenPropertyWriter<T>, T, Handle, FIsAdmin, FPropertyPermissions>2599where2583where2600 T: Config,2584 T: Config,2601 Handle: CommonCollectionOperations<T> + Deref<Target = CollectionHandle<T>>,2585 Handle: CommonCollectionOperations<T> + Deref<Target = CollectionHandle<T>>,2602 FIsAdmin: FnOnce() -> bool,2603 FPropertyPermissions: FnOnce() -> PropertiesPermissionMap,2604{2586{2605 /// A function to write properties to an **already existing** token.2587 /// A function to write properties to an **already existing** token.2606 pub fn write_token_properties(2588 pub fn write_token_properties(2643#[cfg(feature = "runtime-benchmarks")]2625#[cfg(feature = "runtime-benchmarks")]2644impl<T: Config> BenchmarkPropertyWriter<T> {2626impl<T: Config> BenchmarkPropertyWriter<T> {2645 /// Creates a [`PropertyWriter`] for benchmarking tokens properties writing.2627 /// Creates a [`PropertyWriter`] for benchmarking tokens properties writing.2646 pub fn new<'a, Handle, FIsAdmin, FPropertyPermissions>(2628 pub fn new<'a, Handle>(2647 collection: &Handle,2629 collection: &Handle,2648 collection_lazy_info: PropertyWriterLazyCollectionInfo<FIsAdmin, FPropertyPermissions>,2630 collection_lazy_info: PropertyWriterLazyCollectionInfo,2649 ) -> PropertyWriter<Self, T, Handle, FIsAdmin, FPropertyPermissions>2631 ) -> PropertyWriter<'a, Self, T, Handle>2650 where2632 where2651 Handle: CommonCollectionOperations<T> + Deref<Target = CollectionHandle<T>>,2633 Handle: CommonCollectionOperations<T> + Deref<Target = CollectionHandle<T>>,2652 FIsAdmin: FnOnce() -> bool,2653 FPropertyPermissions: FnOnce() -> PropertiesPermissionMap,2654 {2634 {2655 PropertyWriter {2635 PropertyWriter {2656 collection,2636 collection,2663 pub fn load_collection_info<Handle>(2643 pub fn load_collection_info<Handle>(2664 collection_handle: &Handle,2644 collection_handle: &Handle,2665 sender: &T::CrossAccountId,2645 sender: &T::CrossAccountId,2666 ) -> PropertyWriterLazyCollectionInfo<2646 ) -> PropertyWriterLazyCollectionInfo<'static>2667 impl FnOnce() -> bool,2668 impl FnOnce() -> PropertiesPermissionMap,2669 >2670 where2647 where2671 Handle: Deref<Target = CollectionHandle<T>>,2648 Handle: Deref<Target = CollectionHandle<T>>,2683 pub fn load_token_properties<Handle>(2660 pub fn load_token_properties<Handle>(2684 collection: &Handle,2661 collection: &Handle,2685 token_id: TokenId,2662 token_id: TokenId,2686 ) -> PropertyWriterLazyTokenInfo<2663 ) -> PropertyWriterLazyTokenInfo2687 impl FnOnce() -> bool,2688 impl FnOnce() -> Result<bool, DispatchError>,2689 impl FnOnce() -> TokenProperties,2690 >2691 where2664 where2692 Handle: CommonCollectionOperations<T>,2665 Handle: CommonCollectionOperations<T>,2693 {2666 {2704}2677}270526782706#[cfg(feature = "runtime-benchmarks")]2679#[cfg(feature = "runtime-benchmarks")]2707impl<'a, T, Handle, FIsAdmin, FPropertyPermissions>2680impl<'a, T, Handle> PropertyWriter<'a, BenchmarkPropertyWriter<T>, T, Handle>2708 PropertyWriter<'a, BenchmarkPropertyWriter<T>, T, Handle, FIsAdmin, FPropertyPermissions>2709where2681where2710 T: Config,2682 T: Config,2711 Handle: CommonCollectionOperations<T> + Deref<Target = CollectionHandle<T>>,2683 Handle: CommonCollectionOperations<T> + Deref<Target = CollectionHandle<T>>,2712 FIsAdmin: FnOnce() -> bool,2713 FPropertyPermissions: FnOnce() -> PropertiesPermissionMap,2714{2684{2715 /// A function to benchmark the writing of token properties.2685 /// A function to benchmark the writing of token properties.2716 pub fn write_token_properties(2686 pub fn write_token_properties(2826 /* 15*/ TestCase::new(1, 1, 1, 1, 0),2796 /* 15*/ TestCase::new(1, 1, 1, 1, 0),2827 ];2797 ];282827982829 pub fn check_token_permissions<T, FCA, FTO, FTE>(2799 pub fn check_token_permissions<T: Config>(2830 collection_admin_permitted: bool,2800 collection_admin_permitted: bool,2831 token_owner_permitted: bool,2801 token_owner_permitted: bool,2832 is_collection_admin: &mut LazyValue<bool, FCA>,2802 is_collection_admin: &mut LazyValue<bool>,2833 check_token_ownership: &mut LazyValue<Result<bool, DispatchError>, FTO>,2803 check_token_ownership: &mut LazyValue<Result<bool, DispatchError>>,2834 check_token_existence: &mut LazyValue<bool, FTE>,2804 check_token_existence: &mut LazyValue<bool>,2835 ) -> DispatchResult2805 ) -> DispatchResult {2836 where2837 T: Config,2838 FCA: FnOnce() -> bool,2839 FTO: FnOnce() -> Result<bool, DispatchError>,2840 FTE: FnOnce() -> bool,2841 {2842 crate::check_token_permissions::<T, FCA, FTO, FTE>(2806 crate::check_token_permissions::<T>(2843 collection_admin_permitted,2807 collection_admin_permitted,2844 token_owner_permitted,2808 token_owner_permitted,2845 is_collection_admin,2809 is_collection_admin,