Repository: typst/typst
File: crates/typst-library/src/text/mod.rs (Rust)

Code before:
        .map(|(tag, num)| {
            let bytes = tag.to_bytes();
            let key = std::str::from_utf8(&bytes).unwrap_or_default();
            (key.into(), num.into_value())
        })
        .collect::<Dict>()
        .into_value(),
    values: Array => Self(values
        .into_iter()
        .enumerate()
        .map(|(i, v)| Ok((
            v.clone().cast::<Tag>()
                .hint(eco_format!(
                    "occurred in tag at index {i}, '{}'",
                    v.cast::<EcoString>().unwrap_or_default()
                ))
                .hint("to set features with custom values, consider supplying a `dictionary`")?,
            1
        )))
        .collect::<HintedStrResult<_>>()?),
    values: Dict => Self(values
        .into_iter()
        .enumerate()
        .map(|(i, (k, v))| Ok((
            k.clone().into_value().cast::<Tag>().hint(
                eco_format!("occurred in tag at index {i}, '{k}'")
            )?,
            v.cast::<u32>()?
        )))
        .collect::<HintedStrResult<_>>()?),
}

impl Fold for FontFeatures {
    fn fold(self, outer: Self) -> Self {
        Self(self.0.fold(outer.0))
    }
}

/// Collect the OpenType features to apply.
pub fn features(styles: StyleChain) -> Vec<Feature> {
    let mut tags = vec![];
    let mut feat = |tag: &[u8; 4], value: u32| {
        tags.push(Feature::new(Tag::from_bytes(tag), value, ..));
    };

    // Features that are on by default in Harfbuzz are only added if disabled.
    if !styles.get(TextElem::kerning) {
        feat(b"kern", 0);
    }

    // Features that are off by default in Harfbuzz are only added if enabled.

Review comment (refactor):
this could also happen for the value. I suppose we could move it into a helper function.

maybe there is also a potential for sharing code with the `Array` case

Code after:
                // Append a hint if the value is a string containing the
                // assignment operator `=` or another type was supplied.
                if v.cast::<Str>().map_or(true, |v| v.as_str().contains('=')) {
                    e.with_hint("to set features with custom values, consider supplying a dictionary")
                } else {
                    e
                }
            })?,
            1
        )))
        .collect::<HintedStrResult<_>>()?),
    values: Dict => Self(values
        .into_iter()
        .enumerate()
        .map(|(i, (k, v))| Ok((
            k.clone().into_value().cast::<Tag>().hint(tag_hint_helper(i, &k))?,
            v.cast::<u32>().hint(tag_hint_helper(i, &k))?
        )))
        .collect::<HintedStrResult<_>>()?),
}

fn tag_hint_helper(index: usize, key: &impl Repr) -> EcoString {
    eco_format!("occurred in tag at index {index} (`{}`)", key.repr())
}

impl Fold for FontFeatures {
    fn fold(self, outer: Self) -> Self {
        Self(self.0.fold(outer.0))
    }
}

/// Collect the OpenType features to apply.
pub fn features(styles: StyleChain) -> Vec<Feature> {
    let mut tags = vec![];
    let mut feat = |tag: &[u8; 4], value: u32| {
        tags.push(Feature::new(Tag::from_bytes(tag), value, ..));
    };

    // Features that are on by default in Harfbuzz are only added if disabled.
    if !styles.get(TextElem::kerning) {
        feat(b"kern", 0);
    }

    // Features that are off by default in Harfbuzz are only added if enabled.
    if let Some(sc) = styles.get(TextElem::smallcaps) {
        feat(b"smcp", 1);
        if sc == Smallcaps::All {
            feat(b"c2sc", 1);
        }
    }