referrerpolicy=no-referrer-when-downgrade

pallet_assets/
extra_mutator.rs

1// This file is part of Substrate.
2
3// Copyright (C) Parity Technologies (UK) Ltd.
4// SPDX-License-Identifier: Apache-2.0
5
6// Licensed under the Apache License, Version 2.0 (the "License");
7// you may not use this file except in compliance with the License.
8// You may obtain a copy of the License at
9//
10// 	http://www.apache.org/licenses/LICENSE-2.0
11//
12// Unless required by applicable law or agreed to in writing, software
13// distributed under the License is distributed on an "AS IS" BASIS,
14// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15// See the License for the specific language governing permissions and
16// limitations under the License.
17
18//! Datatype for easy mutation of the extra "sidecar" data.
19
20use super::*;
21
22/// A mutator type allowing inspection and possible modification of the extra "sidecar" data.
23///
24/// This may be used as a `Deref` for the pallet's extra data. If mutated (using `DerefMut`), then
25/// any uncommitted changes (see `commit` function) will be automatically committed to storage when
26/// dropped. Changes, even after committed, may be reverted to their original values with the
27/// `revert` function.
28pub struct ExtraMutator<T: Config<I>, I: 'static = ()> {
29	id: T::AssetId,
30	who: T::AccountId,
31	original: T::Extra,
32	pending: Option<T::Extra>,
33}
34
35impl<T: Config<I>, I: 'static> Drop for ExtraMutator<T, I> {
36	fn drop(&mut self) {
37		debug_assert!(self.commit().is_ok(), "attempt to write to non-existent asset account");
38	}
39}
40
41impl<T: Config<I>, I: 'static> core::ops::Deref for ExtraMutator<T, I> {
42	type Target = T::Extra;
43	fn deref(&self) -> &T::Extra {
44		match self.pending {
45			Some(ref value) => value,
46			None => &self.original,
47		}
48	}
49}
50
51impl<T: Config<I>, I: 'static> core::ops::DerefMut for ExtraMutator<T, I> {
52	fn deref_mut(&mut self) -> &mut T::Extra {
53		if self.pending.is_none() {
54			self.pending = Some(self.original.clone());
55		}
56		self.pending.as_mut().unwrap()
57	}
58}
59
60impl<T: Config<I>, I: 'static> ExtraMutator<T, I> {
61	pub(super) fn maybe_new(
62		id: T::AssetId,
63		who: impl core::borrow::Borrow<T::AccountId>,
64	) -> Option<ExtraMutator<T, I>> {
65		if let Some(a) = Account::<T, I>::get(&id, who.borrow()) {
66			Some(ExtraMutator::<T, I> {
67				id,
68				who: who.borrow().clone(),
69				original: a.extra,
70				pending: None,
71			})
72		} else {
73			None
74		}
75	}
76
77	/// Commit any changes to storage.
78	pub fn commit(&mut self) -> Result<(), ()> {
79		if let Some(extra) = self.pending.take() {
80			Account::<T, I>::try_mutate(&self.id, &self.who, |maybe_account| {
81				maybe_account.as_mut().ok_or(()).map(|account| account.extra = extra)
82			})
83		} else {
84			Ok(())
85		}
86	}
87
88	/// Revert any changes, even those already committed by `self` and drop self.
89	pub fn revert(mut self) -> Result<(), ()> {
90		self.pending = None;
91		Account::<T, I>::try_mutate(&self.id, &self.who, |maybe_account| {
92			maybe_account
93				.as_mut()
94				.ok_or(())
95				.map(|account| account.extra = self.original.clone())
96		})
97	}
98}