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>);