package parquet

import (
	
	
	
	
	
	
	
	
	

	
	
	
)

const (
	// 170 x sizeof(Value) = 4KB
	defaultValueBufferSize = 170

	offsetOfPtr  = unsafe.Offsetof(Value{}.ptr)
	offsetOfU64  = unsafe.Offsetof(Value{}.u64)
	offsetOfU32  = offsetOfU64 + firstByteOffsetOf32BitsValue
	offsetOfBool = offsetOfU64 + firstByteOffsetOfBooleanValue
)

// The Value type is similar to the reflect.Value abstraction of Go values, but
// for parquet values. Value instances wrap underlying Go values mapped to one
// of the parquet physical types.
//
// Value instances are small, immutable objects, and usually passed by value
// between function calls.
//
// The zero-value of Value represents the null parquet value.
type Value struct {
	// data
	ptr *byte
	u64 uint64
	// type
	kind int8 // XOR(Kind) so the zero-value is <null>
	// levels
	definitionLevel byte
	repetitionLevel byte
	columnIndex     int16 // XOR so the zero-value is -1
}

// ValueReader is an interface implemented by types that support reading
// batches of values.
type ValueReader interface {
	// Read values into the buffer passed as argument and return the number of
	// values read. When all values have been read, the error will be io.EOF.
	ReadValues([]Value) (int, error)
}

// ValueReaderAt is an interface implemented by types that support reading
// values at offsets specified by the application.
type ValueReaderAt interface {
	ReadValuesAt([]Value, int64) (int, error)
}

// ValueReaderFrom is an interface implemented by value writers to read values
// from a reader.
type ValueReaderFrom interface {
	ReadValuesFrom(ValueReader) (int64, error)
}

// ValueWriter is an interface implemented by types that support reading
// batches of values.
type ValueWriter interface {
	// Write values from the buffer passed as argument and returns the number
	// of values written.
	WriteValues([]Value) (int, error)
}

// ValueWriterTo is an interface implemented by value readers to write values to
// a writer.
type ValueWriterTo interface {
	WriteValuesTo(ValueWriter) (int64, error)
}

// ValueReaderFunc is a function type implementing the ValueReader interface.
type ValueReaderFunc func([]Value) (int, error)

func ( ValueReaderFunc) ( []Value) (int, error) { return () }

// ValueWriterFunc is a function type implementing the ValueWriter interface.
type ValueWriterFunc func([]Value) (int, error)

func ( ValueWriterFunc) ( []Value) (int, error) { return () }

// CopyValues copies values from src to dst, returning the number of values
// that were written.
//
// As an optimization, the reader and writer may choose to implement
// ValueReaderFrom and ValueWriterTo to provide their own copy logic.
//
// The function returns any error it encounters reading or writing pages, except
// for io.EOF from the reader which indicates that there were no more values to
// read.
func ( ValueWriter,  ValueReader) (int64, error) {
	return copyValues(, , nil)
}

func copyValues( ValueWriter,  ValueReader,  []Value) ( int64,  error) {
	if ,  := .(ValueWriterTo);  {
		return .WriteValuesTo()
	}

	if ,  := .(ValueReaderFrom);  {
		return .ReadValuesFrom()
	}

	if len() == 0 {
		 = make([]Value, defaultValueBufferSize)
	}

	defer clearValues()

	for {
		,  := .ReadValues()

		if  > 0 {
			,  := .WriteValues([:])
			 += int64()
			if  != nil {
				return , 
			}
		}

		if  != nil {
			if  == io.EOF {
				 = nil
			}
			return , 
		}

		if  == 0 {
			return , io.ErrNoProgress
		}
	}
}

