| ... | ... | @@ -91,30 +91,64 @@ pub const Headers = struct { |
| 91 | 91 | /// |
| 92 | 92 | /// If the `owned` field is true, both name and value will be copied. |
| 93 | 93 | pub fn append(headers: *Headers, name: []const u8, value: []const u8) !void { |
| 94 | | const n = headers.list.items.len; |
| 94 | try headers.appendOwned(.{ .unowned = name }, .{ .unowned = value }); |
| 95 | } |
| 95 | 96 | |
| 96 | | const value_duped = if (headers.owned) try headers.allocator.dupe(u8, value) else value; |
| 97 | | errdefer if (headers.owned) headers.allocator.free(value_duped); |
| 97 | pub const OwnedString = union(enum) { |
| 98 | /// A string allocated by the `allocator` field. |
| 99 | owned: []u8, |
| 100 | /// A string to be copied by the `allocator` field. |
| 101 | unowned: []const u8, |
| 102 | }; |
| 98 | 103 | |
| 99 | | var entry = Field{ .name = undefined, .value = value_duped }; |
| 104 | /// Appends a header to the list. |
| 105 | /// |
| 106 | /// If the `owned` field is true, `name` and `value` will be copied if unowned. |
| 107 | pub fn appendOwned(headers: *Headers, name: OwnedString, value: OwnedString) !void { |
| 108 | const n = headers.list.items.len; |
| 109 | try headers.list.ensureUnusedCapacity(headers.allocator, 1); |
| 110 | |
| 111 | const owned_value = switch (value) { |
| 112 | .owned => |owned| owned, |
| 113 | .unowned => |unowned| if (headers.owned) |
| 114 | try headers.allocator.dupe(u8, unowned) |
| 115 | else |
| 116 | unowned, |
| 117 | }; |
| 118 | errdefer if (value == .unowned and headers.owned) headers.allocator.free(owned_value); |
| 119 | |
| 120 | var entry = Field{ .name = undefined, .value = owned_value }; |
| 121 | |
| 122 | if (headers.index.getEntry(switch (name) { |
| 123 | inline else => |string| string, |
| 124 | })) |kv| { |
| 125 | defer switch (name) { |
| 126 | .owned => |owned| headers.allocator.free(owned), |
| 127 | .unowned => {}, |
| 128 | }; |
| 100 | 129 | |
| 101 | | if (headers.index.getEntry(name)) |kv| { |
| 102 | 130 | entry.name = kv.key_ptr.*; |
| 103 | 131 | try kv.value_ptr.append(headers.allocator, n); |
| 104 | 132 | } else { |
| 105 | | const name_duped = if (headers.owned) try std.ascii.allocLowerString(headers.allocator, name) else name; |
| 106 | | errdefer if (headers.owned) headers.allocator.free(name_duped); |
| 133 | const owned_name = switch (name) { |
| 134 | .owned => |owned| owned, |
| 135 | .unowned => |unowned| if (headers.owned) |
| 136 | try std.ascii.allocLowerString(headers.allocator, unowned) |
| 137 | else |
| 138 | unowned, |
| 139 | }; |
| 140 | errdefer if (name == .unowned and headers.owned) headers.allocator.free(owned_name); |
| 107 | 141 | |
| 108 | | entry.name = name_duped; |
| 142 | entry.name = owned_name; |
| 109 | 143 | |
| 110 | 144 | var new_index = try HeaderIndexList.initCapacity(headers.allocator, 1); |
| 111 | 145 | errdefer new_index.deinit(headers.allocator); |
| 112 | 146 | |
| 113 | 147 | new_index.appendAssumeCapacity(n); |
| 114 | | try headers.index.put(headers.allocator, name_duped, new_index); |
| 148 | try headers.index.put(headers.allocator, owned_name, new_index); |
| 115 | 149 | } |
| 116 | 150 | |
| 117 | | try headers.list.append(headers.allocator, entry); |
| 151 | headers.list.appendAssumeCapacity(entry); |
| 118 | 152 | } |
| 119 | 153 | |
| 120 | 154 | /// Returns true if this list of headers contains the given name. |