package ioseqimport ()// Seq represents a sequence of byte slices. It's somewhat equivalent to// [Reader], although simpler in some respects.// See [SeqFromReader] and [ReaderFromSeq] for a way to convert// between [Seq] and [Reader].//// Each element in the sequence must have either a non-nil byte slice or// a non-nil error; a producer should never produce either (nil, nil) or// a non-nil slice and a non-nil error.//// The sequence always ends at the first error: if there are temporary// errors, it's up to the producer to deal with them.//// The code ranging over the sequence must not use the slice outside of// the loop or across iterations; that is, the receiver owns a slice// until that particular iteration ends.//// Callers must not mutate the slice. [TODO perhaps it might be OK to// allow callers to mutate, but not append to, the slice].typeSeq = iter.Seq2[[]byte, error]// SeqFromReader returns a [Seq] that reads from r, allocating one buffer// of the given size to do so unless r implements [WriterTo], in which// case no buffer is needed.func ( io.Reader, int) Seq {if , := .(io.WriterTo); {returnfunc( func([]byte, error) bool) { := true , := .WriteTo(writerFunc(func( []byte) (int, error) {if !(, nil) { = falsereturn0, ErrSequenceTerminated }returnlen(), nil }))if != nil && { (nil, ) } } }returnfunc( func([]byte, error) bool) { := make([]byte, )for { , := .Read()if != nil {if == io.EOF { = nil }// Note: we _could_ call slices.Clip on the buffer // here, but there's no particular reason to do so: // if the rest of the buffer is overwritten by the // consumer, it doesn't make any difference.if > 0 && !([:], nil) {return }if != nil { (nil, ) }return }if > 0 && !([:], nil) {return } } }}typewriterFuncfunc([]byte) (int, error)func ( writerFunc) ( []byte) (int, error) {return ()}// ReaderFromSeq converts an iterator into an io.ReadCloser.// Close must be called after the caller is done with the reader.func ( Seq) io.ReadCloser {return &iterReader{seq: , }}typeiterReaderstruct {seqSeqnextfunc() ([]byte, error, bool)closefunc()errerrordata []byte}// WriteTo implements [WriterTo].func ( *iterReader) ( io.Writer) (int64, error) {if .seq != nil {// Read hasn't been called yet, we can just use the // iterator directly, saving the cost of iter.Pull2. , := CopySeq(, .seq)// Subsequent reads should return EOF. .seq = func(func([]byte, error) bool) {}return , }returnio.Copy(, )}func ( *iterReader) ( []byte) (int, error) {if .seq != nil { .next, .close = iter.Pull2(.seq)// Can't use the fast path in WriteTo any more. .seq = nil }if .err != nil {return0, .err }iflen(.data) == 0 {varbool .data, .err, = .next()if ! { .err = io.EOF } } := copy(, .data) .data = .data[:]iflen(.data) > 0 {return , nil }return , .err}func ( *iterReader) () error {if .close != nil { .close() .close = nilif .err == nil { .err = io.EOF } }returnnil}// CopySeq is like [io.Copy] but reads over r writing// all the data to w. It returns the total number of bytes// read.func ( io.Writer, Seq) (int64, error) { := int64(0)for , := range {if != nil {return , } , := .Write() += int64()if != nil {return , } }return , nil}// SeqWriter returns a [Writer] that operates on the yield// function passed into a [Seq] iterator. Writes will succeed until// the iteration is terminated, upon which Write will return// [ErrSequenceTerminated].//// The returned Writer should not be used outside the scope// of the iterator function, following the same rules as any yield// function.//// If active is non-nil, it reflects the "active" status of the generator// and its value should be (but does not have to be) true initially.// yield will not be called when *active is false.// If yield returns false, *active will be set to false.//// The caller can use the value of *active to find out whether// the iterator is still active.func ( func([]byte, error) bool, *bool) io.Writer {if == nil { = new(bool) * = true }returnseqWriter{yield: ,active: , }}typeseqWriterstruct {yieldfunc([]byte, error) boolactive *bool}varErrSequenceTerminated = errors.New("sequence terminated")func ( seqWriter) ( []byte) (int, error) {if !*.active {return0, ErrSequenceTerminated }if !.yield(slices.Clip(), nil) { *.active = falsereturn0, ErrSequenceTerminated }returnlen(), nil}// PipeSeqThrough returns a Seq that iterates over the data written// by the function f to its argument Writer. The Writer implementation// that it returns will be written with the data read from seq.//// In other words, data read from seq will be "piped through" f,// resulting in a new Seq.func [ io.WriteCloser]( Seq, func( io.Writer) ) Seq {returnfunc( func([]byte, error) bool) { := func( io.WriteCloser, Seq) error {if , := CopySeq(, ); != nil {return }return .Close() } := true := (SeqWriter(, &))if := (, ); != nil && { (nil, ) } }}// PipeThrough calls f; all data written by f to its argument writer// will be made available on the returned ReadCloser; all data read from// f will be written to the writer implementation returned by f.//// In other words, it returns a reader that "pipes" the content from r// through f.func [ io.WriteCloser]( io.Reader, func(io.Writer) , int) io.ReadCloser { := SeqFromReader(, ) := PipeSeqThrough(, )returnReaderFromSeq()}// ReaderWithContent returns a [Reader] that calls the given function to generate the// data to be read. If the function returns an error, that error will// be returned from the reader.func ( func( io.Writer) error) io.ReadCloser {returnReaderFromSeq(func( func([]byte, error) bool) { := trueif := (SeqWriter(, &)); != nil && { (nil, ) } })}
The pages are generated with Goldsv0.7.6. (GOOS=linux GOARCH=amd64)