// ValueOf constructs a parquet value from a Go value v.
//
// The physical type of the value is assumed from the Go type of v using the
// following conversion table:
//
//	Go type | Parquet physical type
//	------- | ---------------------
//	nil     | NULL
//	bool    | BOOLEAN
//	int8    | INT32
//	int16   | INT32
//	int32   | INT32
//	int64   | INT64
//	int     | INT64
//	uint8   | INT32
//	uint16  | INT32
//	uint32  | INT32
//	uint64  | INT64
//	uintptr | INT64
//	float32 | FLOAT
//	float64 | DOUBLE
//	string  | BYTE_ARRAY
//	[]byte  | BYTE_ARRAY
//	[*]byte | FIXED_LEN_BYTE_ARRAY
//
// When converting a []byte or [*]byte value, the underlying byte array is not
// copied; instead, the returned parquet value holds a reference to it.
//
// The repetition and definition levels of the returned value are both zero.
//
// The function panics if the Go value cannot be represented in parquet.
func ( interface{}) Value {
	 := Kind(-1)
	 := reflect.TypeOf()

	switch value := .(type) {
	case nil:
		return Value{}
	case uuid.UUID:
		return makeValueBytes(FixedLenByteArray, [:])
	case deprecated.Int96:
		return makeValueInt96()
	case time.Time:
		 = Int64
	}

	switch .Kind() {
	case reflect.Bool:
		 = Boolean
	case reflect.Int8, reflect.Int16, reflect.Int32, reflect.Uint8, reflect.Uint16, reflect.Uint32:
		 = Int32
	case reflect.Int64, reflect.Int, reflect.Uint64, reflect.Uint, reflect.Uintptr:
		 = Int64
	case reflect.Float32:
		 = Float
	case reflect.Float64:
		 = Double
	case reflect.String:
		 = ByteArray
	case reflect.Slice:
		if .Elem().Kind() == reflect.Uint8 {
			 = ByteArray
		}
	case reflect.Array:
		if .Elem().Kind() == reflect.Uint8 {
			 = FixedLenByteArray
		}
	}

	if  < 0 {
		panic("cannot create parquet value from go value of type " + .String())
	}

	return makeValue(, nil, reflect.ValueOf())
}

// NulLValue constructs a null value, which is the zero-value of the Value type.
func () Value { return Value{} }

// ZeroValue constructs a zero value of the given kind.
func ( Kind) Value { return makeValueKind() }

// BooleanValue constructs a BOOLEAN parquet value from the bool passed as
// argument.
func ( bool) Value { return makeValueBoolean() }

// Int32Value constructs a INT32 parquet value from the int32 passed as
// argument.
func ( int32) Value { return makeValueInt32() }

// Int64Value constructs a INT64 parquet value from the int64 passed as
// argument.
func ( int64) Value { return makeValueInt64() }

// Int96Value constructs a INT96 parquet value from the deprecated.Int96 passed
// as argument.
func ( deprecated.Int96) Value { return makeValueInt96() }

// FloatValue constructs a FLOAT parquet value from the float32 passed as
// argument.
func ( float32) Value { return makeValueFloat() }

// DoubleValue constructs a DOUBLE parquet value from the float64 passed as
// argument.
func ( float64) Value { return makeValueDouble() }

// ByteArrayValue constructs a BYTE_ARRAY parquet value from the byte slice
// passed as argument.
func ( []byte) Value { return makeValueBytes(ByteArray, ) }

// FixedLenByteArrayValue constructs a BYTE_ARRAY parquet value from the byte
// slice passed as argument.
func ( []byte) Value { return makeValueBytes(FixedLenByteArray, ) }

