unicode-width 0.2.3

Determine displayed width of `char` and `str` types according to Unicode Standard Annex #11 rules.
Documentation
// Copyright 2012-2025 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

// NOTE: The following code was generated by "scripts/unicode.py", do not edit directly
use crate::tables::*;
use core::cmp::Ordering;

/// Whether this character has Joining_Group=Lam.
pub fn is_joining_group_lam(c: char) -> bool {
    matches!(
        c,
        '\u{644}' | '\u{6B5}'..='\u{6B8}' | '\u{76A}' | '\u{8A6}' | '\u{8C7}'
    )
}

/// Whether this character is a default-ignorable combining mark
/// or ZWJ. These characters won't interrupt non-Arabic ligatures.
pub fn is_ligature_transparent(c: char) -> bool {
    matches!(
        c,
        '\u{34F}' | '\u{17B4}'..='\u{17B5}' | '\u{180B}'..='\u{180D}' | '\u{180F}' | '\u{200D}' | '\u{FE00}'..='\u{FE0F}' | '\u{E0100}'..='\u{E01EF}'
    )
}

/// Whether this character forms an [emoji presentation sequence]
/// (https://www.unicode.org/reports/tr51/#def_emoji_presentation_sequence)
/// when followed by `'\u{FEOF}'`.
/// Emoji presentation sequences are considered to have width 2.
#[inline]
pub fn starts_emoji_presentation_seq(c: char) -> bool {
    let cp: u32 = c.into();
    // First level of lookup uses all but 10 LSB
    let top_bits = cp >> 10;
    let idx_of_leaf: usize = match top_bits {
        0x0 => 0,
        0x8 => 1,
        0x9 => 2,
        0xA => 3,
        0xC => 4,
        0x7C => 5,
        0x7D => 6,
        _ => return false,
    };
    // Extract the 3-9th (0-indexed) least significant bits of `cp`,
    // and use them to index into `leaf_row`.
    let idx_within_leaf = usize::try_from((cp >> 3) & 0x7F).unwrap();
    let leaf_byte = EMOJI_PRESENTATION_LEAVES.0[idx_of_leaf][idx_within_leaf];
    // Use the 3 LSB of `cp` to index into `leaf_byte`.
    ((leaf_byte >> (cp & 7)) & 1) == 1
}

/// Returns `true` if `c` has default emoji presentation, but forms a [text presentation sequence]
/// (https://www.unicode.org/reports/tr51/#def_text_presentation_sequence)
/// when followed by `'\u{FEOE}'`, and is not ideographic.
/// Such sequences are considered to have width 1.
#[inline]
pub fn starts_non_ideographic_text_presentation_seq(c: char) -> bool {
    let cp: u32 = c.into();
    // First level of lookup uses all but 8 LSB
    let top_bits = cp >> 8;
    let leaf: &[(u8, u8)] = match top_bits {
        0x23 => &TEXT_PRESENTATION_LEAF_0,
        0x25 => &TEXT_PRESENTATION_LEAF_1,
        0x26 => &TEXT_PRESENTATION_LEAF_2,
        0x27 => &TEXT_PRESENTATION_LEAF_3,
        0x2B => &TEXT_PRESENTATION_LEAF_4,
        0x1F0 => &TEXT_PRESENTATION_LEAF_5,
        0x1F3 => &TEXT_PRESENTATION_LEAF_6,
        0x1F4 => &TEXT_PRESENTATION_LEAF_7,
        0x1F5 => &TEXT_PRESENTATION_LEAF_8,
        0x1F6 => &TEXT_PRESENTATION_LEAF_9,
        _ => return false,
    };

    let bottom_bits = (cp & 0xFF) as u8;
    leaf.binary_search_by(|&(lo, hi)| {
        if bottom_bits < lo {
            Ordering::Greater
        } else if bottom_bits > hi {
            Ordering::Less
        } else {
            Ordering::Equal
        }
    })
    .is_ok()
}

/// Returns `true` if `c` is an `Emoji_Modifier_Base`.
#[inline]
pub fn is_emoji_modifier_base(c: char) -> bool {
    let cp: u32 = c.into();
    // First level of lookup uses all but 8 LSB
    let top_bits = cp >> 8;
    let leaf: &[(u8, u8)] = match top_bits {
        0x26 => &EMOJI_MODIFIER_LEAF_0,
        0x27 => &EMOJI_MODIFIER_LEAF_1,
        0x1F3 => &EMOJI_MODIFIER_LEAF_2,
        0x1F4 => &EMOJI_MODIFIER_LEAF_3,
        0x1F5 => &EMOJI_MODIFIER_LEAF_4,
        0x1F6 => &EMOJI_MODIFIER_LEAF_5,
        0x1F9 => &EMOJI_MODIFIER_LEAF_6,
        0x1FA => &EMOJI_MODIFIER_LEAF_7,
        _ => return false,
    };

    let bottom_bits = (cp & 0xFF) as u8;
    leaf.binary_search_by(|&(lo, hi)| {
        if bottom_bits < lo {
            Ordering::Greater
        } else if bottom_bits > hi {
            Ordering::Less
        } else {
            Ordering::Equal
        }
    })
    .is_ok()
}