// Copyright 2024 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// Helper code for parsing a protocol buffer

package protolazy

import (
	
	
	

	
)

// BufferReader is a structure encapsulating a protobuf and a current position
type BufferReader struct {
	Buf []byte
	Pos int
}

// NewBufferReader creates a new BufferRead from a protobuf
func ( []byte) BufferReader {
	return BufferReader{Buf: , Pos: 0}
}

var errOutOfBounds = errors.New("protobuf decoding: out of bounds")
var errOverflow = errors.New("proto: integer overflow")

func ( *BufferReader) () ( uint64,  error) {
	 := .Pos
	 := len(.Buf)

	for  := uint(0);  < 64;  += 7 {
		if  >=  {
			 = io.ErrUnexpectedEOF
			return
		}
		 := .Buf[]
		++
		 |= (uint64() & 0x7F) << 
		if  < 0x80 {
			.Pos = 
			return
		}
	}

	// The number is too large to represent in a 64-bit value.
	 = errOverflow
	return
}

// decodeVarint decodes a varint at the current position
func ( *BufferReader) () ( uint64,  error) {
	 := .Pos
	 := .Buf

	if  >= len() {
		return 0, io.ErrUnexpectedEOF
	} else if [] < 0x80 {
		.Pos++
		return uint64([]), nil
	} else if len()- < 10 {
		return .DecodeVarintSlow()
	}

	var  uint64
	// we already checked the first byte
	 = uint64([]) & 127
	++

	 = uint64([])
	++
	 |= ( & 127) << 7
	if  < 128 {
		goto 
	}

	 = uint64([])
	++
	 |= ( & 127) << 14
	if  < 128 {
		goto 
	}

	 = uint64([])
	++
	 |= ( & 127) << 21
	if  < 128 {
		goto 
	}

	 = uint64([])
	++
	 |= ( & 127) << 28
	if  < 128 {
		goto 
	}

	 = uint64([])
	++
	 |= ( & 127) << 35
	if  < 128 {
		goto 
	}

	 = uint64([])
	++
	 |= ( & 127) << 42
	if  < 128 {
		goto 
	}

	 = uint64([])
	++
	 |= ( & 127) << 49
	if  < 128 {
		goto 
	}

	 = uint64([])
	++
	 |= ( & 127) << 56
	if  < 128 {
		goto 
	}

	 = uint64([])
	++
	 |= ( & 127) << 63
	if  < 128 {
		goto 
	}

	return 0, errOverflow

:
	.Pos = 
	return
}

// decodeVarint32 decodes a varint32 at the current position
func ( *BufferReader) () ( uint32,  error) {
	 := .Pos
	 := .Buf

	if  >= len() {
		return 0, io.ErrUnexpectedEOF
	} else if [] < 0x80 {
		.Pos++
		return uint32([]), nil
	} else if len()- < 5 {
		,  := .DecodeVarintSlow()
		return uint32(), 
	}

	var  uint32
	// we already checked the first byte
	 = uint32([]) & 127
	++

	 = uint32([])
	++
	 |= ( & 127) << 7
	if  < 128 {
		goto 
	}

	 = uint32([])
	++
	 |= ( & 127) << 14
	if  < 128 {
		goto 
	}

	 = uint32([])
	++
	 |= ( & 127) << 21
	if  < 128 {
		goto 
	}

	 = uint32([])
	++
	 |= ( & 127) << 28
	if  < 128 {
		goto 
	}

	return 0, errOverflow

:
	.Pos = 
	return
}

// skipValue skips a value in the protobuf, based on the specified tag
func ( *BufferReader) ( uint32) ( error) {
	 :=  & 0x7
	switch protowire.Type() {
	case protowire.VarintType:
		 = .SkipVarint()
	case protowire.Fixed64Type:
		 = .SkipFixed64()
	case protowire.BytesType:
		var  uint32
		,  = .DecodeVarint32()
		if  == nil {
			 = .Skip(int())
		}
	case protowire.StartGroupType:
		 = .SkipGroup()
	case protowire.Fixed32Type:
		 = .SkipFixed32()
	default:
		 = fmt.Errorf("Unexpected wire type (%d)", )
	}
	return
}

// skipGroup skips a group with the specified tag.  It executes efficiently using a tag stack
func ( *BufferReader) ( uint32) ( error) {
	 := make([]uint32, 0, 16)
	 = append(, )
	var  uint32
	for len() > 0 {
		,  = .DecodeVarint32()
		if  != nil {
			return 
		}
		switch protowire.Type( & 0x7) {
		case protowire.VarintType:
			 = .SkipVarint()
		case protowire.Fixed64Type:
			 = .Skip(8)
		case protowire.BytesType:
			,  = .DecodeVarint32()
			if  == nil {
				 = .Skip(int())
			}
		case protowire.StartGroupType:
			 = append(, )
		case protowire.Fixed32Type:
			 = .SkipFixed32()
		case protowire.EndGroupType:
			if protoFieldNumber([len()-1]) == protoFieldNumber() {
				 = [:len()-1]
			} else {
				 = fmt.Errorf("end group tag %d does not match begin group tag %d at pos %d",
					protoFieldNumber(), protoFieldNumber([len()-1]), .Pos)
			}
		}
		if  != nil {
			return 
		}
	}
	return nil
}

// skipVarint effiently skips a varint
func ( *BufferReader) () ( error) {
	 := .Pos

	if len(.Buf)- < 10 {
		// Use DecodeVarintSlow() to check for buffer overflow, but ignore result
		if ,  := .DecodeVarintSlow();  != nil {
			return 
		}
		return nil
	}

	if .Buf[] < 0x80 {
		goto 
	}
	++

	if .Buf[] < 0x80 {
		goto 
	}
	++

	if .Buf[] < 0x80 {
		goto 
	}
	++

	if .Buf[] < 0x80 {
		goto 
	}
	++

	if .Buf[] < 0x80 {
		goto 
	}
	++

	if .Buf[] < 0x80 {
		goto 
	}
	++

	if .Buf[] < 0x80 {
		goto 
	}
	++

	if .Buf[] < 0x80 {
		goto 
	}
	++

	if .Buf[] < 0x80 {
		goto 
	}
	++

	if .Buf[] < 0x80 {
		goto 
	}
	return errOverflow

:
	.Pos =  + 1
	return nil
}

// skip skips the specified number of bytes
func ( *BufferReader) ( int) ( error) {
	if len(.Buf) < .Pos+ {
		return io.ErrUnexpectedEOF
	}
	.Pos += 
	return
}

// skipFixed64 skips a fixed64
func ( *BufferReader) () ( error) {
	return .Skip(8)
}

// skipFixed32 skips a fixed32
func ( *BufferReader) () ( error) {
	return .Skip(4)
}

// skipBytes skips a set of bytes
func ( *BufferReader) () ( error) {
	,  := .DecodeVarint32()
	if  != nil {
		return 
	}
	return .Skip(int())
}

// Done returns whether we are at the end of the protobuf
func ( *BufferReader) () bool {
	return .Pos == len(.Buf)
}

// Remaining returns how many bytes remain
func ( *BufferReader) () int {
	return len(.Buf) - .Pos
}