func makeValue( Kind,  *format.LogicalType,  reflect.Value) Value {
	if .Kind() == reflect.Interface {
		if .IsNil() {
			return Value{}
		}
		if  = .Elem(); .Kind() == reflect.Pointer && .IsNil() {
			return Value{}
		}
	}

	switch .Type() {
	case reflect.TypeOf(time.Time{}):
		 := Nanosecond.TimeUnit()
		if  != nil && .Timestamp != nil {
			 = .Timestamp.Unit
		}

		 := .Interface().(time.Time)
		var  int64
		switch {
		case .Millis != nil:
			 = .UnixMilli()
		case .Micros != nil:
			 = .UnixMicro()
		default:
			 = .UnixNano()
		}
		return makeValueInt64()
	}

	switch  {
	case Boolean:
		return makeValueBoolean(.Bool())

	case Int32:
		switch .Kind() {
		case reflect.Int8, reflect.Int16, reflect.Int32:
			return makeValueInt32(int32(.Int()))
		case reflect.Uint8, reflect.Uint16, reflect.Uint32:
			return makeValueInt32(int32(.Uint()))
		}

	case Int64:
		switch .Kind() {
		case reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Int:
			return makeValueInt64(.Int())
		case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uint, reflect.Uintptr:
			return makeValueUint64(.Uint())
		}

	case Int96:
		switch .Type() {
		case reflect.TypeOf(deprecated.Int96{}):
			return makeValueInt96(.Interface().(deprecated.Int96))
		}

	case Float:
		switch .Kind() {
		case reflect.Float32:
			return makeValueFloat(float32(.Float()))
		}

	case Double:
		switch .Kind() {
		case reflect.Float32, reflect.Float64:
			return makeValueDouble(.Float())
		}

	case ByteArray:
		switch .Kind() {
		case reflect.String:
			return makeValueString(, .String())
		case reflect.Slice:
			if .Type().Elem().Kind() == reflect.Uint8 {
				return makeValueBytes(, .Bytes())
			}
		}

	case FixedLenByteArray:
		switch .Kind() {
		case reflect.String: // uuid
			return makeValueString(, .String())
		case reflect.Array:
			if .Type().Elem().Kind() == reflect.Uint8 {
				return makeValueFixedLenByteArray()
			}
		case reflect.Slice:
			if .Type().Elem().Kind() == reflect.Uint8 {
				return makeValueBytes(, .Bytes())
			}
		}
	}

	panic("cannot create parquet value of type " + .String() + " from go value of type " + .Type().String())
}

func makeValueKind( Kind) Value {
	return Value{kind: ^int8()}
}

func makeValueBoolean( bool) Value {
	 := Value{kind: ^int8(Boolean)}
	if  {
		.u64 = 1
	}
	return 
}

func makeValueInt32( int32) Value {
	return Value{
		kind: ^int8(Int32),
		u64:  uint64(),
	}
}

func makeValueInt64( int64) Value {
	return Value{
		kind: ^int8(Int64),
		u64:  uint64(),
	}
}

func makeValueInt96( deprecated.Int96) Value {
	// TODO: this is highly inefficient because we need a heap allocation to
	// store the value; we don't expect INT96 to be used frequently since it
	// is a deprecated feature of parquet, and it helps keep the Value type
	// compact for all the other more common cases.
	 := [12]byte{}
	binary.LittleEndian.PutUint32([0:4], [0])
	binary.LittleEndian.PutUint32([4:8], [1])
	binary.LittleEndian.PutUint32([8:12], [2])
	return Value{
		kind: ^int8(Int96),
		ptr:  &[0],
		u64:  12, // set the length so we can use the ByteArray method
	}
}

func makeValueUint32( uint32) Value {
	return Value{
		kind: ^int8(Int32),
		u64:  uint64(),
	}
}

func makeValueUint64( uint64) Value {
	return Value{
		kind: ^int8(Int64),
		u64:  ,
	}
}

func makeValueFloat( float32) Value {
	return Value{
		kind: ^int8(Float),
		u64:  uint64(math.Float32bits()),
	}
}

func makeValueDouble( float64) Value {
	return Value{
		kind: ^int8(Double),
		u64:  math.Float64bits(),
	}
}

func makeValueBytes( Kind,  []byte) Value {
	return makeValueByteArray(, unsafe.SliceData(), len())
}

func makeValueString( Kind,  string) Value {
	return makeValueByteArray(, unsafe.StringData(), len())
}

