Skip to content

proposal: bytes: add Buffer.Peek #73794

Open
@icholy

Description

@icholy

Proposal Details

Add a Peek method to bytes.Buffer to avoid unnecessary wrapping when passing a buffer to image.Decode.

package bytes

// Peek returns the next n bytes without advancing the buffer.
// If there are fewer than n bytes in the buffer, it returns error [io.EOF].
// The slice is only valid until the next buffer modification.
func (b *Buffer) Peek(n int) ([]byte, error)

See:

Activity

added this to the Proposal milestone on May 20, 2025
added a commit that references this issue on May 20, 2025
a364508
linked a pull request that will close this issue on May 20, 2025
gopherbot

gopherbot commented on May 20, 2025

@gopherbot
Contributor

Change https://go.dev/cl/674415 mentions this issue: bytes: add Buffer.Peek

gabyhelp

gabyhelp commented on May 20, 2025

@gabyhelp

Related Issues

Related Code Changes

(Emoji vote if this was helpful or unhelpful; more detailed feedback welcome in this discussion.)

added
LibraryProposalIssues describing a requested change to the Go standard library or x/ libraries, but not to a tool
on May 20, 2025
added a commit that references this issue on May 20, 2025
9183579
moved this to Incoming in Proposalson May 20, 2025
CAFxX

CAFxX commented on May 20, 2025

@CAFxX
Contributor

Or maybe we can just add something like this?

func asReader(r io.Reader) reader {
	if rr, ok := r.(reader); ok {
		return rr
	} else if bb, ok := r.(*bytes.Buffer); ok {
		return bytesBufferAdapter{bb}
	}
	return bufio.NewReader(r)
}

type bytesBufferAdapter struct{ *bytes.Buffer }

func (a bytesBufferAdapter) Peek(n int) ([]byte, error) {
	b := a.Bytes()
	if len(b) < n {
		return b, io.EOF
	}
	return b[:n], nil
}

bufio already imports bytes anyway.

Alternatively you could just do the same when passing the *bytes.Buffer...

apparentlymart

apparentlymart commented on May 20, 2025

@apparentlymart

I think this functionality makes sense, but I was initially confused between this and the existing Buffer.AvailableBuffer method, since the noun "buffer" is representing all sorts of different things here!

In retrospect I guess I might've named Buffer.AvailableBuffer as Buffer.ExtraCapacity instead, to distinguish more strongly between the active part of the buffer and its tail of unused additional capacity.

But since that ship has already sailed, perhaps this can be addressed with just some careful wording in the documentation, possibly including an analogy to Buffer.Read.

Thinking down that path made me also wonder about a slightly different behavior:

  • If there's at least one byte remaining in the buffer, returns a slice covering either the first n bytes of the buffer or the entire buffer (whichever is shortest) and no error.
  • If there are zero bytes remaining in the buffer, returns io.EOF.

This definition makes it more directly analogous to Read, such that it could potentially be defined as "Like Buffer.Read, except that it does not advance the buffer's read position.".

That would make it slightly different than the current reader.Peek in package image, but it seems like the code that uses it would tolerate a "short peek" already:

go/src/image/format.go

Lines 59 to 69 in c8bf388

func match(magic string, b []byte) bool {
if len(magic) != len(b) {
return false
}
for i, c := range b {
if magic[i] != c && magic[i] != '?' {
return false
}
}
return true
}

(the if len(magic) != len(b) branch handles that case)

icholy

icholy commented on Jun 2, 2025

@icholy
Author

Related to: #63548

dsnet

dsnet commented on Jun 3, 2025

@dsnet
Member

A user could inject the Peek method themselves, but I think this is pointing to the fact that we should codify something like #63548. TIL I learned that the "image" package had functionality done that.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    LibraryProposalIssues describing a requested change to the Go standard library or x/ libraries, but not to a toolProposal

    Type

    No type

    Projects

    Status

    Incoming

    Relationships

    None yet

      Development

      Participants

      @apparentlymart@CAFxX@icholy@dsnet@gopherbot

      Issue actions

        proposal: bytes: add Buffer.Peek · Issue #73794 · golang/go