atproto utils for zig zat.dev
atproto sdk zig
26
fork

Configure Feed

Select the types of activity you want to include in your feed.

migrate MstReader to low-level cbor read API, remove duplicate parser

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

jcalabro 2545e358 7388697d

+63 -111
+63 -111
src/internal/repo/mst.zig
··· 842 842 }; 843 843 844 844 pub fn decodeMstNode(allocator: Allocator, data: []const u8) !MstNodeData { 845 - var r = MstReader{ .data = data, .pos = 0 }; 845 + var pos: usize = 0; 846 846 847 - const map_count = try r.expectMap(); 848 - if (map_count != 2) return error.InvalidMstNode; 847 + const map_hdr = cbor.readMapHeader(data, pos) catch return error.InvalidMstNode; 848 + pos = map_hdr.end; 849 + if (map_hdr.val != 2) return error.InvalidMstNode; 849 850 850 851 // "e" key 851 - const key_e = try r.readTextString(); 852 - if (!std.mem.eql(u8, key_e, "e")) return error.InvalidMstNode; 852 + const key_e = cbor.readText(data, pos) catch return error.InvalidMstNode; 853 + pos = key_e.end; 854 + if (!std.mem.eql(u8, key_e.val, "e")) return error.InvalidMstNode; 853 855 854 856 // entries array 855 - const entries_count = try r.expectArray(); 856 - const entries = try allocator.alloc(MstEntryData, entries_count); 857 + const arr_hdr = cbor.readArrayHeader(data, pos) catch return error.InvalidMstNode; 858 + pos = arr_hdr.end; 859 + const entries = try allocator.alloc(MstEntryData, @intCast(arr_hdr.val)); 857 860 for (entries) |*entry| { 858 - entry.* = try readMstEntry(&r); 861 + const result = readMstEntry(data, pos) catch return error.InvalidMstNode; 862 + entry.* = result.entry; 863 + pos = result.end; 859 864 } 860 865 861 866 // "l" key 862 - const key_l = try r.readTextString(); 863 - if (!std.mem.eql(u8, key_l, "l")) return error.InvalidMstNode; 867 + const key_l = cbor.readText(data, pos) catch return error.InvalidMstNode; 868 + pos = key_l.end; 869 + if (!std.mem.eql(u8, key_l.val, "l")) return error.InvalidMstNode; 864 870 865 - const left = try r.readCidOrNull(); 871 + // left CID or null 872 + const left_result = readCidOrNull(data, pos) catch return error.InvalidMstNode; 866 873 867 - return .{ .left = left, .entries = entries }; 874 + return .{ .left = left_result.val, .entries = entries }; 868 875 } 869 876 870 - fn readMstEntry(r: *MstReader) !MstEntryData { 871 - const map_count = try r.expectMap(); 872 - if (map_count != 4) return error.InvalidMstNode; 877 + const MstEntryResult = struct { 878 + entry: MstEntryData, 879 + end: usize, 880 + }; 881 + 882 + fn readMstEntry(data: []const u8, pos: usize) !MstEntryResult { 883 + var p = pos; 884 + 885 + const map_hdr = cbor.readMapHeader(data, p) catch return error.InvalidMstNode; 886 + p = map_hdr.end; 887 + if (map_hdr.val != 4) return error.InvalidMstNode; 873 888 874 889 // "k" → key suffix (byte string) 875 - _ = try r.readTextString(); 876 - const key_suffix = try r.readByteString(); 890 + const key_k = cbor.readText(data, p) catch return error.InvalidMstNode; 891 + p = key_k.end; 892 + const key_suffix = cbor.readBytes(data, p) catch return error.InvalidMstNode; 893 + p = key_suffix.end; 877 894 878 895 // "p" → prefix length (unsigned int) 879 - _ = try r.readTextString(); 880 - const prefix_len = try r.readUnsigned(); 896 + const key_p = cbor.readText(data, p) catch return error.InvalidMstNode; 897 + p = key_p.end; 898 + const prefix_len = cbor.readUint(data, p) catch return error.InvalidMstNode; 899 + p = prefix_len.end; 881 900 882 901 // "t" → right subtree CID or null 883 - _ = try r.readTextString(); 884 - const tree = try r.readCidOrNull(); 902 + const key_t = cbor.readText(data, p) catch return error.InvalidMstNode; 903 + p = key_t.end; 904 + const tree_result = readCidOrNull(data, p) catch return error.InvalidMstNode; 905 + p = tree_result.end; 885 906 886 907 // "v" → value CID 887 - _ = try r.readTextString(); 888 - const value = try r.readCid(); 908 + const key_v = cbor.readText(data, p) catch return error.InvalidMstNode; 909 + p = key_v.end; 910 + const value = cbor.readCidLink(data, p) catch return error.InvalidMstNode; 911 + p = value.end; 889 912 890 913 return .{ 891 - .key_suffix = key_suffix, 892 - .prefix_len = @intCast(prefix_len), 893 - .tree = tree, 894 - .value = value, 914 + .entry = .{ 915 + .key_suffix = key_suffix.val, 916 + .prefix_len = @intCast(prefix_len.val), 917 + .tree = tree_result.val, 918 + .value = value.val, 919 + }, 920 + .end = p, 895 921 }; 896 922 } 897 923 898 - const MstReader = struct { 899 - data: []const u8, 900 - pos: usize, 901 - 902 - fn expectMap(self: *MstReader) !usize { 903 - return self.readMajorWithArg(5); 904 - } 905 - 906 - fn expectArray(self: *MstReader) !usize { 907 - return self.readMajorWithArg(4); 908 - } 909 - 910 - fn readTextString(self: *MstReader) ![]const u8 { 911 - const len = try self.readMajorWithArg(3); 912 - if (self.pos + len > self.data.len) return error.InvalidMstNode; 913 - const result = self.data[self.pos .. self.pos + len]; 914 - self.pos += len; 915 - return result; 916 - } 917 - 918 - fn readByteString(self: *MstReader) ![]const u8 { 919 - const len = try self.readMajorWithArg(2); 920 - if (self.pos + len > self.data.len) return error.InvalidMstNode; 921 - const result = self.data[self.pos .. self.pos + len]; 922 - self.pos += len; 923 - return result; 924 - } 925 - 926 - fn readUnsigned(self: *MstReader) !u64 { 927 - return self.readMajorWithArg(0); 928 - } 929 - 930 - fn readCidOrNull(self: *MstReader) !?[]const u8 { 931 - if (self.pos >= self.data.len) return error.InvalidMstNode; 932 - if (self.data[self.pos] == 0xf6) { 933 - self.pos += 1; 934 - return null; 935 - } 936 - return try self.readCid(); 937 - } 924 + const CidOrNullResult = struct { 925 + val: ?[]const u8, 926 + end: usize, 927 + }; 938 928 939 - fn readCid(self: *MstReader) ![]const u8 { 940 - // tag(42) encodes as 0xd8 0x2a 941 - if (self.pos + 1 >= self.data.len) return error.InvalidMstNode; 942 - if (self.data[self.pos] != 0xd8 or self.data[self.pos + 1] != 0x2a) 943 - return error.InvalidMstNode; 944 - self.pos += 2; 945 - const bytes = try self.readByteString(); 946 - if (bytes.len < 1 or bytes[0] != 0x00) return error.InvalidMstNode; 947 - return bytes[1..]; // skip 0x00 identity multibase prefix 948 - } 949 - 950 - fn readMajorWithArg(self: *MstReader, expected_major: u3) !usize { 951 - if (self.pos >= self.data.len) return error.InvalidMstNode; 952 - const b = self.data[self.pos]; 953 - self.pos += 1; 954 - const major: u3 = @truncate(b >> 5); 955 - if (major != expected_major) return error.InvalidMstNode; 956 - const additional: u5 = @truncate(b); 957 - return self.readArgValue(additional); 958 - } 959 - 960 - fn readArgValue(self: *MstReader, additional: u5) !usize { 961 - if (additional < 24) return @as(usize, additional); 962 - if (additional == 24) { 963 - if (self.pos >= self.data.len) return error.InvalidMstNode; 964 - const val = self.data[self.pos]; 965 - self.pos += 1; 966 - return @as(usize, val); 967 - } 968 - if (additional == 25) { 969 - if (self.pos + 2 > self.data.len) return error.InvalidMstNode; 970 - const val = std.mem.readInt(u16, self.data[self.pos..][0..2], .big); 971 - self.pos += 2; 972 - return @as(usize, val); 973 - } 974 - if (additional == 26) { 975 - if (self.pos + 4 > self.data.len) return error.InvalidMstNode; 976 - const val = std.mem.readInt(u32, self.data[self.pos..][0..4], .big); 977 - self.pos += 4; 978 - return @as(usize, val); 979 - } 980 - return error.InvalidMstNode; 981 - } 982 - }; 929 + fn readCidOrNull(data: []const u8, pos: usize) !CidOrNullResult { 930 + if (pos >= data.len) return error.InvalidMstNode; 931 + if (data[pos] == 0xf6) return .{ .val = null, .end = pos + 1 }; 932 + const cid_result = cbor.readCidLink(data, pos) catch return error.InvalidMstNode; 933 + return .{ .val = cid_result.val, .end = cid_result.end }; 934 + } 983 935 984 936 pub const MstDecodeError = error{InvalidMstNode} || Allocator.Error; 985 937