func makeValueFixedLenByteArray( reflect.Value) Value {
	 := .Type()
	// When the array is addressable, we take advantage of this
	// condition to avoid the heap allocation otherwise needed
	// to pack the reference into an interface{} value.
	if .CanAddr() {
		 = .Addr()
	} else {
		 := reflect.New()
		.Elem().Set()
		 = 
	}
	return makeValueByteArray(FixedLenByteArray, (*byte)(.UnsafePointer()), .Len())
}

func makeValueByteArray( Kind,  *byte,  int) Value {
	return Value{
		kind: ^int8(),
		ptr:  ,
		u64:  uint64(),
	}
}

// These methods are internal versions of methods exported by the Value type,
// they are usually inlined by the compiler and intended to be used inside the
// parquet-go package because they tend to generate better code than their
// exported counter part, which requires making a copy of the receiver.
func ( *Value) () bool            { return .kind == 0 }
func ( *Value) () byte              { return byte(.u64) }
func ( *Value) () bool           { return .u64 != 0 }
func ( *Value) () int32            { return int32(.u64) }
func ( *Value) () int64            { return int64(.u64) }
func ( *Value) () deprecated.Int96 { return makeInt96(.byteArray()) }
func ( *Value) () float32          { return math.Float32frombits(uint32(.u64)) }
func ( *Value) () float64         { return math.Float64frombits(uint64(.u64)) }
func ( *Value) () uint32          { return uint32(.u64) }
func ( *Value) () uint64          { return .u64 }
func ( *Value) () []byte       { return unsafe.Slice(.ptr, .u64) }
func ( *Value) () string          { return unsafe.String(.ptr, .u64) }
func ( *Value) () *[16]byte        { return (*[16]byte)(unsafe.Pointer(.ptr)) }
func ( *Value) () int             { return int(^.columnIndex) }

func ( Value) ( bool) Value {
	.kind = ^int8(Boolean)
	.ptr = nil
	.u64 = 0
	if  {
		.u64 = 1
	}
	return 
}

func ( Value) ( int32) Value {
	.kind = ^int8(Int32)
	.ptr = nil
	.u64 = uint64()
	return 
}

func ( Value) ( int64) Value {
	.kind = ^int8(Int64)
	.ptr = nil
	.u64 = uint64()
	return 
}

func ( Value) ( deprecated.Int96) Value {
	 := makeValueInt96()
	.kind = .kind
	.ptr = .ptr
	.u64 = .u64
	return 
}

func ( Value) ( float32) Value {
	.kind = ^int8(Float)
	.ptr = nil
	.u64 = uint64(math.Float32bits())
	return 
}

func ( Value) ( float64) Value {
	.kind = ^int8(Double)
	.ptr = nil
	.u64 = math.Float64bits()
	return 
}

func ( Value) ( []byte) Value {
	.kind = ^int8(ByteArray)
	.ptr = unsafe.SliceData()
	.u64 = uint64(len())
	return 
}

func ( Value) ( []byte) Value {
	.kind = ^int8(FixedLenByteArray)
	.ptr = unsafe.SliceData()
	.u64 = uint64(len())
	return 
}

// Kind returns the kind of v, which represents its parquet physical type.
func ( Value) () Kind { return ^Kind(.kind) }

// IsNull returns true if v is the null value.
func ( Value) () bool { return .isNull() }

// Byte returns v as a byte, which may truncate the underlying byte.
func ( Value) () byte { return .byte() }

// Boolean returns v as a bool, assuming the underlying type is BOOLEAN.
func ( Value) () bool { return .boolean() }

// Int32 returns v as a int32, assuming the underlying type is INT32.
func ( Value) () int32 { return .int32() }

// Int64 returns v as a int64, assuming the underlying type is INT64.
func ( Value) () int64 { return .int64() }

// Int96 returns v as a int96, assuming the underlying type is INT96.
func ( Value) () deprecated.Int96 {
	var  deprecated.Int96
	if !.isNull() {
		 = .int96()
	}
	return 
}

// Float returns v as a float32, assuming the underlying type is FLOAT.
func ( Value) () float32 { return .float() }

