#unicode #joining #arabic #shaping #no-std

no-std unicode-joining-type

Fast lookup of the Unicode Joining Type and Joining Group properties

8 releases (breaking)

0.7.0 Sep 19, 2022
0.6.0 Jan 25, 2022
0.5.0 Feb 3, 2021
0.4.0 Nov 18, 2020
0.1.0 Dec 13, 2019

#1659 in Text processing

Download history 477/week @ 2023-11-04 499/week @ 2023-11-11 728/week @ 2023-11-18 423/week @ 2023-11-25 383/week @ 2023-12-02 234/week @ 2023-12-09 302/week @ 2023-12-16 187/week @ 2023-12-23 285/week @ 2023-12-30 384/week @ 2024-01-06 410/week @ 2024-01-13 409/week @ 2024-01-20 395/week @ 2024-01-27 272/week @ 2024-02-03 562/week @ 2024-02-10 558/week @ 2024-02-17

1,838 downloads per month
Used in 10 crates (2 directly)


1.5K SLoC


Fast lookup of the Unicode Joining Type and Joining Group properties for char in Rust using Unicode 15.0 data. This crate is no-std compatible.


use unicode_joining_type::{get_joining_type, JoiningType};
use unicode_joining_type::{get_joining_group, JoiningGroup};

fn main() {
    assert_eq!(get_joining_type('A'), JoiningType::NonJoining);
    assert_eq!(get_joining_group('ھ'), JoiningGroup::KnottedHeh);

Performance & Implementation Notes

ucd-generate is used to generate joining_type_tables.rs and joining_group_tables.rs. A build script (build.rs) compiles each of these into a two level look up tables. The look up time is constant as it is just indexing into two arrays.

The two level approach maps a code point to a block, then to a position within a block. The allows the second level of block to be deduplicated, saving space. The code is parameterised over the block size, which must be a power of 2. The value in the build script is optimal for the data set.

This approach trades off some space for faster lookups. The joining type tables take up about 26KiB, the joining group tables take up about 6.75KiB. Benchmarks showed this approach to be ~5–10× faster than the typical binary search approach.

There is still room for further size reduction. For example, by eliminating repeated block mappings at the end of the first level block array.

No runtime deps