frame_suite/misc.rs
1// SPDX-License-Identifier: MPL-2.0
2//
3// Part of Auguth Labs open-source softwares.
4// Built for the Substrate framework.
5//
6// This Source Code Form is subject to the terms of the Mozilla Public
7// License, v. 2.0. If a copy of the MPL was not distributed with this
8// file, You can obtain one at https://mozilla.org/MPL/2.0/.
9//
10// Copyright (c) 2026 Auguth Labs (OPC) Pvt Ltd, India
11
12// ===============================================================================
13// ```````````````````````````````` MISCELLANEOUS ````````````````````````````````
14// ===============================================================================
15
16//! Provides small, reusable building blocks that are broadly applicable
17//! across pallets and runtime components.
18
19// ===============================================================================
20// ``````````````````````````````````` IMPORTS ```````````````````````````````````
21// ===============================================================================
22
23// --- Local crate imports ---
24use crate::{Probe, virtuals::DiscriminantTag};
25
26// --- Core ---
27use core::{fmt::Debug, marker::PhantomData};
28
29// --- SCALE & metadata ---
30use codec::{Decode, DecodeWithMemTracking, Encode, MaxEncodedLen};
31use scale_info::TypeInfo;
32
33// --- Frame Support ---
34use frame_support::traits::{
35 tokens::{Fortitude, Precision},
36 VariantCount,
37};
38
39// --- Substrate Primitives ---
40use sp_runtime::{traits::Zero, Vec};
41use sp_core::blake2_256;
42
43// ===============================================================================
44// ```````````````````````````````````` TRAITS ```````````````````````````````````
45// ===============================================================================
46
47/// A trait for deriving values across different extents within a bounded space.
48///
49/// This trait is domain-agnostic and provides a unified interface to compute
50/// values at the lower bound, upper bound, and an optimal point under given conditions.
51///
52/// ## Methods:
53/// - `minimum`: Returns the lowest permissible or derived value.
54/// - `maximum`: Returns the highest permissible or derived value.
55/// - `optimal`: Returns the most suitable or preferred value within bounds.
56///
57/// ## Usage Scenarios:
58/// - **Constraint systems**: Determining valid lower and upper limits.
59/// - **Optimization problems**: Selecting a balanced or ideal value.
60/// - **Rate limiting**: Bounding operations within safe thresholds.
61/// - **Resource allocation**: Computing safe vs optimal utilization.
62/// - **Financial systems**: Sizing deposits, mints, or adjustments.
63///
64/// ## Design Notes:
65/// - Fully abstract and reusable across domains.
66/// - Each method is independent and may be computed lazily.
67/// - Implementations may choose to derive values from shared logic.
68///
69/// ## Default Discriminant
70///
71/// - `Discriminant = ()`: defines a single default extent,
72/// meaning one unique set of bounds/derivations is assumed.
73pub trait Extent<Discriminant: DiscriminantTag = ()> {
74 /// The scalar representing the bounded value.
75 type Scalar: PartialOrd + Copy;
76
77 /// Returns the minimum value under given conditions.
78 fn minimum(&self) -> Option<Self::Scalar>;
79
80 /// Returns the maximum value under given conditions.
81 fn maximum(&self) -> Option<Self::Scalar>;
82
83 /// Returns the optimal value under given conditions.
84 fn optimal(&self) -> Option<Self::Scalar>;
85
86 /// Returns an unbounded extent.
87 ///
88 /// This represents the absence of any constraints, where:
89 /// - [`Self::minimum`] returns `None`
90 /// - [`Self::maximum`] returns `None`
91 /// - [`Self::optimal`] returns `None`
92 ///
93 /// Useful as a neutral/default extent when no bounds are required.
94 fn none() -> Self;
95
96 /// Checks whether the given value lies within the extent's bounds.
97 ///
98 /// Returns `true` if:
99 /// - The value is greater than or equal to [`Self::minimum`] (if available), and
100 /// - The value is less than or equal to [`Self::maximum`] (if available).
101 ///
102 /// Missing bounds (`None`) are treated as unbounded in that direction.
103 ///
104 /// This method performs a simple range check and does not enforce
105 /// optimality or other domain-specific constraints.
106 fn contains(&self, value: Self::Scalar) -> bool {
107 if let Some(min) = self.minimum() {
108 if value < min {
109 return false;
110 }
111 }
112
113 if let Some(max) = self.maximum() {
114 if value > max {
115 return false;
116 }
117 }
118
119 true
120 }
121}
122
123/// A trait expressing the execution directive of an operation.
124///
125/// `Directive` defines *how an action should be carried out*, independent of
126/// the value or state it operates on. It captures two orthogonal dimensions:
127///
128/// - [`Precision`]: The required exactness of the operation.
129/// - `Exact`: The operation must satisfy strict conditions.
130/// - `BestEffort`: The operation may proceed with relaxed or partial fulfillment.
131///
132/// - [`Fortitude`]: The strength or authority of execution.
133/// - `Polite`: The operation should respect constraints and may yield.
134/// - `Force`: The operation must be enforced regardless of resistance.
135///
136/// ## Interpretation
137///
138/// | Precision | Fortitude | Meaning |
139/// |---------------|-----------|----------------------------------|
140/// | BestEffort | Polite | Soft, optional attempt |
141/// | Exact | Polite | Strict but non-forcing |
142/// | BestEffort | Force | Enforced but flexible execution |
143/// | Exact | Force | Strict and mandatory execution |
144///
145/// ## Design Notes
146///
147/// - Encodes **intent**, not state or value
148/// - Fully domain-agnostic
149/// - Separates *what to do* from *how to do it*
150/// - Enables consistent execution behavior across systems
151///
152/// Implementations should ensure that `from_directive` produces a value whose
153/// behavior reflects the specified execution semantics.
154///
155/// ## Default Discriminant
156///
157/// - `Discriminant = ()`: defines a single default directive,
158/// meaning one unique set of directions is assumed.
159pub trait Directive<Discriminant: DiscriminantTag = ()>: Sized {
160 /// Returns the required precision of the operation.
161 fn precision(&self) -> Precision;
162
163 /// Returns the enforcement strength of the operation.
164 fn fortitude(&self) -> Fortitude;
165
166 /// Constructs a value from execution semantics.
167 ///
168 /// The resulting value should embody how the operation behaves
169 /// in terms of strictness and enforcement.
170 fn new(precision: Precision, fortitude: Fortitude) -> Self;
171}
172
173/// Maps semantic variants to zero-based position indices.
174///
175/// `VariantCount` is 1-based, while `PositionIndex` is 0-based. As a result,
176/// the maximum valid index is `VariantCount::VARIANT_COUNT - 1`.
177pub trait PositionIndex: VariantCount {
178 /// Returns the zero-based index for this variant, or `None` if the
179 /// variant must not participate in indexing.
180 fn index(&self) -> usize;
181
182 /// Returns the variant for the given zero-based index, or `None`
183 /// if the index is out of range or non-semantic.
184 fn position_of(index: usize) -> Option<Self>
185 where
186 Self: Sized;
187}
188
189/// Trivial implementation for marker type [`Ignore`], representing a
190/// single, non-variant position.
191impl PositionIndex for Ignore {
192 /// [`Ignore`] has exactly one semantic variant and always maps to index `0`.
193 fn index(&self) -> usize {
194 0
195 }
196
197 /// Returns the variant for index `0`; any non-zero index is invalid.
198 fn position_of(index: usize) -> Option<Self> {
199 if index.is_zero() {
200 return Some(Ignore(PhantomData));
201 }
202 None
203 }
204}
205
206impl VariantCount for Ignore {
207 /// [`Ignore`] defines a single semantic variant.
208 const VARIANT_COUNT: u32 = 1;
209}
210
211/// A trait for structures that grow by preserving previous state
212/// while creating fresh local generations.
213///
214/// `Accrete` stores and propagates deterministic item keys,
215/// not the full item payload itself.
216///
217/// The actual payload may live elsewhere (for example:
218/// `key -> value` storage), while this structure tracks only
219/// membership and historical propagation of stable keys.
220///
221/// Calling `accrete()` creates a new generation where:
222///
223/// - current local item keys are promoted into inherited history
224/// - the returned value begins with fresh local state
225///
226/// Example flow:
227///
228/// | Generation | Inherited | Local |
229/// |------------|------------------|----------|
230/// | A | `[]` | `[a, b]` |
231/// | B | `[a, b]` | `[]` |
232/// | B | `[a, b]` | `[c, d]` |
233/// | C | `[a, b, c, d]` | `[]` |
234///
235/// where `a`, `b`, `c`, and `d` represent deterministic
236/// item key hashes (`[u8; 32]`), not full values.
237///
238/// This allows persistent, layered growth where older generations
239/// remain preserved while new values are added independently.
240///
241/// ## Note
242///
243/// Always prefer working with the most recent generation, since it
244/// contains the complete inherited state of all previous generations.
245///
246/// Older generations may be retained for history, snapshots, or audit
247/// purposes, but they should not be used for active logic without first
248/// consulting the latest generation to confirm whether that state still
249/// exists, has changed, or has been removed.
250pub trait Accrete: Clone {
251 /// The payload type used to derive deterministic keys.
252 ///
253 /// The payload itself is not stored inside the accreted structure.
254 /// Only its stable deterministic key hash is tracked.
255 type Item: Probe;
256
257 /// Creates a deterministic key for an item.
258 ///
259 /// This key is what gets stored, inherited, and removed
260 /// across generations.
261 ///
262 /// This should be stable across executions so the same item
263 /// always resolves to the same key.
264 ///
265 /// Typical implementations use:
266 ///
267 /// - SCALE encoding + hash (`blake2_256`)
268 /// - canonical identifiers
269 /// - domain-specific unique references
270 fn make_key(
271 item: &Self::Item,
272 ) -> [u8; 32] {
273 blake2_256(&item.encode())
274 }
275
276 /// Creates the next generation from the current instance.
277 ///
278 /// The current local key set becomes inherited history,
279 /// and the returned value starts a fresh local generation.
280 fn accrete(&self) -> Self;
281
282 /// Returns keys inherited from previous generations.
283 fn inherited(&self) -> Vec<[u8; 32]>;
284
285 /// Returns keys belonging only to the current generation.
286 fn local(&self) -> Vec<[u8; 32]>;
287
288 /// Inserts an item's deterministic key into the current
289 /// local generation.
290 ///
291 /// Returns the stable key used for future reference.
292 fn add_to_local(
293 &mut self,
294 item: Self::Item,
295 ) -> [u8; 32];
296
297 /// Returns `true` if the given key exists in the current
298 /// local generation only.
299 fn exists_in_local(
300 &self,
301 key: &[u8; 32],
302 ) -> bool;
303
304 /// Returns `true` if the given key exists in inherited
305 /// generations only.
306 fn exists_in_inherited(
307 &self,
308 key: &[u8; 32],
309 ) -> bool;
310
311 /// Removes a key from the current local generation.
312 fn remove_from_local(
313 &mut self,
314 key: &[u8; 32],
315 );
316
317 /// Removes a key from inherited generations.
318 ///
319 /// This should be used carefully since inherited state
320 /// affects descendant visibility.
321 fn remove_from_inherited(
322 &mut self,
323 key: &[u8; 32],
324 );
325}
326
327// ===============================================================================
328// ```````````````````````````````````` ENUMS ````````````````````````````````````
329// ===============================================================================
330
331/// A tri-state enum representing a generic disposition or stance.
332///
333/// This enum is designed to be domain-agnostic, enabling its use in a variety of contexts
334/// such as decision making, status tracking, access control, and governance logic.
335///
336/// #### Variants:
337/// - `Affirmative`: Represents a positive/agreeing/approved state.
338/// - `Contrary`: Represents a negative/disagreeing/rejected state.
339/// - `Awaiting`: Represents an undecided, pending, or inactive state.
340///
341/// #### Usage Scenarios:
342/// - **Governance/voting**: To track votes (Yes/No/Pending).
343/// - **Authorization**: Representing access status (Granted/Denied/Unverified).
344/// - **Workflow/state machines**: To mark stages such as completed, failed, or pending.
345/// - **Consensus/validation**: To model block author responses.
346/// - **General application logic**: Anywhere a compact, expressive tri-state is useful.
347#[derive(
348 Encode,
349 Decode,
350 Clone,
351 Copy,
352 PartialEq,
353 Eq,
354 MaxEncodedLen,
355 TypeInfo,
356 DecodeWithMemTracking,
357 Default,
358 Debug,
359)]
360pub enum Disposition {
361 /// Represents an affirmative (positive/agreeing) disposition.
362 #[default]
363 Affirmative,
364 /// Represents a contrary (negative/disagreeing) disposition.
365 Contrary,
366 /// Represents a disposition that is undecided or still pending.
367 Awaiting,
368}
369
370impl PositionIndex for Disposition {
371 fn index(&self) -> usize {
372 match self {
373 Disposition::Affirmative => 0,
374 Disposition::Contrary => 1,
375 Disposition::Awaiting => 2,
376 }
377 }
378
379 fn position_of(index: usize) -> Option<Self> {
380 match index {
381 0 => Some(Disposition::Affirmative),
382 1 => Some(Disposition::Contrary),
383 2 => Some(Disposition::Awaiting),
384 _ => None,
385 }
386 }
387}
388
389impl VariantCount for Disposition {
390 const VARIANT_COUNT: u32 = 3;
391}
392
393/// A generic enum representing the polarity or nature of an entity.
394///
395/// This enum captures whether something is fundamentally constructive, destructive,
396/// a mix of both, or undefined. It is abstract and domain-independent, making it suitable
397/// for systems that involve influence, intent, or behavioral modeling.
398///
399/// #### Variants:
400/// - `Constructive`: Positive or generative in nature.
401/// - `Destructive`: Negative or harmful in nature.
402/// - `Composite`: Contains both constructive and destructive traits.
403/// - `Indeterminate`: Polarity is undefined, neutral, or undecided.
404///
405/// #### Use Cases:
406/// - **Reputation systems**: To classify behavior or actions.
407/// - **Governance models**: To evaluate the polarity of proposals or arguments.
408/// - **Content moderation**: Tagging interactions or submissions by nature.
409/// - **Feedback analysis**: To assess sentiment or system feedback.
410///
411/// #### Relation to [`Disposition`]:
412/// Often used **similar to `Disposition`** to provide richer semantic meaning:
413/// - `Disposition` indicates the **stance** (affirmative, contrary, awaiting).
414/// - `Polarity` indicates the **nature or impact** (constructive, destructive, etc.).
415///
416#[derive(Encode, Decode, Clone, PartialEq, Eq, MaxEncodedLen, TypeInfo, Debug, Default)]
417pub enum Polarity {
418 /// Represents a positive, generative, or beneficial nature.
419 #[default]
420 Constructive,
421 /// Represents a negative, harmful, or destructive nature.
422 Destructive,
423 /// Represents a mix of both constructive and destructive traits.
424 Composite,
425 /// Represents an undefined, neutral, or undecided polarity.
426 Indeterminate,
427}
428
429impl VariantCount for Polarity {
430 const VARIANT_COUNT: u32 = 4;
431}
432
433impl PositionIndex for Polarity {
434 fn index(&self) -> usize {
435 match self {
436 Polarity::Constructive => 0,
437 Polarity::Destructive => 1,
438 Polarity::Composite => 2,
439 Polarity::Indeterminate => 3,
440 }
441 }
442
443 fn position_of(index: usize) -> Option<Self> {
444 match index {
445 0 => Some(Polarity::Constructive),
446 1 => Some(Polarity::Destructive),
447 2 => Some(Polarity::Composite),
448 3 => Some(Polarity::Indeterminate),
449 _ => None,
450 }
451 }
452}
453
454// ===============================================================================
455// ``````````````````````````````````` STRUCTS ```````````````````````````````````
456// ===============================================================================
457
458/// No-op generic marker type used in place of `()` when a generic
459/// parameter needs to be carried.
460///
461/// While `()` is commonly used as a default no-op type in Rust,
462/// it cannot expose or propagate generic parameters. `Ignore`
463/// provides a zero-sized alternative that preserves generic context
464/// without introducing behavior.
465///
466/// ## Purpose
467///
468/// - Acts as a no-op / default implementor
469/// - Carries a generic type parameter `T`
470/// - Enables trait implementations that require associated types
471/// derived from a generic input
472///
473/// ## Usage
474///
475/// Used in generic abstractions where:
476/// - a placeholder type is required,
477/// - behavior is intentionally absent,
478/// - but type information must still flow through the system.
479///
480/// ## Example
481///
482/// ```ignore
483/// trait ProvidesType {
484/// type Item;
485/// }
486///
487/// // Cannot use `()` here because it cannot carry `T`
488/// impl<T> ProvidesType for Ignore<T> {
489/// type Item = T;
490/// }
491/// ```
492///
493/// This allows a no-op type to still propagate generic information.
494pub struct Ignore<T = ()>(pub PhantomData<T>);