// Double returns v as a float64, assuming the underlying type is DOUBLE.
func ( Value) () float64 { return .double() }

// Uint32 returns v as a uint32, assuming the underlying type is INT32.
func ( Value) () uint32 { return .uint32() }

// Uint64 returns v as a uint64, assuming the underlying type is INT64.
func ( Value) () uint64 { return .uint64() }

// ByteArray returns v as a []byte, assuming the underlying type is either
// BYTE_ARRAY or FIXED_LEN_BYTE_ARRAY.
//
// The application must treat the returned byte slice as a read-only value,
// mutating the content will result in undefined behaviors.
func ( Value) () []byte { return .byteArray() }

// RepetitionLevel returns the repetition level of v.
func ( Value) () int { return int(.repetitionLevel) }

// DefinitionLevel returns the definition level of v.
func ( Value) () int { return int(.definitionLevel) }

// Column returns the column index within the row that v was created from.
//
// Returns -1 if the value does not carry a column index.
func ( Value) () int { return .column() }

// Bytes returns the binary representation of v.
//
// If v is the null value, an nil byte slice is returned.
func ( Value) () []byte {
	switch .Kind() {
	case Boolean:
		 := [8]byte{}
		binary.LittleEndian.PutUint32([:4], .uint32())
		return [0:1]
	case Int32, Float:
		 := [8]byte{}
		binary.LittleEndian.PutUint32([:4], .uint32())
		return [:4]
	case Int64, Double:
		 := [8]byte{}
		binary.LittleEndian.PutUint64([:8], .uint64())
		return [:8]
	case ByteArray, FixedLenByteArray, Int96:
		return .byteArray()
	default:
		return nil
	}
}

// AppendBytes appends the binary representation of v to b.
//
// If v is the null value, b is returned unchanged.
func ( Value) ( []byte) []byte {
	 := [8]byte{}
	switch .Kind() {
	case Boolean:
		binary.LittleEndian.PutUint32([:4], .uint32())
		return append(, [0])
	case Int32, Float:
		binary.LittleEndian.PutUint32([:4], .uint32())
		return append(, [:4]...)
	case Int64, Double:
		binary.LittleEndian.PutUint64([:8], .uint64())
		return append(, [:8]...)
	case ByteArray, FixedLenByteArray, Int96:
		return append(, .byteArray()...)
	default:
		return 
	}
}

// Format outputs a human-readable representation of v to w, using r as the
// formatting verb to describe how the value should be printed.
//
// The following formatting options are supported:
//
//	%c	prints the column index
//	%+c	prints the column index, prefixed with "C:"
//	%d	prints the definition level
//	%+d	prints the definition level, prefixed with "D:"
//	%r	prints the repetition level
//	%+r	prints the repetition level, prefixed with "R:"
//	%q	prints the quoted representation of v
//	%+q	prints the quoted representation of v, prefixed with "V:"
//	%s	prints the string representation of v
//	%+s	prints the string representation of v, prefixed with "V:"
//	%v	same as %s
//	%+v	prints a verbose representation of v
//	%#v	prints a Go value representation of v
//
// Format satisfies the fmt.Formatter interface.
func ( Value) ( fmt.State,  rune) {
	switch  {
	case 'c':
		if .Flag('+') {
			io.WriteString(, "C:")
		}
		fmt.Fprint(, .column())

	case 'd':
		if .Flag('+') {
			io.WriteString(, "D:")
		}
		fmt.Fprint(, .definitionLevel)

	case 'r':
		if .Flag('+') {
			io.WriteString(, "R:")
		}
		fmt.Fprint(, .repetitionLevel)

	case 'q':
		if .Flag('+') {
			io.WriteString(, "V:")
		}
		switch .Kind() {
		case ByteArray, FixedLenByteArray:
			fmt.Fprintf(, "%q", .byteArray())
		default:
			fmt.Fprintf(, `"%s"`, )
		}

	case 's':
		if .Flag('+') {
			io.WriteString(, "V:")
		}
		switch .Kind() {
		case Boolean:
			fmt.Fprint(, .boolean())
		case Int32:
			fmt.Fprint(, .int32())
		case Int64:
			fmt.Fprint(, .int64())
		case Int96:
			fmt.Fprint(, .int96())
		case Float:
			fmt.Fprint(, .float())
		case Double:
			fmt.Fprint(, .double())
		case ByteArray, FixedLenByteArray:
			.Write(.byteArray())
		default:
			io.WriteString(, "<null>")
		}

	case 'v':
		switch {
		case .Flag('+'):
			fmt.Fprintf(, "%+[1]c %+[1]d %+[1]r %+[1]s", )
		case .Flag('#'):
			.formatGoString()
		default:
			.(, 's')
		}
	}
}

