You are an expert in writing code in many different languages. Your goal is to perform code completion for the following code, keeping in mind the rest of the code and the file meta data.
    Metadata details:
    filename: decoder.go
    path of file: ./repos/moby/vendor/github.com/klauspost/compress/zstd
    
    the code of the file until where you have to start completion: // Copyright 2019+ Klaus Post. All rights reserved.
// License information can be found in the LICENSE file.
// Based on work by Yann Collet, released under BSD License.

package zstd

import (
	"context"
	"encoding/binary"
	"io"
	"sync"

	"github.com/klauspost/compress/zstd/internal/xxhash"
)

// Decoder provides decoding of zstandard streams.
// The decoder has been designed to operate without allocations after a warmup.
// This means that you should store the decoder for best performance.
// To re-use a stream decoder, use the Reset(r io.Reader) error to switch to another stream.
// A decoder can safely be re-used even if the previous stream failed.
// To release the resources, you must call the Close() function on a decoder.
type Decoder struct {
	o decoderOptions

	// Unreferenced decoders, ready for use.
	decoders chan *blockDec

	// Current read position used for Reader functionality.
	current decoderState

	// sync stream decoding
	syncStream struct {
		decodedFrame uint64
		br           readerWrapper
		enabled      bool
		inFrame      bool
		dstBuf       []byte
	}

	frame *frameDec

	// Custom dictionaries.
	dicts map[uint32]*dict

	// streamWg is the waitgroup for all streams
	streamWg sync.WaitGroup
}

// decoderState is used for maintaining state when the decoder
// is used for streaming.
type decoderState struct {
	// current block being written to stream.
	decodeOutput

	// output in order to be written to stream.
	output chan decodeOutput

	// cancel remaining output.
	cance
    
func (d *Decoder) nextBlockSync() (ok bool) {
	if d.current.d == nil {
		d.current.d = <-d.decoders
	}
	for len(d.current.b) == 0 {
		if !d.syncStream.inFrame {
			d.frame.history.reset()
			d.current.err = d.frame.reset(&d.syncStream.br)
			if d.current.err == nil {
				d.current.err = d.setDict(d.frame)
			}
			if d.current.err != nil {
				return false
			}
			if d.frame.WindowSize > d.o.maxDecodedSize || d.frame.WindowSize > d.o.maxWindowSize {
				d.current.err = ErrDecoderSizeExceeded
				return false
			}

			d.syncStream.decodedFrame = 0
			d.syncStream.inFrame = true
		}
		d.current.err = d.frame.next(d.current.d)
		if d.current.err != nil {
			return false
		}
		d.frame.history.ensureBlock()
		if debugDecoder {
			println("History trimmed:", len(d.frame.history.b), "decoded already:", d.syncStream.decodedFrame)
		}
		histBefore := len(d.frame.history.b)
		d.current.err = d.current.d.decodeBuf(&d.frame.history)

		if d.current.err != nil {
			println("error after:", d.current.err)
			return false
		}
		d.current.b = d.frame.history.b[histBefore:]
		if debugDecoder {
			println("history after:", len(d.frame.history.b))
		}

		// Check frame size (before CRC)
		d.syncStream.decodedFrame += uint64(len(d.current.b))
		if d.syncStream.decodedFrame > d.frame.FrameContentSize {
			if debugDecoder {
				printf("DecodedFrame (%d) > FrameContentSize (%d)\n", d.syncStream.decodedFrame, d.frame.FrameContentSize)
			}
			d.current.err = ErrFrameSizeExceeded
			return false
		}

		// Check FCS
		if d.current.d.Last && d.frame.FrameContentSize != fcsUnknown && d.syncStream.decodedFrame != d.frame.FrameContentSize {
			if debugDecoder {
				printf("DecodedFrame (%d) != FrameContentSize (%d)\n", d.syncStream.decodedFrame, d.frame.FrameContentSize)
			}
			d.current.err = ErrFrameSizeMismatch
			return false
		}

		// Update/Check CRC
		if d.frame.HasCheckSum {
			if !d.o.ignoreChecksum {
				d.frame.crc.Write(d.current.b)
			}
			if d.current.d.Last {
				if !d.o.ignoreChecksum {
					d.current.err = d.frame.checkCRC()
				} else {
					d.current.err = d.frame.consumeCRC()
				}
				if d.current.err != nil {
					println("CRC error:", d.current.err)
					return false
				}
			}
		}
		d.syncStream.inFrame = !d.current.d.Last
	}
	return true
}