diff options
| author | 2025-06-24 07:55:16 -0400 | |
|---|---|---|
| committer | 2025-06-24 07:55:16 -0400 | |
| commit | d7df2b4b92e198fbdbe5cfc29095d48980675004 (patch) | |
| tree | 3a6a8afa88dfcbee6b5733769604060d0f95b7b9 /src/Emoji.zig | |
| parent | Merge pull request 'Fix benchmarks' (#56) from jacobsandlund/zg:benchmarks in... (diff) | |
| download | zg-d7df2b4b92e198fbdbe5cfc29095d48980675004.tar.gz zg-d7df2b4b92e198fbdbe5cfc29095d48980675004.tar.xz zg-d7df2b4b92e198fbdbe5cfc29095d48980675004.zip | |
Add Emoji module and codegen/emoji
Diffstat (limited to 'src/Emoji.zig')
| -rw-r--r-- | src/Emoji.zig | 132 |
1 files changed, 132 insertions, 0 deletions
diff --git a/src/Emoji.zig b/src/Emoji.zig new file mode 100644 index 0000000..bf7014d --- /dev/null +++ b/src/Emoji.zig | |||
| @@ -0,0 +1,132 @@ | |||
| 1 | const std = @import("std"); | ||
| 2 | const builtin = @import("builtin"); | ||
| 3 | const mem = std.mem; | ||
| 4 | const Allocator = mem.Allocator; | ||
| 5 | const compress = std.compress; | ||
| 6 | const unicode = std.unicode; | ||
| 7 | |||
| 8 | const CodePoint = @import("code_point").CodePoint; | ||
| 9 | const CodePointIterator = @import("code_point").Iterator; | ||
| 10 | |||
| 11 | s1: []u16 = undefined, | ||
| 12 | s2: []u6 = undefined, | ||
| 13 | |||
| 14 | const Emoji = @This(); | ||
| 15 | |||
| 16 | // This must be an exact match of `Emoji` from `codegen/emoji.zig`. | ||
| 17 | pub 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 | |||
| 26 | pub fn init(allocator: Allocator) Allocator.Error!Emoji { | ||
| 27 | var emoji = Emoji{}; | ||
| 28 | try emoji.setup(allocator); | ||
| 29 | return emoji; | ||
| 30 | } | ||
| 31 | |||
| 32 | pub 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 | |||
| 52 | pub 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. | ||
| 58 | fn properties(emoji: Emoji, cp: u21) Properties { | ||
| 59 | return @bitCast(emoji.s2[emoji.s1[cp >> 8] + (cp & 0xff)]); | ||
| 60 | } | ||
| 61 | |||
| 62 | pub fn isEmoji(emoji: Emoji, cp: u21) bool { | ||
| 63 | return properties(emoji, cp).Emoji; | ||
| 64 | } | ||
| 65 | |||
| 66 | pub fn isEmojiPresentation(emoji: Emoji, cp: u21) bool { | ||
| 67 | return properties(emoji, cp).Emoji_Presentation; | ||
| 68 | } | ||
| 69 | |||
| 70 | pub fn isEmojiModifier(emoji: Emoji, cp: u21) bool { | ||
| 71 | return properties(emoji, cp).Emoji_Modifier; | ||
| 72 | } | ||
| 73 | |||
| 74 | pub fn isEmojiModifierBase(emoji: Emoji, cp: u21) bool { | ||
| 75 | return properties(emoji, cp).Emoji_Modifier_Base; | ||
| 76 | } | ||
| 77 | |||
| 78 | pub fn isEmojiComponent(emoji: Emoji, cp: u21) bool { | ||
| 79 | return properties(emoji, cp).Emoji_Component; | ||
| 80 | } | ||
| 81 | |||
| 82 | pub fn isExtendedPictographic(emoji: Emoji, cp: u21) bool { | ||
| 83 | return properties(emoji, cp).Extended_Pictographic; | ||
| 84 | } | ||
| 85 | |||
| 86 | test "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 | |||
| 94 | test "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 | |||
| 102 | test "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 | |||
| 110 | test "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 | |||
| 118 | test "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 | |||
| 126 | test "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 | } | ||