func ( Value) ( fmt.State) {
	io.WriteString(, "parquet.")
	switch .Kind() {
	case Boolean:
		fmt.Fprintf(, "BooleanValue(%t)", .boolean())
	case Int32:
		fmt.Fprintf(, "Int32Value(%d)", .int32())
	case Int64:
		fmt.Fprintf(, "Int64Value(%d)", .int64())
	case Int96:
		fmt.Fprintf(, "Int96Value(%#v)", .int96())
	case Float:
		fmt.Fprintf(, "FloatValue(%g)", .float())
	case Double:
		fmt.Fprintf(, "DoubleValue(%g)", .double())
	case ByteArray:
		fmt.Fprintf(, "ByteArrayValue(%q)", .byteArray())
	case FixedLenByteArray:
		fmt.Fprintf(, "FixedLenByteArrayValue(%#v)", .byteArray())
	default:
		io.WriteString(, "Value{}")
		return
	}
	fmt.Fprintf(, ".Level(%d,%d,%d)",
		.RepetitionLevel(),
		.DefinitionLevel(),
		.Column(),
	)
}

// String returns a string representation of v.
func ( Value) () string {
	switch .Kind() {
	case Boolean:
		return strconv.FormatBool(.boolean())
	case Int32:
		return strconv.FormatInt(int64(.int32()), 10)
	case Int64:
		return strconv.FormatInt(.int64(), 10)
	case Int96:
		return .Int96().String()
	case Float:
		return strconv.FormatFloat(float64(.float()), 'g', -1, 32)
	case Double:
		return strconv.FormatFloat(.double(), 'g', -1, 32)
	case ByteArray, FixedLenByteArray:
		return string(.byteArray())
	default:
		return "<null>"
	}
}

// GoString returns a Go value string representation of v.
func ( Value) () string { return fmt.Sprintf("%#v", ) }

// Level returns v with the repetition level, definition level, and column index
// set to the values passed as arguments.
//
// The method panics if either argument is negative.
func ( Value) (, ,  int) Value {
	.repetitionLevel = makeRepetitionLevel()
	.definitionLevel = makeDefinitionLevel()
	.columnIndex = ^makeColumnIndex()
	return 
}

// Clone returns a copy of v which does not share any pointers with it.
func ( Value) () Value {
	switch  := .Kind();  {
	case ByteArray, FixedLenByteArray:
		.ptr = unsafe.SliceData(copyBytes(.byteArray()))
	}
	return 
}

func makeInt96( []byte) ( deprecated.Int96) {
	return deprecated.Int96{
		2: binary.LittleEndian.Uint32([8:12]),
		1: binary.LittleEndian.Uint32([4:8]),
		0: binary.LittleEndian.Uint32([0:4]),
	}
}

