| ... | @@ -91,30 +91,64 @@ pub const Headers = struct { | ... | @@ -91,30 +91,64 @@ pub const Headers = struct { |
| 91 | /// | 91 | /// |
| 92 | /// If the `owned` field is true, both name and value will be copied. | 92 | /// If the `owned` field is true, both name and value will be copied. |
| 93 | pub fn append(headers: *Headers, name: []const u8, value: []const u8) !void { | 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 | pub const OwnedString = union(enum) { |
| 97 | errdefer if (headers.owned) headers.allocator.free(value_duped); | 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 | entry.name = kv.key_ptr.*; | 130 | entry.name = kv.key_ptr.*; |
| 103 | try kv.value_ptr.append(headers.allocator, n); | 131 | try kv.value_ptr.append(headers.allocator, n); |
| 104 | } else { | 132 | } else { |
| 105 | const name_duped = if (headers.owned) try std.ascii.allocLowerString(headers.allocator, name) else name; | 133 | const owned_name = switch (name) { |
| 106 | errdefer if (headers.owned) headers.allocator.free(name_duped); | 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 | var new_index = try HeaderIndexList.initCapacity(headers.allocator, 1); | 144 | var new_index = try HeaderIndexList.initCapacity(headers.allocator, 1); |
| 111 | errdefer new_index.deinit(headers.allocator); | 145 | errdefer new_index.deinit(headers.allocator); |
| 112 | | 146 | |
| 113 | new_index.appendAssumeCapacity(n); | 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 | /// Returns true if this list of headers contains the given name. | 154 | /// Returns true if this list of headers contains the given name. |