1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
use crate::sys;

#[derive(Clone, Eq, PartialEq, Debug)]
enum FontGlyphRangeData {
    ChineseSimplifiedCommon,
    ChineseFull,
    Cyrillic,
    Default,
    Japanese,
    Korean,
    Thai,
    Vietnamese,
    Custom(*const sys::ImWchar),
}

/// A set of 16-bit Unicode codepoints
#[derive(Clone, Eq, PartialEq, Debug)]
pub struct FontGlyphRanges(FontGlyphRangeData);
impl FontGlyphRanges {
    /// The default set of glyph ranges used by imgui.
    pub fn default() -> FontGlyphRanges {
        FontGlyphRanges(FontGlyphRangeData::Default)
    }
    /// A set of glyph ranges appropriate for use with simplified common Chinese text.
    pub fn chinese_simplified_common() -> FontGlyphRanges {
        FontGlyphRanges(FontGlyphRangeData::ChineseSimplifiedCommon)
    }
    /// A set of glyph ranges appropriate for use with Chinese text.
    pub fn chinese_full() -> FontGlyphRanges {
        FontGlyphRanges(FontGlyphRangeData::ChineseFull)
    }
    /// A set of glyph ranges appropriate for use with Cyrillic text.
    pub fn cyrillic() -> FontGlyphRanges {
        FontGlyphRanges(FontGlyphRangeData::Cyrillic)
    }
    /// A set of glyph ranges appropriate for use with Japanese text.
    pub fn japanese() -> FontGlyphRanges {
        FontGlyphRanges(FontGlyphRangeData::Japanese)
    }
    /// A set of glyph ranges appropriate for use with Korean text.
    pub fn korean() -> FontGlyphRanges {
        FontGlyphRanges(FontGlyphRangeData::Korean)
    }
    /// A set of glyph ranges appropriate for use with Thai text.
    pub fn thai() -> FontGlyphRanges {
        FontGlyphRanges(FontGlyphRangeData::Thai)
    }
    /// A set of glyph ranges appropriate for use with Vietnamese text.
    pub fn vietnamese() -> FontGlyphRanges {
        FontGlyphRanges(FontGlyphRangeData::Vietnamese)
    }

    /// Creates a glyph range from a static slice. The expected format is a series of pairs of
    /// non-zero shorts, each representing an inclusive range of codepoints, followed by a single
    /// zero terminating the range. The ranges must not overlap.
    ///
    /// As the slice is expected to last as long as a font is used, and is written into global
    /// state, it must be `'static`.
    ///
    /// Panics
    /// ======
    ///
    /// This function will panic if the given slice is not a valid font range.
    pub fn from_slice(slice: &'static [u16]) -> FontGlyphRanges {
        assert_eq!(
            slice.len() % 2,
            1,
            "The length of a glyph range must be odd."
        );
        assert_eq!(
            slice.last(),
            Some(&0),
            "A glyph range must be zero-terminated."
        );

        for (i, &glyph) in slice.iter().enumerate().take(slice.len() - 1) {
            assert_ne!(
                glyph, 0,
                "A glyph in a range cannot be zero. \
                 (Glyph is zero at index {})",
                i
            )
        }

        let mut ranges = Vec::new();
        for i in 0..slice.len() / 2 {
            let (start, end) = (slice[i * 2], slice[i * 2 + 1]);
            assert!(
                start <= end,
                "The start of a range cannot be larger than its end. \
                 (At index {}, {} > {})",
                i * 2,
                start,
                end
            );
            ranges.push((start, end));
        }
        ranges.sort_unstable_by_key(|x| x.0);
        for i in 0..ranges.len() - 1 {
            let (range_a, range_b) = (ranges[i], ranges[i + 1]);
            if range_a.1 >= range_b.0 {
                panic!(
                    "The glyph ranges {:?} and {:?} overlap between {:?}.",
                    range_a,
                    range_b,
                    (range_a.1, range_b.0)
                );
            }
        }

        unsafe { FontGlyphRanges::from_slice_unchecked(slice) }
    }

    /// Creates a glyph range from a static slice without checking its validity.
    ///
    /// See [`FontGlyphRanges::from_slice`] for more information.
    ///
    /// # Safety
    ///
    /// It is up to the caller to guarantee the slice contents are valid.
    pub unsafe fn from_slice_unchecked(slice: &'static [u16]) -> FontGlyphRanges {
        FontGlyphRanges::from_ptr(slice.as_ptr())
    }

    /// Creates a glyph range from a pointer, without checking its validity or enforcing its
    /// lifetime. The memory the pointer points to must be valid for as long as the font is
    /// in use.
    ///
    /// # Safety
    ///
    /// It is up to the caller to guarantee the pointer is not null, remains valid forever, and
    /// points to valid data.
    pub unsafe fn from_ptr(ptr: *const u16) -> FontGlyphRanges {
        FontGlyphRanges(FontGlyphRangeData::Custom(ptr))
    }

    pub(crate) unsafe fn to_ptr(&self, atlas: *mut sys::ImFontAtlas) -> *const sys::ImWchar {
        match self.0 {
            FontGlyphRangeData::ChineseFull => sys::ImFontAtlas_GetGlyphRangesChineseFull(atlas),
            FontGlyphRangeData::ChineseSimplifiedCommon => {
                sys::ImFontAtlas_GetGlyphRangesChineseSimplifiedCommon(atlas)
            }
            FontGlyphRangeData::Cyrillic => sys::ImFontAtlas_GetGlyphRangesCyrillic(atlas),
            FontGlyphRangeData::Default => sys::ImFontAtlas_GetGlyphRangesDefault(atlas),
            FontGlyphRangeData::Japanese => sys::ImFontAtlas_GetGlyphRangesJapanese(atlas),
            FontGlyphRangeData::Korean => sys::ImFontAtlas_GetGlyphRangesKorean(atlas),
            FontGlyphRangeData::Thai => sys::ImFontAtlas_GetGlyphRangesThai(atlas),
            FontGlyphRangeData::Vietnamese => sys::ImFontAtlas_GetGlyphRangesVietnamese(atlas),
            FontGlyphRangeData::Custom(ptr) => ptr,
        }
    }
}