Repository: bevyengine/bevy
File: crates/bevy_text/src/text.rs (Rust)

Code before:
}

/// OpenType features for .otf fonts that support them.
///
/// Examples features include:
/// "liga": Standard ligatures
/// "clig": Contextual ligatures
/// "dlig": Discretionary ligatures
/// "smcp": Small-caps
/// "ss01", "ss02", ..., "ss20": Stylistic alternates
/// "frac": Fractions, formatting numbers like 1/2
/// "ordn": Ordinals, formatting characters like "1st" or "2nd" properly
/// For the complete list of OpenType features, see the spec at
/// `<https://learn.microsoft.com/en-us/typography/opentype/spec/featurelist>`.
///
/// The above font features can be enabled via [`FontFeatures::enable`]. Some font features take
/// numeric values, rather than being on/off switches. For example, for weights of variable
/// fonts, the font feature "wght" can be any value between 100 and 900, with lower values
/// corresponding to lighter weights and higher values corresponding to heavier weights. For
/// these features, use [`FontFeatures::set`] to assign a specific value.
#[derive(Clone, Debug, Default, Reflect)]
pub struct FontFeatures {
    features: HashMap<[u8; 4], u32>,
}

impl FontFeatures {
    /// Create a new [`FontFeatures`].
    pub fn new() -> Self {
        FontFeatures {
            features: HashMap::new(),
        }
    }

    /// Enable an OpenType feature.
    ///
    /// Most OpenType features are on/off switches, so this is a convenience method that sets the
    /// feature's value to "1" (enabled). For non-boolean features, see [`FontFeatures::set`].
    pub fn enable(self, feature: &[u8; 4]) -> Self {
        self.set(feature, 1)
    }

    /// Set an OpenType feature to a specific value.
    ///
    /// For most features, the [`FontFeatures::enable`] method should be used instead. A few
    /// features, such as "wght", take numeric values, so this method may be used for these cases.
    pub fn set(mut self, feature: &[u8; 4], value: u32) -> Self {
        self.features.insert(*feature, value);
        self
    }
}


Review comment (suggestion):
Agree that an enum with 100+ variants might be burdensome to maintain, but maybe some constants for commonly used features might be useful like:
```suggestion
impl FontFeatures {
    pub const SUPERSCRIPT: [u8; 4] = b"sups";
```
and so on

Code after:
    /// Replaces figures with subscript figures.
    pub const SUBSCRIPT: FontFeatureTag = FontFeatureTag::new(b"subs");

    /// Changes numbers to "oldstyle" form, which fit better in the flow of sentences or other text.
    pub const OLDSTYLE_FIGURES: FontFeatureTag = FontFeatureTag::new(b"onum");

    /// Changes numbers to "lining" form, which are better suited for standalone numbers. When
    /// enabled, the bottom of all numbers will be aligned with each other.
    pub const LINING_FIGURES: FontFeatureTag = FontFeatureTag::new(b"lnum");

    /// Changes numbers to be of proportional width. When enabled, numbers may have varying widths.
    pub const PROPORTIONAL_FIGURES: FontFeatureTag = FontFeatureTag::new(b"pnum");

    /// Changes numbers to be of uniform (tabular) width. When enabled, all numbers will have the
    /// same width.
    pub const TABULAR_FIGURES: FontFeatureTag = FontFeatureTag::new(b"tnum");

    /// Varies the stroke thickness. Values must be in the range of 0 to 1000.
    pub const WEIGHT: FontFeatureTag = FontFeatureTag::new(b"wght");

    /// Varies the width of text from narrower to wider. Must be a value greater than 0. A value of
    /// 100 is typically considered standard width.
    pub const WIDTH: FontFeatureTag = FontFeatureTag::new(b"wdth");

    /// Varies between upright and slanted text. Must be a value greater than -90 and less than +90.
    /// A value of 0 is upright.
    pub const SLANT: FontFeatureTag = FontFeatureTag::new(b"slnt");

    /// Create a new [`FontFeatureTag`] from raw bytes.
    pub const fn new(src: &[u8; 4]) -> Self {
        Self(*src)
    }
}

impl Debug for FontFeatureTag {
    fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
        // OpenType tags are always ASCII, so this match will succeed for valid tags. This gives us
        // human-readable debug output, e.g. FontFeatureTag("liga").
        match from_utf8(&self.0) {
            Ok(s) => write!(f, "FontFeatureTag(\"{}\")", s),
            Err(_) => write!(f, "FontFeatureTag({:?})", self.0),
        }
    }
}

/// OpenType features for .otf fonts that support them.
///
/// Examples features include ligatures, small-caps, and fractional number display. For the complete
/// list of OpenType features, see the spec at
/// `<https://learn.microsoft.com/en-us/typography/opentype/spec/featurelist>`.
///