// Bounds-checked little-endian reader over a byte slice, plus the matching
// writer helpers. Port of the Rust codec's cursor.rs; the read side rejects
// any length that exceeds the remaining input before allocating.

package rcpg

import (
	
	
	
	
)

type cursor struct {
	b   []byte
	pos int
}

func newCursor( []byte) *cursor {
	return &cursor{b: }
}

func ( *cursor) () int {
	return len(.b) - .pos
}

func ( *cursor) ( int) ([]byte, error) {
	if  < 0 || .remaining() <  {
		return nil, corruptf("unexpected end of input: need %d bytes at offset %d, have %d",
			, .pos, .remaining())
	}
	 := .b[.pos : .pos+]
	.pos += 
	return , nil
}

func ( *cursor) () (uint8, error) {
	,  := .take(1)
	if  != nil {
		return 0, 
	}
	return [0], nil
}

func ( *cursor) () (uint16, error) {
	,  := .take(2)
	if  != nil {
		return 0, 
	}
	return binary.LittleEndian.Uint16(), nil
}

func ( *cursor) () (uint32, error) {
	,  := .take(4)
	if  != nil {
		return 0, 
	}
	return binary.LittleEndian.Uint32(), nil
}

func ( *cursor) () (uint64, error) {
	,  := .take(8)
	if  != nil {
		return 0, 
	}
	return binary.LittleEndian.Uint64(), nil
}

func ( *cursor) () (int64, error) {
	,  := .u64()
	return int64(), 
}

func ( *cursor) () (float64, error) {
	,  := .u64()
	return math.Float64frombits(), 
}

// lenPrefix reads a u32 length that will be used to allocate elemSize-byte
// elements, rejecting lengths that exceed the remaining input (prevents huge
// allocations from corrupt length fields).
func ( *cursor) ( int) (int, error) {
	,  := .u32()
	if  != nil {
		return 0, 
	}
	 := int()
	 :=  * 
	if / !=  ||  > .remaining() {
		return 0, corruptf("declared length %d (%d bytes) exceeds remaining input %d at offset %d",
			, , .remaining(), .pos)
	}
	return , nil
}

func ( *cursor) () ([]uint32, error) {
	,  := .lenPrefix(4)
	if  != nil {
		return nil, 
	}
	,  := .take( * 4)
	if  != nil {
		return nil, 
	}
	 := make([]uint32, )
	for  := range  {
		[] = binary.LittleEndian.Uint32([*4:])
	}
	return , nil
}

func ( *cursor) () ([]int64, error) {
	,  := .lenPrefix(8)
	if  != nil {
		return nil, 
	}
	,  := .take( * 8)
	if  != nil {
		return nil, 
	}
	 := make([]int64, )
	for  := range  {
		[] = int64(binary.LittleEndian.Uint64([*8:]))
	}
	return , nil
}

func ( *cursor) () ([]float64, error) {
	,  := .lenPrefix(8)
	if  != nil {
		return nil, 
	}
	,  := .take( * 8)
	if  != nil {
		return nil, 
	}
	 := make([]float64, )
	for  := range  {
		[] = math.Float64frombits(binary.LittleEndian.Uint64([*8:]))
	}
	return , nil
}

func ( *cursor) () (string, error) {
	,  := .lenPrefix(1)
	if  != nil {
		return "", 
	}
	,  := .take()
	if  != nil {
		return "", 
	}
	if !utf8.Valid() {
		return "", corruptf("invalid utf8 at offset %d", .pos)
	}
	return string(), nil
}

// --- writer helpers ---------------------------------------------------------

// wLenPrefix writes a collection length as the format's u32 length prefix,
// erroring rather than silently truncating a length that exceeds u32 capacity
// (the on-disk format caps counts at 2^32-1).
func wLenPrefix( *bytes.Buffer,  int) error {
	if  < 0 || uint64() > math.MaxUint32 {
		return corruptf("length %d exceeds the format's u32 capacity", )
	}
	wU32(, uint32())
	return nil
}

func wU8( *bytes.Buffer,  uint8) {
	.WriteByte()
}

func wU16( *bytes.Buffer,  uint16) {
	.Write(binary.LittleEndian.AppendUint16(nil, ))
}

func wU32( *bytes.Buffer,  uint32) {
	.Write(binary.LittleEndian.AppendUint32(nil, ))
}

func wU64( *bytes.Buffer,  uint64) {
	.Write(binary.LittleEndian.AppendUint64(nil, ))
}

func wI64( *bytes.Buffer,  int64) {
	wU64(, uint64())
}

func wF64( *bytes.Buffer,  float64) {
	wU64(, math.Float64bits())
}

func wU32Vec( *bytes.Buffer,  []uint32) error {
	if  := wLenPrefix(, len());  != nil {
		return 
	}
	for ,  := range  {
		wU32(, )
	}
	return nil
}

func wString( *bytes.Buffer,  string) error {
	if  := wLenPrefix(, len());  != nil {
		return 
	}
	.WriteString()
	return nil
}