const std = @import("std"); const Allocator = std.mem.Allocator; const ArrayList = std.ArrayList; const GeneralCategories = @import("GeneralCategories"); const LetterCasing = @import("LetterCasing"); const Utf8View = std.unicode.Utf8View; pub fn escapeXml(writer: anytype, text: []const u8) !void { for (text) |ch| { try switch (ch) { '<' => writer.writeAll("<"), '>' => writer.writeAll(">"), '&' => writer.writeAll("&"), '"' => writer.writeAll("""), else => writer.writeByte(ch), }; } } var gc_global: ?GeneralCategories = null; pub fn getGC() !GeneralCategories { if (gc_global) |gc| { return gc; } gc_global = try GeneralCategories.init(std.heap.page_allocator); return gc_global.?; } var lc_global: ?LetterCasing = null; pub fn getLetterCasing() !LetterCasing { if (lc_global) |lc| { return lc; } lc_global = try LetterCasing.init(std.heap.page_allocator); return lc_global.?; } // arr should be sorted as according to isSorted. pub inline fn isIn(comptime T: type, val: T, arr: []const T) bool { const order = struct { pub fn f(a: T, b: T) std.math.Order { return std.math.order(a, b); } }.f; return std.sort.binarySearch(T, arr, val, order) != null; } pub inline fn isNull(value: anytype) bool { return switch (@typeInfo(@TypeOf(value))) { .null => true, .optional => value == null, else => false, }; } pub inline fn isSorted(comptime T: type, arr: []const T) bool { return std.sort.isSorted(T, arr, {}, std.sort.asc(T)); } pub fn isTgWhitespaceStr(str: []const u8) !bool { const view = try Utf8View.init(str); const gc = try getGC(); var it = view.iterator(); while (it.nextCodepoint()) |cp| { if (!isTgWhitespace(gc, cp)) { return false; } } return true; } inline fn isTgWhitespace(gc: GeneralCategories, cp: u21) bool { return gc.isSeparator(cp) or gc.isControl(cp) or cp == 0x2800 // BRAILLE PATTERN BLANK, telegram treats messages with just this as invalid messages ; }