func parseValue( Kind,  []byte) ( Value,  error) {
	switch  {
	case Boolean:
		if len() == 1 {
			 = makeValueBoolean([0] != 0)
		}
	case Int32:
		if len() == 4 {
			 = makeValueInt32(int32(binary.LittleEndian.Uint32()))
		}
	case Int64:
		if len() == 8 {
			 = makeValueInt64(int64(binary.LittleEndian.Uint64()))
		}
	case Int96:
		if len() == 12 {
			 = makeValueInt96(makeInt96())
		}
	case Float:
		if len() == 4 {
			 = makeValueFloat(float32(math.Float32frombits(binary.LittleEndian.Uint32())))
		}
	case Double:
		if len() == 8 {
			 = makeValueDouble(float64(math.Float64frombits(binary.LittleEndian.Uint64())))
		}
	case ByteArray, FixedLenByteArray:
		 = makeValueBytes(, )
	}
	if .isNull() {
		 = fmt.Errorf("cannot decode %s value from input of length %d", , len())
	}
	return , 
}

func copyBytes( []byte) []byte {
	 := make([]byte, len())
	copy(, )
	return 
}

// Equal returns true if v1 and v2 are equal.
//
// Values are considered equal if they are of the same physical type and hold
// the same Go values. For BYTE_ARRAY and FIXED_LEN_BYTE_ARRAY, the content of
// the underlying byte arrays are tested for equality.
//
// Note that the repetition levels, definition levels, and column indexes are
// not compared by this function, use DeepEqual instead.
func (,  Value) bool {
	if .kind != .kind {
		return false
	}
	switch ^Kind(.kind) {
	case Boolean:
		return .boolean() == .boolean()
	case Int32:
		return .int32() == .int32()
	case Int64:
		return .int64() == .int64()
	case Int96:
		return .int96() == .int96()
	case Float:
		return .float() == .float()
	case Double:
		return .double() == .double()
	case ByteArray, FixedLenByteArray:
		return bytes.Equal(.byteArray(), .byteArray())
	case -1: // null
		return true
	default:
		return false
	}
}

// DeepEqual returns true if v1 and v2 are equal, including their repetition
// levels, definition levels, and column indexes.
//
// See Equal for details about how value equality is determined.
func (,  Value) bool {
	return Equal(, ) &&
		.repetitionLevel == .repetitionLevel &&
		.definitionLevel == .definitionLevel &&
		.columnIndex == .columnIndex
}

var (
	_ fmt.Formatter = Value{}
	_ fmt.Stringer  = Value{}
)

func clearValues( []Value) {
	for  := range  {
		[] = Value{}
	}
}

// BooleanReader is an interface implemented by ValueReader instances which
// expose the content of a column of boolean values.
type BooleanReader interface {
	// Read boolean values into the buffer passed as argument.
	//
	// The method returns io.EOF when all values have been read.
	ReadBooleans(values []bool) (int, error)
}

// BooleanWriter is an interface implemented by ValueWriter instances which
// support writing columns of boolean values.
type BooleanWriter interface {
	// Write boolean values.
	//
	// The method returns the number of values written, and any error that
	// occurred while writing the values.
	WriteBooleans(values []bool) (int, error)
}

// Int32Reader is an interface implemented by ValueReader instances which expose
// the content of a column of int32 values.
type Int32Reader interface {
	// Read 32 bits integer values into the buffer passed as argument.
	//
	// The method returns io.EOF when all values have been read.
	ReadInt32s(values []int32) (int, error)
}

// Int32Writer is an interface implemented by ValueWriter instances which
// support writing columns of 32 bits signed integer values.
type Int32Writer interface {
	// Write 32 bits signed integer values.
	//
	// The method returns the number of values written, and any error that
	// occurred while writing the values.
	WriteInt32s(values []int32) (int, error)
}

// Int64Reader is an interface implemented by ValueReader instances which expose
// the content of a column of int64 values.
type Int64Reader interface {
	// Read 64 bits integer values into the buffer passed as argument.
	//
	// The method returns io.EOF when all values have been read.
	ReadInt64s(values []int64) (int, error)
}

// Int64Writer is an interface implemented by ValueWriter instances which
// support writing columns of 64 bits signed integer values.
type Int64Writer interface {
	// Write 64 bits signed integer values.
	//
	// The method returns the number of values written, and any error that
	// occurred while writing the values.
	WriteInt64s(values []int64) (int, error)
}

