package relayproto

import 

// errVarintEnd is returned when a buffer is too short to hold a varint.
var errVarintEnd = errors.New("relayproto: unexpected end decoding varint")

// QUIC variable-length integers per RFC 9000 §16: the two most-significant bits
// of the first byte select a 1/2/4/8-byte length (prefixes 0b00/01/10/11).

// varintLen returns the number of bytes needed to encode v as a QUIC varint.
func varintLen( uint64) int {
	switch {
	case  < 1<<6:
		return 1
	case  < 1<<14:
		return 2
	case  < 1<<30:
		return 4
	case  < 1<<62:
		return 8
	default:
		panic("relayproto: varint too large")
	}
}

// appendVarint appends v to dst as a QUIC varint.
func appendVarint( []byte,  uint64) []byte {
	switch varintLen() {
	case 1:
		return append(, byte())
	case 2:
		return append(, byte(>>8)|0x40, byte())
	case 4:
		return append(,
			byte(>>24)|0x80, byte(>>16), byte(>>8), byte())
	default: // 8
		return append(,
			byte(>>56)|0xc0, byte(>>48), byte(>>40), byte(>>32),
			byte(>>24), byte(>>16), byte(>>8), byte())
	}
}

// readVarint reads a QUIC varint from the front of buf, returning the value and
// the remaining bytes.
func readVarint( []byte) (uint64, []byte, error) {
	if len() == 0 {
		return 0, nil, errVarintEnd
	}
	 := [0] >> 6
	 := 1 <<  // 1, 2, 4, or 8 bytes
	if len() <  {
		return 0, nil, errVarintEnd
	}
	 := uint64([0] & 0x3f)
	for  := 1;  < ; ++ {
		 = <<8 | uint64([])
	}
	return , [:], nil
}

// postcard uses LEB128 (unsigned little-endian base-128) varints for lengths and
// integers, which is a different encoding from the QUIC varints above. The relay
// datagram framing uses QUIC varints (for frame types); the handshake frame
// bodies are postcard, so their length prefixes use these.

// appendPostcardVarint appends v to dst as a postcard/LEB128 varint.
func appendPostcardVarint( []byte,  uint64) []byte {
	for  >= 0x80 {
		 = append(, byte()|0x80)
		 >>= 7
	}
	return append(, byte())
}

// readPostcardVarint reads a postcard/LEB128 varint from the front of buf.
func readPostcardVarint( []byte) (uint64, []byte, error) {
	var  uint64
	for  := 0;  < len(); ++ {
		 := []
		 |= uint64(&0x7f) << (7 * )
		if  < 0x80 {
			return , [+1:], nil
		}
		if  >= 9 {
			break
		}
	}
	return 0, nil, errVarintEnd
}

// EcnCodepoint is the QUIC explicit-congestion-notification codepoint carried in
// a relayed datagram (RFC 9000 §13.4 / IP ECN field values).
type EcnCodepoint uint8

const (
	// EcnEct1 is ECT(1).
	EcnEct1 EcnCodepoint = 1
	// EcnEct0 is ECT(0).
	EcnEct0 EcnCodepoint = 2
	// EcnCe is CE (congestion experienced).
	EcnCe EcnCodepoint = 3
)

// ecnFromBits returns the EcnCodepoint for the low two bits of b, or (0, false)
// for Not-ECT.
func ecnFromBits( uint8) (EcnCodepoint, bool) {
	switch  & 0b11 {
	case 1:
		return EcnEct1, true
	case 2:
		return EcnEct0, true
	case 3:
		return EcnCe, true
	default:
		return 0, false
	}
}