summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/Emoji.zig132
1 files changed, 132 insertions, 0 deletions
diff --git a/src/Emoji.zig b/src/Emoji.zig
new file mode 100644
index 0000000..75b44c2
--- /dev/null
+++ b/src/Emoji.zig
@@ -0,0 +1,132 @@
1const std = @import("std");
2const builtin = @import("builtin");
3const mem = std.mem;
4const Allocator = mem.Allocator;
5const compress = std.compress;
6const unicode = std.unicode;
7
8const CodePoint = @import("code_point").CodePoint;
9const CodePointIterator = @import("code_point").Iterator;
10
11s1: []u16 = undefined,
12s2: []u6 = undefined,
13
14const Emoji = @This();
15
16// This must be an exact match of `Emoji` from `codegen/emoji.zig`.
17pub const Properties = packed struct {
18 Emoji: bool = false,
19 Emoji_Presentation: bool = false,
20 Emoji_Modifier: bool = false,
21 Emoji_Modifier_Base: bool = false,
22 Emoji_Component: bool = false,
23 Extended_Pictographic: bool = false,
24};
25
26pub fn init(allocator: Allocator) Allocator.Error!Emoji {
27 var emoji = Emoji{};
28 try emoji.setup(allocator);
29 return emoji;
30}
31
32pub fn setup(emoji: *Emoji, allocator: Allocator) Allocator.Error!void {
33 const decompressor = compress.flate.inflate.decompressor;
34 const in_bytes = @embedFile("emoji");
35 var in_fbs = std.io.fixedBufferStream(in_bytes);
36 var in_decomp = decompressor(.raw, in_fbs.reader());
37 var reader = in_decomp.reader();
38
39 const endian = builtin.cpu.arch.endian();
40
41 const s1_len: u16 = reader.readInt(u16, endian) catch unreachable;
42 emoji.s1 = try allocator.alloc(u16, s1_len);
43 errdefer allocator.free(emoji.s1);
44 for (0..s1_len) |i| emoji.s1[i] = reader.readInt(u16, endian) catch unreachable;
45
46 const s2_len: u16 = reader.readInt(u16, endian) catch unreachable;
47 emoji.s2 = try allocator.alloc(u6, s2_len);
48 errdefer allocator.free(emoji.s2);
49 for (0..s2_len) |i| emoji.s2[i] = @intCast(reader.readInt(u8, endian) catch unreachable);
50}
51
52pub fn deinit(emoji: *const Emoji, allocator: Allocator) void {
53 allocator.free(emoji.s1);
54 allocator.free(emoji.s2);
55}
56
57/// Lookup the emoji properties for a code point.
58fn properties(emoji: Emoji, cp: u21) Properties {
59 return @bitCast(emoji.s2[emoji.s1[cp >> 8] + (cp & 0xff)]);
60}
61
62pub fn isEmoji(emoji: Emoji, cp: u21) bool {
63 return properties(emoji, cp).Emoji;
64}
65
66pub fn isEmojiPresentation(emoji: Emoji, cp: u21) bool {
67 return properties(emoji, cp).Emoji_Presentation;
68}
69
70pub fn isEmojiModifier(emoji: Emoji, cp: u21) bool {
71 return properties(emoji, cp).Emoji_Modifier;
72}
73
74pub fn isEmojiModifierBase(emoji: Emoji, cp: u21) bool {
75 return properties(emoji, cp).Emoji_Modifier_Base;
76}
77
78pub fn isEmojiComponent(emoji: Emoji, cp: u21) bool {
79 return properties(emoji, cp).Emoji_Component;
80}
81
82pub fn isExtendedPictographic(emoji: Emoji, cp: u21) bool {
83 return properties(emoji, cp).Extended_Pictographic;
84}
85
86test "isEmoji" {
87 const emoji = try Emoji.init(std.testing.allocator);
88 defer emoji.deinit(std.testing.allocator);
89
90 try std.testing.expect(emoji.isEmoji(0x1F415)); // 🐕
91 try std.testing.expect(!emoji.isEmoji(0x3042)); // あ
92}
93
94test "isEmojiPresentation" {
95 const emoji = try Emoji.init(std.testing.allocator);
96 defer emoji.deinit(std.testing.allocator);
97
98 try std.testing.expect(emoji.isEmojiPresentation(0x1F408)); // 🐈
99 try std.testing.expect(!emoji.isEmojiPresentation(0x267E)); // ♾
100}
101
102test "isEmojiModifier" {
103 const emoji = try Emoji.init(std.testing.allocator);
104 defer emoji.deinit(std.testing.allocator);
105
106 try std.testing.expect(emoji.isEmojiModifier(0x1F3FF)); // 🏿
107 try std.testing.expect(!emoji.isEmojiModifier(0x1F385)); // 🎅
108}
109
110test "isEmojiModifierBase" {
111 const emoji = try Emoji.init(std.testing.allocator);
112 defer emoji.deinit(std.testing.allocator);
113
114 try std.testing.expect(emoji.isEmojiModifierBase(0x1F977)); // 🥷
115 try std.testing.expect(!emoji.isEmojiModifierBase(0x1F4F8)); // 📸
116}
117
118test "isEmojiComponent" {
119 const emoji = try Emoji.init(std.testing.allocator);
120 defer emoji.deinit(std.testing.allocator);
121
122 try std.testing.expect(emoji.isEmojiComponent(0x1F9B0)); // 🦰
123 try std.testing.expect(!emoji.isEmojiComponent(0x1F9B5)); // 🦵
124}
125
126test "isExtendedPictographic" {
127 const emoji = try Emoji.init(std.testing.allocator);
128 defer emoji.deinit(std.testing.allocator);
129
130 try std.testing.expect(emoji.isExtendedPictographic(0x1F005)); // 🀅
131 try std.testing.expect(!emoji.isExtendedPictographic(0x2A)); // *
132}