Skip to content

Commit 815075c

Browse files
authored
Merge pull request #151 from EdwardX29/ctx-decompress-into
add Ctx.DecompressInto for decompression of payloads with known sizes
2 parents 091c219 + 9fc0c52 commit 815075c

File tree

2 files changed

+51
-8
lines changed

2 files changed

+51
-8
lines changed

zstd_ctx.go

Lines changed: 21 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,15 @@ type Ctx interface {
2424
// prevent allocation. If it is too small, or if nil is passed, a new buffer
2525
// will be allocated and returned.
2626
Decompress(dst, src []byte) ([]byte, error)
27+
28+
// DecompressInto decompresses src into dst. Unlike Decompress, DecompressInto
29+
// requires that dst be sufficiently large to hold the decompressed payload.
30+
// DecompressInto may be used when the caller knows the size of the decompressed
31+
// payload before attempting decompression.
32+
//
33+
// It returns the number of bytes copied and an error if any is encountered. If
34+
// dst is too small, DecompressInto errors.
35+
DecompressInto(dst, src []byte) (int, error)
2736
}
2837

2938
type ctx struct {
@@ -104,14 +113,7 @@ func (c *ctx) Decompress(dst, src []byte) ([]byte, error) {
104113
dst = make([]byte, bound)
105114
}
106115

107-
written := int(C.ZSTD_decompressDCtx(
108-
c.dctx,
109-
unsafe.Pointer(&dst[0]),
110-
C.size_t(len(dst)),
111-
unsafe.Pointer(&src[0]),
112-
C.size_t(len(src))))
113-
114-
err := getError(written)
116+
written, err := c.DecompressInto(dst, src)
115117
if err == nil {
116118
return dst[:written], nil
117119
}
@@ -125,6 +127,17 @@ func (c *ctx) Decompress(dst, src []byte) ([]byte, error) {
125127
return ioutil.ReadAll(r)
126128
}
127129

130+
func (c *ctx) DecompressInto(dst, src []byte) (int, error) {
131+
written := int(C.ZSTD_decompressDCtx(
132+
c.dctx,
133+
unsafe.Pointer(&dst[0]),
134+
C.size_t(len(dst)),
135+
unsafe.Pointer(&src[0]),
136+
C.size_t(len(src))))
137+
err := getError(written)
138+
return written, err
139+
}
140+
128141
func finalizeCtx(c *ctx) {
129142
C.ZSTD_freeCCtx(c.cctx)
130143
C.ZSTD_freeDCtx(c.dctx)

zstd_ctx_test.go

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,36 @@ func TestCtxDecompressZeroLengthBuf(t *testing.T) {
118118
}
119119
}
120120

121+
func TestCtxCompressDecompressInto(t *testing.T) {
122+
ctx := NewCtx()
123+
payload := []byte("Hello World!")
124+
compressed, err := ctx.Compress(make([]byte, CompressBound(len(payload))), payload)
125+
if err != nil {
126+
t.Fatalf("Error while compressing: %v", err)
127+
}
128+
t.Logf("Compressed: %v", compressed)
129+
130+
// We know the size of the payload; construct a buffer that perfectly fits
131+
// the payload and use DecompressInto.
132+
decompressed := make([]byte, len(payload))
133+
if n, err := ctx.DecompressInto(decompressed, compressed); err != nil {
134+
t.Fatalf("error while decompressing into buffer of size %d: %v",
135+
len(decompressed), err)
136+
} else if n != len(decompressed) {
137+
t.Errorf("Ctx.DecompressedInto = (%d, nil), want (%d, nil)", n, len(decompressed))
138+
}
139+
if !bytes.Equal(payload, decompressed) {
140+
t.Fatalf("Ctx.DecompressInto(_, Ctx.Compress(_, %q)) yielded %q, want %q", payload, decompressed, payload)
141+
}
142+
143+
// Ensure that decompressing into a buffer too small errors appropriately.
144+
smallBuffer := make([]byte, len(payload)-1)
145+
if _, err := ctx.DecompressInto(smallBuffer, compressed); !IsDstSizeTooSmallError(err) {
146+
t.Fatalf("Ctx.DecompressInto(<%d-sized buffer>, Ctx.Compress(_, %q)) = %v, want 'Destination buffer is too small'",
147+
len(smallBuffer), payload, err)
148+
}
149+
}
150+
121151
func TestCtxTooSmall(t *testing.T) {
122152
ctx := NewCtx()
123153

0 commit comments

Comments
 (0)