Files
s390-tools/rust/pvimg/src/pv_utils/se_hdr/generic_flags.rs
Marc Hartmayer 177d8ae0dd pvimg: Get rid of most 'ignore' doctest directives
Signed-off-by: Marc Hartmayer <marc@linux.ibm.com>
Reviewed-by: Steffen Eiden <seiden@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
2026-07-31 09:51:14 +02:00

879 lines
26 KiB
Rust

// SPDX-License-Identifier: MIT
//
// Copyright IBM Corp.
//! Generic control flags infrastructure for Secure Execution (SE) headers.
//!
//! This module provides the generic, reusable components for managing control flags
//! in IBM Secure Execution headers. It defines traits, generic types, and implementations
//! that can work with any flag enum type.
//!
//! # Core Components
//!
//! ## Traits
//!
//! - [`ControlFlagTrait`] - Core trait that flag enums must implement
//! - [`IntoEnumIterator`] - Enables iteration over flag enum variants
//! - [`IntoBitPosition`] - Converts types to bit positions
//!
//! ## Generic Types
//!
//! - [`ControlFlagsModel<T>`] - Version-specific configuration model
//! - [`EffectiveControlFlags<T>`] - Final flags after applying overrides
//! - [`FlagsOverride<T>`] - Container for user-specified overrides
//! - [`FlagData<T>`] - Pairs a flag with its state
//! - [`UnknownFlags`] - Tracks unknown/unsupported flag bits
//!
//! ## Supporting Types
//!
//! - [`FlagState`] - Enabled or Disabled state
//! - [`FlagValidationError<T>`] - Validation errors
//! - [`Msb0FlagsConversionError<T>`] - Conversion errors
//!
//! # Usage
//!
//! This module is not typically used directly. Instead, use the concrete implementations
//! in the [`flags`](super::flags) module which provide `SeHdrFlag`, `SeHdrControlFlagsModel`,
//! and related types built on top of this generic infrastructure.
use std::collections::{HashMap, HashSet};
use std::fmt::{Debug, Display};
use std::hash::Hash;
use pv::misc::{Flags, Msb0Flags64};
use super::brb::SeHdrVersion;
#[derive(Debug)]
pub enum FlagValidationError<T: ControlFlagTrait> {
UnknownFlag(),
NotSupported { model: &'static str, flag: T },
}
impl<T: ControlFlagTrait> Display for FlagValidationError<T> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
FlagValidationError::UnknownFlag() => write!(f, "Unknown flag"),
FlagValidationError::NotSupported { model, flag } => {
write!(f, "Flag '{}' is not supported in {}", flag, model)
}
}
}
}
impl<T: ControlFlagTrait> std::error::Error for FlagValidationError<T> {}
/// Secure Execution target configuration.
///
/// Specifies the target environment for which a Secure Execution boot image is being created.
/// This enum allows selecting the appropriate control flags and configuration based on the
/// target machine generation or SE header version.
///
/// # Current Usage
///
/// Currently, this enum is primarily used for selecting control flags configurations.
/// The target determines which control flags are available and their default values.
///
/// # Purpose
///
/// The target determines:
/// - Which control flags are available and their default values
/// - The SE header format version to use
/// - Compatibility with specific machine generations (future use)
///
/// # Future Extensibility
///
/// This design allows for future expansion when multiple variants of V1 or V2 configurations
/// may exist.
///
/// # Examples
///
/// ```
/// use pvimg::uvdata::{SeHdrControlFlagsModel, SeTarget};
///
/// // Select latest V1 configuration for newest features
/// let target = SeTarget::V1Max;
///
/// // Use target to get appropriate control flags
/// let pcf = SeHdrControlFlagsModel::pcf_for_target(target);
/// ```
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
pub enum SeTarget {
/// Latest V1 configuration.
///
/// Targets the most recent V1 SE header format with all available V1 control flags.
/// Use this for maximum compatibility with older machine generations that support V1.
V1Max,
/// Latest V2 configuration.
///
/// Targets the most recent V2 SE header format with all available V2 control flags.
/// Use this for newest features and machine generations that support V2.
V2Max,
}
impl SeTarget {
/// Converts the target to the corresponding SeHdrVersion.
pub fn to_se_hdr_version(self) -> SeHdrVersion {
match self {
SeTarget::V1Max => SeHdrVersion::V1,
SeTarget::V2Max => SeHdrVersion::V2,
}
}
/// Creates a target from a SeHdrVersion.
pub fn from_se_hdr_version(version: SeHdrVersion) -> Self {
match version {
SeHdrVersion::V1 => SeTarget::V1Max,
SeHdrVersion::V2 => SeTarget::V2Max,
}
}
}
impl Display for SeTarget {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
SeTarget::V1Max => write!(f, "V1-max"),
SeTarget::V2Max => write!(f, "V2-max"),
}
}
}
pub trait IntoEnumIterator {
/// Returns an iterator over all variants of this enum.
fn iter() -> impl Iterator<Item = Self>;
}
/// Trait for individual control flag types.
///
/// This trait defines the interface for control flag enums, providing methods
/// to get the flag's bit position and create enabled/disabled flag data.
pub trait ControlFlagTrait:
Debug + Hash + Copy + Eq + Ord + Display + IntoEnumIterator + AsRef<Self>
{
/// Returns the bit position of this flag.
///
/// The bit position determines where this flag is set in the control flags bitfield.
fn bit_position(self) -> u8;
/// Creates flag data with this flag in the enabled state.
fn enabled(self) -> FlagData<Self> {
FlagData::new(self, FlagState::Enabled)
}
/// Creates flag data with this flag in the disabled state.
fn disabled(self) -> FlagData<Self> {
FlagData::new(self, FlagState::Disabled)
}
}
/// Internal state of a control flag (enabled or disabled).
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Copy)]
pub enum FlagState {
/// Flag is enabled (bit set to 1)
Enabled,
/// Flag is disabled (bit set to 0)
Disabled,
}
/// Represents a control flag with its associated state.
///
/// This structure pairs a flag with its enabled/disabled state, used when
/// constructing or modifying `ControlFlags` instances.
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone)]
pub struct FlagData<T: ControlFlagTrait> {
value: T,
state: FlagState,
}
impl<T: ControlFlagTrait> FlagData<T> {
const fn new(value: T, state: FlagState) -> Self {
Self { value, state }
}
}
/// Generic flags configuration for a specific SE header flags target.
///
/// Contains the default and supported flags for a given target version.
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct ControlFlagsModel<T: ControlFlagTrait> {
target: SeTarget,
default: HashSet<T>,
supported: HashSet<T>,
}
impl<T: ControlFlagTrait> ControlFlagsModel<T> {
/// Creates a new Flags configuration.
pub(super) fn new(target: SeTarget, default: HashSet<T>, supported: HashSet<T>) -> Self {
Self {
target,
default,
supported,
}
}
/// Returns the SE header flags target.
pub fn target(&self) -> SeTarget {
self.target
}
/// Returns the SE header version corresponding to this target.
pub fn version(&self) -> SeHdrVersion {
self.target.to_se_hdr_version()
}
/// Returns the set of default flags for this version.
pub fn default_flags(&self) -> &HashSet<T> {
&self.default
}
/// Returns the set of supported flags for this version.
pub fn supported_flags(&self) -> &HashSet<T> {
&self.supported
}
/// Checks if a flag is supported in this version.
pub fn supports<F: AsRef<T>>(&self, flag: F) -> bool {
self.supported.contains(flag.as_ref())
}
/// Checks if a flag is a default flag in this version.
#[must_use]
pub fn is_default<F: AsRef<T>>(&self, flag: F) -> bool {
self.default.contains(flag.as_ref())
}
/// Validates that all flags in the overrides are supported by this model.
///
/// # Arguments
///
/// * `overrides` - The overrides to validate
///
/// # Errors
///
/// Returns `FlagValidationError::NotSupported` if any override flag is not supported by this
/// model
pub fn validate_overrides(
&self,
overrides: &FlagsOverride<T>,
) -> Result<(), FlagValidationError<T>> {
for (flag, _state) in overrides.iter() {
if !self.supports(flag) {
return Err(FlagValidationError::NotSupported {
model: std::any::type_name::<T>(),
flag: *flag,
});
}
}
Ok(())
}
/// Applies overrides to the default flags and returns the effective control flags.
///
/// This method validates the overrides, applies them to the default flags, and returns
/// an `EffectiveControlFlags` instance containing the resulting configuration.
///
/// # Arguments
///
/// * `overrides` - Overrides to apply to the default flags
///
/// # Returns
///
/// An `EffectiveControlFlags<T>` instance with the effective flags after applying overrides
///
/// # Errors
///
/// Returns `FlagValidationError::NotSupported` if an override flag is not supported by this
/// model
pub fn with_overrides(
&self,
overrides: &FlagsOverride<T>,
) -> Result<EffectiveControlFlags<T>, FlagValidationError<T>> {
// Validate overrides first
self.validate_overrides(overrides)?;
let mut effective_flags = self.default.clone();
// Apply overrides
for (flag, state) in overrides.iter() {
match state {
FlagState::Enabled => {
effective_flags.insert(*flag);
}
FlagState::Disabled => {
effective_flags.remove(flag);
}
}
}
Ok(EffectiveControlFlags {
version: self.version(),
known_flags: effective_flags,
unknown_flags: UnknownFlags::empty(),
})
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct UnknownFlags(Msb0Flags64);
/// Trait for types that can be converted to a bit position.
pub trait IntoBitPosition {
fn into_bit_position(self) -> u8;
}
/// Implement IntoBitPosition for u8 directly
impl IntoBitPosition for u8 {
fn into_bit_position(self) -> u8 {
self
}
}
/// Implement IntoBitPosition for types that implement ControlFlagTrait
impl<T: ControlFlagTrait> IntoBitPosition for T {
fn into_bit_position(self) -> u8 {
self.bit_position()
}
}
impl UnknownFlags {
pub fn empty() -> Self {
Self(Msb0Flags64::from(0u64))
}
pub fn from_bits(bits: Msb0Flags64) -> Self {
Self(bits)
}
pub fn bits(self) -> u64 {
self.0.into()
}
#[must_use]
pub fn is_empty(self) -> bool {
self.bits() == 0
}
/// Checks if a specific flag or bit position is set in the unknown flags.
///
/// # Arguments
///
/// * `flag` - Either a flag that implements `ControlFlagTrait`, a reference to such a flag, or
/// a raw bit position (u8)
///
/// # Returns
///
/// `true` if the bit position is set in the unknown flags, `false` otherwise
///
/// # Examples
///
/// ```
/// use pv::misc::Msb0Flags64;
/// use pvimg::uvdata::UnknownFlags;
///
/// // Create UnknownFlags with bit 5 set
/// let flags = Msb0Flags64::from(1u64 << (63 - 5));
/// let unknown_flags = UnknownFlags::from_bits(flags);
///
/// // Using a raw bit position
/// assert!(unknown_flags.contains(5u8));
/// assert!(!unknown_flags.contains(10u8));
/// ```
#[must_use]
pub fn contains(&self, position: u8) -> bool {
self.0.is_set(position)
}
}
/// Represents the effective control flags after applying overrides.
///
/// This structure contains the final set of flags that will be used, including both
/// known flags (from the model) and any unknown flags that were present in the input.
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct EffectiveControlFlags<T: ControlFlagTrait> {
version: SeHdrVersion,
known_flags: HashSet<T>,
unknown_flags: UnknownFlags,
}
impl<T: ControlFlagTrait> EffectiveControlFlags<T> {
/// Creates a new EffectiveControlFlags instance.
///
/// This is primarily used internally by the flags module.
pub(super) fn new(
version: SeHdrVersion,
known_flags: HashSet<T>,
unknown_flags: UnknownFlags,
) -> Self {
Self {
version,
known_flags,
unknown_flags,
}
}
/// Returns the SE header version.
pub fn version(&self) -> SeHdrVersion {
self.version
}
/// Returns the set of known flags.
pub fn known_flags(&self) -> &HashSet<T> {
&self.known_flags
}
/// Returns the unknown flags.
pub fn unknown_flags(&self) -> UnknownFlags {
self.unknown_flags
}
/// Checks if a flag or bit position is enabled in the effective flags.
///
/// This method accepts either a flag type or a raw bit position (u8).
///
/// # Arguments
///
/// * `position` - Either a flag that implements `ControlFlagTrait`, a reference to such a flag,
/// or a raw bit position (u8)
///
/// # Returns
///
/// `true` if the flag/bit is enabled, `false` otherwise
///
/// # Examples
///
/// ```
/// use pvimg::uvdata::{SeHdrControlFlagsModel, SeHdrFlag, SeTarget};
///
/// // Get default flags for V1
/// let pcf_v1 = SeHdrControlFlagsModel::pcf_for_target(SeTarget::V1Max);
/// let flags = pcf_v1.with_overrides(&Default::default()).unwrap();
///
/// // Using a flag
/// assert!(flags.has(SeHdrFlag::PckmoAes));
///
/// // Using a raw bit position (PckmoAes is at bit 57)
/// assert!(flags.has(57u8));
/// ```
pub fn has<P: IntoBitPosition>(&self, position: P) -> bool {
let bit_pos = position.into_bit_position();
// Check if any known flag has this bit position
for flag in &self.known_flags {
if flag.bit_position() == bit_pos {
return true;
}
}
// Check unknown flags
self.unknown_flags.contains(bit_pos)
}
/// Converts the effective flags to a u64 value.
///
/// # Returns
///
/// A u64 representation combining both known and unknown flags
pub fn to_u64(&self) -> u64 {
let flags: Msb0Flags64 = self.into();
flags.into()
}
}
/// Converts `EffectiveControlFlags` to `Msb0Flags64`.
///
/// This combines both known and unknown flags into a single bitfield.
impl<T: ControlFlagTrait> From<EffectiveControlFlags<T>> for Msb0Flags64 {
fn from(flags: EffectiveControlFlags<T>) -> Self {
let mut value = Msb0Flags64::from(flags.unknown_flags.bits());
for flag in &flags.known_flags {
value.set_bit(flag.bit_position());
}
value
}
}
/// Converts a reference to `EffectiveControlFlags` to `Msb0Flags64`.
impl<T: ControlFlagTrait> From<&EffectiveControlFlags<T>> for Msb0Flags64 {
fn from(flags: &EffectiveControlFlags<T>) -> Self {
let mut value = Msb0Flags64::from(flags.unknown_flags.bits());
for flag in &flags.known_flags {
value.set_bit(flag.bit_position());
}
value
}
}
/// Display implementation for `EffectiveControlFlags<T>`.
///
/// Provides two display formats:
/// - Normal format: Lists all enabled flags with " - " prefix, one per line
/// - Alternate format (`{:#}`): Shows the raw bitfield as 66-character binary string
///
/// # Examples
///
/// ```rust
/// use pvimg::uvdata::{FlagsOverride, SeHdrControlFlagsModel, SeHdrFlag, SeTarget};
///
/// let pcf_v1 = SeHdrControlFlagsModel::pcf_for_target(SeTarget::V1Max);
/// let mut overrides = FlagsOverride::new();
/// overrides.enable(SeHdrFlag::ConfidentialDump);
/// let effective = pcf_v1.with_overrides(&overrides).unwrap();
///
/// // Normal format - lists enabled flags
/// println!("{}", effective);
///
/// // Alternate format - shows binary representation
/// println!("{:#}", effective);
/// ```
impl<T: ControlFlagTrait> Display for EffectiveControlFlags<T> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
if f.alternate() {
// Alternate format: show as binary
let flags: Msb0Flags64 = self.into();
write!(f, "{:#066b}", <u64>::from(flags))
} else {
// Normal format: list enabled flags
let flags_s: Vec<String> = self
.known_flags
.iter()
.map(|flag| format!(" - {flag}"))
.collect();
if flags_s.is_empty() && self.unknown_flags.is_empty() {
write!(f, "(no flags enabled)")
} else {
let mut output = flags_s.join("\n");
if !self.unknown_flags.is_empty() {
if !output.is_empty() {
output.push('\n');
}
output.push_str(&format!(
" - unknown flags: {:#018x}",
self.unknown_flags.bits()
));
}
write!(f, "{}", output)
}
}
}
}
/// Converts a reference to `ControlFlagsModel` to `EffectiveControlFlags` using default flags.
///
/// This implementation allows conversion without consuming the model.
///
/// # Examples
///
/// ```rust
/// use pvimg::uvdata::{EffectiveControlFlags, SeHdrControlFlagsModel, SeTarget};
///
/// let pcf_v1 = SeHdrControlFlagsModel::pcf_for_target(SeTarget::V1Max);
/// let flags: EffectiveControlFlags<_> = (&pcf_v1).into();
/// // pcf_v1 is still usable here
/// ```
impl<T: ControlFlagTrait> From<&ControlFlagsModel<T>> for EffectiveControlFlags<T> {
fn from(model: &ControlFlagsModel<T>) -> Self {
EffectiveControlFlags {
version: model.version(),
known_flags: model.default.clone(),
unknown_flags: UnknownFlags::empty(),
}
}
}
/// Converts `ControlFlagsModel` to `Msb0Flags64` using default flags.
///
/// This consumes the model and converts it to a bitfield representation.
impl<T: ControlFlagTrait> From<ControlFlagsModel<T>> for Msb0Flags64 {
fn from(model: ControlFlagsModel<T>) -> Self {
let mut value = Msb0Flags64::default();
for flag in &model.default {
value.set_bit(flag.bit_position());
}
value
}
}
/// Converts a reference to `ControlFlagsModel` to `Msb0Flags64` using default flags.
///
/// This implementation allows conversion without consuming the model.
impl<T: ControlFlagTrait> From<&ControlFlagsModel<T>> for Msb0Flags64 {
fn from(model: &ControlFlagsModel<T>) -> Self {
let mut value = Msb0Flags64::default();
for flag in &model.default {
value.set_bit(flag.bit_position());
}
value
}
}
/// Display implementation for `ControlFlagsModel<T>`.
///
/// Provides two display formats:
/// - Normal format: Lists all default (enabled) flags with " - " prefix, one per line
/// - Alternate format (`{:#}`): Shows the raw bitfield as 66-character binary string
///
/// Note: This displays only the flags in the model's `default` set. Unknown flags
/// are not tracked by `ControlFlagsModel` - they are returned separately by
/// `from_msb0_flags()` when parsing raw bitfields.
///
/// # Examples
///
/// ```rust
/// use pvimg::uvdata::{SeHdrControlFlagsModel, SeTarget};
///
/// let pcf_v1 = SeHdrControlFlagsModel::pcf_for_target(SeTarget::V1Max);
///
/// // Normal format - lists default flags
/// println!("{}", pcf_v1);
///
/// // Alternate format - shows binary representation
/// println!("{:#}", pcf_v1);
/// ```
impl<T: ControlFlagTrait> Display for ControlFlagsModel<T> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
if f.alternate() {
// Alternate format: show as binary
let flags: Msb0Flags64 = self.into();
write!(f, "{:#066b}", <u64>::from(flags))
} else {
// Normal format: list default (enabled) flags
let flags_s: Vec<String> = self
.default
.iter()
.map(|flag| format!(" - {flag}"))
.collect();
if flags_s.is_empty() {
write!(f, "(no flags enabled)")
} else {
write!(f, "{}", flags_s.join("\n"))
}
}
}
}
/// Error type for `TryFrom<Msb0Flags64>` conversion.
#[derive(Debug)]
// Will be used in an upcoming commit
#[expect(dead_code)]
pub enum Msb0FlagsConversionError<T: ControlFlagTrait> {
/// A flag bit is set that is not supported in any version
UnsupportedFlag { bit_position: u8 },
/// A flag bit is set that is not supported in the specified version
NotSupportedInVersion { flag: T, version: SeHdrVersion },
}
impl<T: ControlFlagTrait> Display for Msb0FlagsConversionError<T> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::UnsupportedFlag { bit_position } => {
write!(f, "Unsupported flag at bit position {}", bit_position)
}
Self::NotSupportedInVersion { flag, version } => {
write!(f, "Flag {} not supported in version {:?}", flag, version)
}
}
}
}
impl<T: ControlFlagTrait> std::error::Error for Msb0FlagsConversionError<T> {}
/// Override configuration for control flags.
///
/// Allows specifying individual flag states that override the default configuration.
/// This is useful for customizing flag settings on a per-flag basis.
///
/// # Type Parameters
///
/// * `T` - The control flag enum type (e.g., [`Flag`])
///
/// # Examples
///
/// ```rust
/// use pvimg::uvdata::{FlagsOverride, SeHdrFlag};
///
/// let mut overrides = FlagsOverride::new();
/// overrides.enable(SeHdrFlag::ConfidentialDump);
/// overrides.disable(SeHdrFlag::PckmoAes);
/// ```
#[derive(Debug, Clone)]
pub struct FlagsOverride<T: ControlFlagTrait> {
overrides: HashMap<T, FlagState>,
}
impl<T: ControlFlagTrait> FlagsOverride<T> {
/// Creates a new empty FlagsOverride.
pub fn new() -> Self {
Self {
overrides: HashMap::new(),
}
}
/// Sets an override for a specific flag.
///
/// # Arguments
///
/// * `flag` - The flag to override
/// * `state` - The desired state (Enabled or Disabled)
pub(super) fn set(&mut self, flag: T, state: FlagState) {
self.overrides.insert(flag, state);
}
/// Enables a specific flag by setting its override state to Enabled.
///
/// This is a convenience method equivalent to `set(flag, FlagState::Enabled)`.
///
/// # Arguments
///
/// * `flag` - The flag to enable
///
/// # Examples
///
/// ```rust
/// use pvimg::uvdata::{FlagsOverride, SeHdrFlag};
///
/// let mut overrides = FlagsOverride::new();
/// overrides.enable(SeHdrFlag::ConfidentialDump);
/// ```
pub fn enable(&mut self, flag: T) {
self.set(flag, FlagState::Enabled);
}
/// Disables a specific flag by setting its override state to Disabled.
///
/// This is a convenience method equivalent to `set(flag, FlagState::Disabled)`.
///
/// # Arguments
///
/// * `flag` - The flag to disable
///
/// # Examples
///
/// ```rust
/// use pvimg::uvdata::{FlagsOverride, SeHdrFlag};
///
/// let mut overrides = FlagsOverride::new();
/// overrides.disable(SeHdrFlag::PckmoAes);
/// ```
pub fn disable(&mut self, flag: T) {
self.set(flag, FlagState::Disabled);
}
/// Enables multiple flags at once from an iterator.
///
/// This is a convenience method for enabling multiple flags in a single call.
///
/// # Arguments
///
/// * `flags` - An iterator over flags to enable
///
/// # Examples
///
/// ```rust
/// use pvimg::uvdata::{FlagsOverride, SeHdrFlag};
///
/// let mut overrides = FlagsOverride::new();
/// overrides.enable_all([SeHdrFlag::ConfidentialDump, SeHdrFlag::PckmoAes]);
/// ```
pub fn enable_all<I>(&mut self, flags: I)
where
I: IntoIterator<Item = T>,
{
for flag in flags {
self.enable(flag);
}
}
/// Disables multiple flags at once from an iterator.
///
/// This is a convenience method for disabling multiple flags in a single call.
///
/// # Arguments
///
/// * `flags` - An iterator over flags to disable
///
/// # Examples
///
/// ```rust
/// use pvimg::uvdata::{FlagsOverride, SeHdrFlag};
///
/// let mut overrides = FlagsOverride::new();
/// overrides.disable_all([SeHdrFlag::PckmoAes, SeHdrFlag::PckmoEcc]);
/// ```
pub fn disable_all<I>(&mut self, flags: I)
where
I: IntoIterator<Item = T>,
{
for flag in flags {
self.disable(flag);
}
}
/// Removes an override for a specific flag.
///
/// # Arguments
///
/// * `flag` - The flag to remove the override for
///
/// # Returns
///
/// The previous state if it existed, None otherwise
pub fn remove(&mut self, flag: T) -> Option<FlagState> {
self.overrides.remove(&flag)
}
/// Gets the override state for a specific flag.
///
/// # Arguments
///
/// * `flag` - The flag to query
///
/// # Returns
///
/// The override state if it exists, None otherwise
pub fn get(&self, flag: T) -> Option<FlagState> {
self.overrides.get(&flag).copied()
}
/// Checks if an override exists for a specific flag.
///
/// # Arguments
///
/// * `flag` - The flag to check
pub fn has_override(&self, flag: T) -> bool {
self.overrides.contains_key(&flag)
}
/// Returns an iterator over all overrides.
pub fn iter(&self) -> impl Iterator<Item = (&T, &FlagState)> {
self.overrides.iter()
}
/// Returns an iterator over all flags that have overrides.
pub fn flags(&self) -> impl Iterator<Item = &T> {
self.overrides.keys()
}
/// Returns the number of overrides.
pub fn len(&self) -> usize {
self.overrides.len()
}
/// Checks if there are no overrides.
#[must_use]
pub fn is_empty(&self) -> bool {
self.overrides.is_empty()
}
/// Clears all overrides.
pub fn clear(&mut self) {
self.overrides.clear();
}
}
impl<T: ControlFlagTrait> Default for FlagsOverride<T> {
fn default() -> Self {
Self::new()
}
}