// Int96Reader is an interface implemented by ValueReader instances which expose
// the content of a column of int96 values.
type Int96Reader interface {
	// Read 96 bits integer values into the buffer passed as argument.
	//
	// The method returns io.EOF when all values have been read.
	ReadInt96s(values []deprecated.Int96) (int, error)
}

// Int96Writer is an interface implemented by ValueWriter instances which
// support writing columns of 96 bits signed integer values.
type Int96Writer interface {
	// Write 96 bits signed integer values.
	//
	// The method returns the number of values written, and any error that
	// occurred while writing the values.
	WriteInt96s(values []deprecated.Int96) (int, error)
}

// FloatReader is an interface implemented by ValueReader instances which expose
// the content of a column of single-precision floating point values.
type FloatReader interface {
	// Read single-precision floating point values into the buffer passed as
	// argument.
	//
	// The method returns io.EOF when all values have been read.
	ReadFloats(values []float32) (int, error)
}

// FloatWriter is an interface implemented by ValueWriter instances which
// support writing columns of single-precision floating point values.
type FloatWriter interface {
	// Write single-precision floating point values.
	//
	// The method returns the number of values written, and any error that
	// occurred while writing the values.
	WriteFloats(values []float32) (int, error)
}

// DoubleReader is an interface implemented by ValueReader instances which
// expose the content of a column of double-precision float point values.
type DoubleReader interface {
	// Read double-precision floating point values into the buffer passed as
	// argument.
	//
	// The method returns io.EOF when all values have been read.
	ReadDoubles(values []float64) (int, error)
}

// DoubleWriter is an interface implemented by ValueWriter instances which
// support writing columns of double-precision floating point values.
type DoubleWriter interface {
	// Write double-precision floating point values.
	//
	// The method returns the number of values written, and any error that
	// occurred while writing the values.
	WriteDoubles(values []float64) (int, error)
}

// ByteArrayReader is an interface implemented by ValueReader instances which
// expose the content of a column of variable length byte array values.
type ByteArrayReader interface {
	// Read values into the byte buffer passed as argument, returning the number
	// of values written to the buffer (not the number of bytes). Values are
	// written using the PLAIN encoding, each byte array prefixed with its
	// length encoded as a 4 bytes little endian unsigned integer.
	//
	// The method returns io.EOF when all values have been read.
	//
	// If the buffer was not empty, but too small to hold at least one value,
	// io.ErrShortBuffer is returned.
	ReadByteArrays(values []byte) (int, error)
}

// ByteArrayWriter is an interface implemented by ValueWriter instances which
// support writing columns of variable length byte array values.
type ByteArrayWriter interface {
	// Write variable length byte array values.
	//
	// The values passed as input must be laid out using the PLAIN encoding,
	// with each byte array prefixed with the four bytes little endian unsigned
	// integer length.
	//
	// The method returns the number of values written to the underlying column
	// (not the number of bytes), or any error that occurred while attempting to
	// write the values.
	WriteByteArrays(values []byte) (int, error)
}

// FixedLenByteArrayReader is an interface implemented by ValueReader instances
// which expose the content of a column of fixed length byte array values.
type FixedLenByteArrayReader interface {
	// Read values into the byte buffer passed as argument, returning the number
	// of values written to the buffer (not the number of bytes).
	//
	// The method returns io.EOF when all values have been read.
	//
	// If the buffer was not empty, but too small to hold at least one value,
	// io.ErrShortBuffer is returned.
	ReadFixedLenByteArrays(values []byte) (int, error)
}

// FixedLenByteArrayWriter is an interface implemented by ValueWriter instances
// which support writing columns of fixed length byte array values.
type FixedLenByteArrayWriter interface {
	// Writes the fixed length byte array values.
	//
	// The size of the values is assumed to be the same as the expected size of
	// items in the column. The method errors if the length of the input values
	// is not a multiple of the expected item size.
	WriteFixedLenByteArrays(values []byte) (int, error)
}