streaming: create structure for loose object streams

As explained in a preceding commit, we want to get rid of the union of stream-type specific data in `struct odb_read_stream`. Create a new structure for loose object streams to move towards this design. Signed-off-by: Patrick Steinhardt <ps@pks.im> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Patrick Steinhardt committed Nov 23, 2025 at 19:59 UTC b7774c0f0de43379c40984b4ede265a512c1a4f0
1 file changed +44 -41
streaming.c
+44 -41
@@ -39,14 +39,6 @@ struct odb_read_stream {
39 enum { z_unused, z_used, z_done, z_error } z_state;
40
41 union {
42 - struct {
43 - void *mapped;
44 - unsigned long mapsize;
45 - char hdr[32];
46 - int hdr_avail;
47 - int hdr_used;
48 - } loose;
49 -
42 struct {
43 struct packed_git *pack;
44 off_t pos;
@@ -165,11 +157,21 @@ static struct odb_read_stream *attach_stream_filter(struct odb_read_stream *st,
157 *
158 *****************************************************************/
159
168 -static ssize_t read_istream_loose(struct odb_read_stream *st, char *buf, size_t sz)
160 +struct odb_loose_read_stream {
161 + struct odb_read_stream base;
162 + void *mapped;
163 + unsigned long mapsize;
164 + char hdr[32];
165 + int hdr_avail;
166 + int hdr_used;
167 +};
168 +
169 +static ssize_t read_istream_loose(struct odb_read_stream *_st, char *buf, size_t sz)
170 {
171 + struct odb_loose_read_stream *st = (struct odb_loose_read_stream *)_st;
172 size_t total_read = 0;
173
172 - switch (st->z_state) {
174 + switch (st->base.z_state) {
175 case z_done:
176 return 0;
177 case z_error:
@@ -178,42 +180,43 @@ static ssize_t read_istream_loose(struct odb_read_stream *st, char *buf, size_t
180 break;
181 }
182
181 - if (st->u.loose.hdr_used < st->u.loose.hdr_avail) {
182 - size_t to_copy = st->u.loose.hdr_avail - st->u.loose.hdr_used;
183 + if (st->hdr_used < st->hdr_avail) {
184 + size_t to_copy = st->hdr_avail - st->hdr_used;
185 if (sz < to_copy)
186 to_copy = sz;
185 - memcpy(buf, st->u.loose.hdr + st->u.loose.hdr_used, to_copy);
186 - st->u.loose.hdr_used += to_copy;
187 + memcpy(buf, st->hdr + st->hdr_used, to_copy);
188 + st->hdr_used += to_copy;
189 total_read += to_copy;
190 }
191
192 while (total_read < sz) {
193 int status;
194
193 - st->z.next_out = (unsigned char *)buf + total_read;
194 - st->z.avail_out = sz - total_read;
195 - status = git_inflate(&st->z, Z_FINISH);
195 + st->base.z.next_out = (unsigned char *)buf + total_read;
196 + st->base.z.avail_out = sz - total_read;
197 + status = git_inflate(&st->base.z, Z_FINISH);
198
197 - total_read = st->z.next_out - (unsigned char *)buf;
199 + total_read = st->base.z.next_out - (unsigned char *)buf;
200
201 if (status == Z_STREAM_END) {
200 - git_inflate_end(&st->z);
201 - st->z_state = z_done;
202 + git_inflate_end(&st->base.z);
203 + st->base.z_state = z_done;
204 break;
205 }
206 if (status != Z_OK && (status != Z_BUF_ERROR || total_read < sz)) {
205 - git_inflate_end(&st->z);
206 - st->z_state = z_error;
207 + git_inflate_end(&st->base.z);
208 + st->base.z_state = z_error;
209 return -1;
210 }
211 }
212 return total_read;
213 }
214
213 -static int close_istream_loose(struct odb_read_stream *st)
215 +static int close_istream_loose(struct odb_read_stream *_st)
216 {
215 - close_deflated_stream(st);
216 - munmap(st->u.loose.mapped, st->u.loose.mapsize);
217 + struct odb_loose_read_stream *st = (struct odb_loose_read_stream *)_st;
218 + close_deflated_stream(&st->base);
219 + munmap(st->mapped, st->mapsize);
220 return 0;
221 }
222
@@ -222,7 +225,7 @@ static int open_istream_loose(struct odb_read_stream **out,
225 const struct object_id *oid)
226 {
227 struct object_info oi = OBJECT_INFO_INIT;
225 - struct odb_read_stream *st;
228 + struct odb_loose_read_stream *st;
229 struct odb_source *source;
230 unsigned long mapsize;
231 void *mapped;
@@ -244,8 +247,8 @@ static int open_istream_loose(struct odb_read_stream **out,
247 */
248 CALLOC_ARRAY(st, 1);
249
247 - switch (unpack_loose_header(&st->z, mapped, mapsize, st->u.loose.hdr,
248 - sizeof(st->u.loose.hdr))) {
250 + switch (unpack_loose_header(&st->base.z, mapped, mapsize, st->hdr,
251 + sizeof(st->hdr))) {
252 case ULHR_OK:
253 break;
254 case ULHR_BAD:
@@ -253,26 +256,26 @@ static int open_istream_loose(struct odb_read_stream **out,
256 goto error;
257 }
258
256 - oi.sizep = &st->size;
257 - oi.typep = &st->type;
259 + oi.sizep = &st->base.size;
260 + oi.typep = &st->base.type;
261
259 - if (parse_loose_header(st->u.loose.hdr, &oi) < 0 || st->type < 0)
262 + if (parse_loose_header(st->hdr, &oi) < 0 || st->base.type < 0)
263 goto error;
264
262 - st->u.loose.mapped = mapped;
263 - st->u.loose.mapsize = mapsize;
264 - st->u.loose.hdr_used = strlen(st->u.loose.hdr) + 1;
265 - st->u.loose.hdr_avail = st->z.total_out;
266 - st->z_state = z_used;
267 - st->close = close_istream_loose;
268 - st->read = read_istream_loose;
265 + st->mapped = mapped;
266 + st->mapsize = mapsize;
267 + st->hdr_used = strlen(st->hdr) + 1;
268 + st->hdr_avail = st->base.z.total_out;
269 + st->base.z_state = z_used;
270 + st->base.close = close_istream_loose;
271 + st->base.read = read_istream_loose;
272
270 - *out = st;
273 + *out = &st->base;
274
275 return 0;
276 error:
274 - git_inflate_end(&st->z);
275 - munmap(st->u.loose.mapped, st->u.loose.mapsize);
277 + git_inflate_end(&st->base.z);
278 + munmap(st->mapped, st->mapsize);
279 free(st);
280 return -1;
281 }