package parquet

import (
	
	
	
	
	

	
)

// ReadMode is an enum that is used to configure the way that a File reads pages.
type ReadMode int

const (
	ReadModeSync  ReadMode = iota // ReadModeSync reads pages synchronously on demand (Default).
	ReadModeAsync                 // ReadModeAsync reads pages asynchronously in the background.
)

const (
	DefaultColumnIndexSizeLimit = 16
	DefaultColumnBufferCapacity = 16 * 1024
	DefaultPageBufferSize       = 256 * 1024
	DefaultWriteBufferSize      = 32 * 1024
	DefaultDataPageVersion      = 2
	DefaultDataPageStatistics   = false
	DefaultSkipPageIndex        = false
	DefaultSkipBloomFilters     = false
	DefaultMaxRowsPerRowGroup   = math.MaxInt64
	DefaultReadMode             = ReadModeSync
)

const (
	parquetGoModulePath = "github.com/parquet-go/parquet-go"
)

var (
	defaultCreatedByInfo string
	defaultCreatedByOnce sync.Once
)

func defaultCreatedBy() string {
	defaultCreatedByOnce.Do(func() {
		 := parquetGoModulePath
		,  := debug.ReadBuildInfo()
		if  {
			for ,  := range .Deps {
				if .Replace == nil && .Path == parquetGoModulePath {
					, ,  := parseModuleVersion(.Version)
					 = formatCreatedBy(, , )
					break
				}
			}
		}
		defaultCreatedByInfo = 
	})
	return defaultCreatedByInfo
}

func parseModuleVersion( string) (, ,  string) {
	,  = splitModuleVersion()
	,  = splitModuleVersion()
	, _ = splitModuleVersion()
	 = strings.TrimPrefix(, "v")
	return
}

func splitModuleVersion( string) (,  string) {
	if  := strings.IndexByte(, '-');  < 0 {
		 = 
	} else {
		,  = [:], [+1:]
	}
	return
}

func formatCreatedBy(, ,  string) string {
	return  + " version " +  + "(build " +  + ")"
}

// The FileConfig type carries configuration options for parquet files.
//
// FileConfig implements the FileOption interface so it can be used directly
// as argument to the OpenFile function when needed, for example:
//
//	f, err := parquet.OpenFile(reader, size, &parquet.FileConfig{
//		SkipPageIndex:    true,
//		SkipBloomFilters: true,
//		ReadMode:         ReadModeAsync,
//	})
type FileConfig struct {
	SkipPageIndex    bool
	SkipBloomFilters bool
	ReadBufferSize   int
	ReadMode         ReadMode
	Schema           *Schema
}

// DefaultFileConfig returns a new FileConfig value initialized with the
// default file configuration.
func () *FileConfig {
	return &FileConfig{
		SkipPageIndex:    DefaultSkipPageIndex,
		SkipBloomFilters: DefaultSkipBloomFilters,
		ReadBufferSize:   defaultReadBufferSize,
		ReadMode:         DefaultReadMode,
		Schema:           nil,
	}
}

// NewFileConfig constructs a new file configuration applying the options passed
// as arguments.
//
// The function returns an non-nil error if some of the options carried invalid
// configuration values.
func ( ...FileOption) (*FileConfig, error) {
	 := DefaultFileConfig()
	.Apply(...)
	return , .Validate()
}

// Apply applies the given list of options to c.
func ( *FileConfig) ( ...FileOption) {
	for ,  := range  {
		.ConfigureFile()
	}
}

// ConfigureFile applies configuration options from c to config.
func ( *FileConfig) ( *FileConfig) {
	* = FileConfig{
		SkipPageIndex:    .SkipPageIndex,
		SkipBloomFilters: .SkipBloomFilters,
		ReadBufferSize:   coalesceInt(.ReadBufferSize, .ReadBufferSize),
		ReadMode:         ReadMode(coalesceInt(int(.ReadMode), int(.ReadMode))),
		Schema:           coalesceSchema(.Schema, .Schema),
	}
}

// Validate returns a non-nil error if the configuration of c is invalid.
func ( *FileConfig) () error {
	return nil
}

// The ReaderConfig type carries configuration options for parquet readers.
//
// ReaderConfig implements the ReaderOption interface so it can be used directly
// as argument to the NewReader function when needed, for example:
//
//	reader := parquet.NewReader(output, schema, &parquet.ReaderConfig{
//		// ...
//	})
type ReaderConfig struct {
	Schema *Schema
}

// DefaultReaderConfig returns a new ReaderConfig value initialized with the
// default reader configuration.
func () *ReaderConfig {
	return &ReaderConfig{}
}

// NewReaderConfig constructs a new reader configuration applying the options
// passed as arguments.
//
// The function returns an non-nil error if some of the options carried invalid
// configuration values.
func ( ...ReaderOption) (*ReaderConfig, error) {
	 := DefaultReaderConfig()
	.Apply(...)
	return , .Validate()
}

// Apply applies the given list of options to c.
func ( *ReaderConfig) ( ...ReaderOption) {
	for ,  := range  {
		.ConfigureReader()
	}
}

// ConfigureReader applies configuration options from c to config.
func ( *ReaderConfig) ( *ReaderConfig) {
	* = ReaderConfig{
		Schema: coalesceSchema(.Schema, .Schema),
	}
}

// Validate returns a non-nil error if the configuration of c is invalid.
func ( *ReaderConfig) () error {
	return nil
}

// The WriterConfig type carries configuration options for parquet writers.
//
// WriterConfig implements the WriterOption interface so it can be used directly
// as argument to the NewWriter function when needed, for example:
//
//	writer := parquet.NewWriter(output, schema, &parquet.WriterConfig{
//		CreatedBy: "my test program",
//	})
type WriterConfig struct {
	CreatedBy            string
	ColumnPageBuffers    BufferPool
	ColumnIndexSizeLimit int
	PageBufferSize       int
	WriteBufferSize      int
	DataPageVersion      int
	DataPageStatistics   bool
	MaxRowsPerRowGroup   int64
	KeyValueMetadata     map[string]string
	Schema               *Schema
	BloomFilters         []BloomFilterColumn
	Compression          compress.Codec
	Sorting              SortingConfig
	SkipPageBounds       [][]string
}

// DefaultWriterConfig returns a new WriterConfig value initialized with the
// default writer configuration.
func () *WriterConfig {
	return &WriterConfig{
		CreatedBy:            defaultCreatedBy(),
		ColumnPageBuffers:    &defaultColumnBufferPool,
		ColumnIndexSizeLimit: DefaultColumnIndexSizeLimit,
		PageBufferSize:       DefaultPageBufferSize,
		WriteBufferSize:      DefaultWriteBufferSize,
		DataPageVersion:      DefaultDataPageVersion,
		DataPageStatistics:   DefaultDataPageStatistics,
		MaxRowsPerRowGroup:   DefaultMaxRowsPerRowGroup,
		Sorting: SortingConfig{
			SortingBuffers: &defaultSortingBufferPool,
		},
	}
}

// NewWriterConfig constructs a new writer configuration applying the options
// passed as arguments.
//
// The function returns an non-nil error if some of the options carried invalid
// configuration values.
func ( ...WriterOption) (*WriterConfig, error) {
	 := DefaultWriterConfig()
	.Apply(...)
	return , .Validate()
}

// Apply applies the given list of options to c.
func ( *WriterConfig) ( ...WriterOption) {
	for ,  := range  {
		.ConfigureWriter()
	}
}

// ConfigureWriter applies configuration options from c to config.
func ( *WriterConfig) ( *WriterConfig) {
	 := .KeyValueMetadata
	if len(.KeyValueMetadata) > 0 {
		if  == nil {
			 = make(map[string]string, len(.KeyValueMetadata))
		}
		for ,  := range .KeyValueMetadata {
			[] = 
		}
	}

	* = WriterConfig{
		CreatedBy:            coalesceString(.CreatedBy, .CreatedBy),
		ColumnPageBuffers:    coalesceBufferPool(.ColumnPageBuffers, .ColumnPageBuffers),
		ColumnIndexSizeLimit: coalesceInt(.ColumnIndexSizeLimit, .ColumnIndexSizeLimit),
		PageBufferSize:       coalesceInt(.PageBufferSize, .PageBufferSize),
		WriteBufferSize:      coalesceInt(.WriteBufferSize, .WriteBufferSize),
		DataPageVersion:      coalesceInt(.DataPageVersion, .DataPageVersion),
		DataPageStatistics:   coalesceBool(.DataPageStatistics, .DataPageStatistics),
		MaxRowsPerRowGroup:   coalesceInt64(.MaxRowsPerRowGroup, .MaxRowsPerRowGroup),
		KeyValueMetadata:     ,
		Schema:               coalesceSchema(.Schema, .Schema),
		BloomFilters:         coalesceBloomFilters(.BloomFilters, .BloomFilters),
		Compression:          coalesceCompression(.Compression, .Compression),
		Sorting:              coalesceSortingConfig(.Sorting, .Sorting),
	}
}

// Validate returns a non-nil error if the configuration of c is invalid.
func ( *WriterConfig) () error {
	const  = "parquet.(*WriterConfig)."
	return errorInvalidConfiguration(
		validateNotNil(+"ColumnPageBuffers", .ColumnPageBuffers),
		validatePositiveInt(+"ColumnIndexSizeLimit", .ColumnIndexSizeLimit),
		validatePositiveInt(+"PageBufferSize", .PageBufferSize),
		validateOneOfInt(+"DataPageVersion", .DataPageVersion, 1, 2),
		.Sorting.Validate(),
	)
}

// The RowGroupConfig type carries configuration options for parquet row groups.
//
// RowGroupConfig implements the RowGroupOption interface so it can be used
// directly as argument to the NewBuffer function when needed, for example:
//
//	buffer := parquet.NewBuffer(&parquet.RowGroupConfig{
//		ColumnBufferCapacity: 10_000,
//	})
type RowGroupConfig struct {
	ColumnBufferCapacity int
	Schema               *Schema
	Sorting              SortingConfig
}

// DefaultRowGroupConfig returns a new RowGroupConfig value initialized with the
// default row group configuration.
func () *RowGroupConfig {
	return &RowGroupConfig{
		ColumnBufferCapacity: DefaultColumnBufferCapacity,
		Sorting: SortingConfig{
			SortingBuffers: &defaultSortingBufferPool,
		},
	}
}

// NewRowGroupConfig constructs a new row group configuration applying the
// options passed as arguments.
//
// The function returns an non-nil error if some of the options carried invalid
// configuration values.
func ( ...RowGroupOption) (*RowGroupConfig, error) {
	 := DefaultRowGroupConfig()
	.Apply(...)
	return , .Validate()
}

// Validate returns a non-nil error if the configuration of c is invalid.
func ( *RowGroupConfig) () error {
	const  = "parquet.(*RowGroupConfig)."
	return errorInvalidConfiguration(
		validatePositiveInt(+"ColumnBufferCapacity", .ColumnBufferCapacity),
		.Sorting.Validate(),
	)
}

func ( *RowGroupConfig) ( ...RowGroupOption) {
	for ,  := range  {
		.ConfigureRowGroup()
	}
}

func ( *RowGroupConfig) ( *RowGroupConfig) {
	* = RowGroupConfig{
		ColumnBufferCapacity: coalesceInt(.ColumnBufferCapacity, .ColumnBufferCapacity),
		Schema:               coalesceSchema(.Schema, .Schema),
		Sorting:              coalesceSortingConfig(.Sorting, .Sorting),
	}
}

// The SortingConfig type carries configuration options for parquet row groups.
//
// SortingConfig implements the SortingOption interface so it can be used
// directly as argument to the NewSortingWriter function when needed,
// for example:
//
//	buffer := parquet.NewSortingWriter[Row](
//		parquet.SortingWriterConfig(
//			parquet.DropDuplicatedRows(true),
//		),
//	})
type SortingConfig struct {
	SortingBuffers     BufferPool
	SortingColumns     []SortingColumn
	DropDuplicatedRows bool
}

// DefaultSortingConfig returns a new SortingConfig value initialized with the
// default row group configuration.
func () *SortingConfig {
	return &SortingConfig{
		SortingBuffers: &defaultSortingBufferPool,
	}
}

// NewSortingConfig constructs a new sorting configuration applying the
// options passed as arguments.
//
// The function returns an non-nil error if some of the options carried invalid
// configuration values.
func ( ...SortingOption) (*SortingConfig, error) {
	 := DefaultSortingConfig()
	.Apply(...)
	return , .Validate()
}

func ( *SortingConfig) () error {
	const  = "parquet.(*SortingConfig)."
	return errorInvalidConfiguration(
		validateNotNil(+"SortingBuffers", .SortingBuffers),
	)
}

func ( *SortingConfig) ( ...SortingOption) {
	for ,  := range  {
		.ConfigureSorting()
	}
}

func ( *SortingConfig) ( *SortingConfig) {
	* = coalesceSortingConfig(*, *)
}

// FileOption is an interface implemented by types that carry configuration
// options for parquet files.
type FileOption interface {
	ConfigureFile(*FileConfig)
}

// ReaderOption is an interface implemented by types that carry configuration
// options for parquet readers.
type ReaderOption interface {
	ConfigureReader(*ReaderConfig)
}

// WriterOption is an interface implemented by types that carry configuration
// options for parquet writers.
type WriterOption interface {
	ConfigureWriter(*WriterConfig)
}

// RowGroupOption is an interface implemented by types that carry configuration
// options for parquet row groups.
type RowGroupOption interface {
	ConfigureRowGroup(*RowGroupConfig)
}

// SortingOption is an interface implemented by types that carry configuration
// options for parquet sorting writers.
type SortingOption interface {
	ConfigureSorting(*SortingConfig)
}

// SkipPageIndex is a file configuration option which prevents automatically
// reading the page index when opening a parquet file, when set to true. This is
// useful as an optimization when programs know that they will not need to
// consume the page index.
//
// Defaults to false.
func ( bool) FileOption {
	return fileOption(func( *FileConfig) { .SkipPageIndex =  })
}

// SkipBloomFilters is a file configuration option which prevents automatically
// reading the bloom filters when opening a parquet file, when set to true.
// This is useful as an optimization when programs know that they will not need
// to consume the bloom filters.
//
// Defaults to false.
func ( bool) FileOption {
	return fileOption(func( *FileConfig) { .SkipBloomFilters =  })
}

// FileReadMode is a file configuration option which controls the way pages
// are read. Currently the only two options are ReadModeAsync and ReadModeSync
// which control whether or not pages are loaded asynchronously. It can be
// advantageous to use ReadModeAsync if your reader is backed by network
// storage.
//
// Defaults to ReadModeSync.
func ( ReadMode) FileOption {
	return fileOption(func( *FileConfig) { .ReadMode =  })
}

// ReadBufferSize is a file configuration option which controls the default
// buffer sizes for reads made to the provided io.Reader. The default of 4096
// is appropriate for disk based access but if your reader is backed by network
// storage it can be advantageous to increase this value to something more like
// 4 MiB.
//
// Defaults to 4096.
func ( int) FileOption {
	return fileOption(func( *FileConfig) { .ReadBufferSize =  })
}

// FileSchema is used to pass a known schema in while opening a Parquet file.
// This optimization is only useful if your application is currently opening
// an extremely large number of parquet files with the same, known schema.
//
// Defaults to nil.
func ( *Schema) FileOption {
	return fileOption(func( *FileConfig) { .Schema =  })
}

// PageBufferSize configures the size of column page buffers on parquet writers.
//
// Note that the page buffer size refers to the in-memory buffers where pages
// are generated, not the size of pages after encoding and compression.
// This design choice was made to help control the amount of memory needed to
// read and write pages rather than controlling the space used by the encoded
// representation on disk.
//
// Defaults to 256KiB.
func ( int) WriterOption {
	return writerOption(func( *WriterConfig) { .PageBufferSize =  })
}

// WriteBufferSize configures the size of the write buffer.
//
// Setting the writer buffer size to zero deactivates buffering, all writes are
// immediately sent to the output io.Writer.
//
// Defaults to 32KiB.
func ( int) WriterOption {
	return writerOption(func( *WriterConfig) { .WriteBufferSize =  })
}

// MaxRowsPerRowGroup configures the maximum number of rows that a writer will
// produce in each row group.
//
// This limit is useful to control size of row groups in both number of rows and
// byte size. While controlling the byte size of a row group is difficult to
// achieve with parquet due to column encoding and compression, the number of
// rows remains a useful proxy.
//
// Defaults to unlimited.
func ( int64) WriterOption {
	if  <= 0 {
		 = DefaultMaxRowsPerRowGroup
	}
	return writerOption(func( *WriterConfig) { .MaxRowsPerRowGroup =  })
}

// CreatedBy creates a configuration option which sets the name of the
// application that created a parquet file.
//
// The option formats the "CreatedBy" file metadata according to the convention
// described by the parquet spec:
//
//	"<application> version <version> (build <build>)"
//
// By default, the option is set to the parquet-go module name, version, and
// build hash.
func (, ,  string) WriterOption {
	 := formatCreatedBy(, , )
	return writerOption(func( *WriterConfig) { .CreatedBy =  })
}

// ColumnPageBuffers creates a configuration option to customize the buffer pool
// used when constructing row groups. This can be used to provide on-disk buffers
// as swap space to ensure that the parquet file creation will no be bottlenecked
// on the amount of memory available.
//
// Defaults to using in-memory buffers.
func ( BufferPool) WriterOption {
	return writerOption(func( *WriterConfig) { .ColumnPageBuffers =  })
}

// ColumnIndexSizeLimit creates a configuration option to customize the size
// limit of page boundaries recorded in column indexes.
//
// Defaults to 16.
func ( int) WriterOption {
	return writerOption(func( *WriterConfig) { .ColumnIndexSizeLimit =  })
}

// DataPageVersion creates a configuration option which configures the version of
// data pages used when creating a parquet file.
//
// Defaults to version 2.
func ( int) WriterOption {
	return writerOption(func( *WriterConfig) { .DataPageVersion =  })
}

// DataPageStatistics creates a configuration option which defines whether data
// page statistics are emitted. This option is useful when generating parquet
// files that intend to be backward compatible with older readers which may not
// have the ability to load page statistics from the column index.
//
// Defaults to false.
func ( bool) WriterOption {
	return writerOption(func( *WriterConfig) { .DataPageStatistics =  })
}

// KeyValueMetadata creates a configuration option which adds key/value metadata
// to add to the metadata of parquet files.
//
// This option is additive, it may be used multiple times to add more than one
// key/value pair.
//
// Keys are assumed to be unique, if the same key is repeated multiple times the
// last value is retained. While the parquet format does not require unique keys,
// this design decision was made to optimize for the most common use case where
// applications leverage this extension mechanism to associate single values to
// keys. This may create incompatibilities with other parquet libraries, or may
// cause some key/value pairs to be lost when open parquet files written with
// repeated keys. We can revisit this decision if it ever becomes a blocker.
func (,  string) WriterOption {
	return writerOption(func( *WriterConfig) {
		if .KeyValueMetadata == nil {
			.KeyValueMetadata = map[string]string{: }
		} else {
			.KeyValueMetadata[] = 
		}
	})
}

// BloomFilters creates a configuration option which defines the bloom filters
// that parquet writers should generate.
//
// The compute and memory footprint of generating bloom filters for all columns
// of a parquet schema can be significant, so by default no filters are created
// and applications need to explicitly declare the columns that they want to
// create filters for.
func ( ...BloomFilterColumn) WriterOption {
	 = append([]BloomFilterColumn{}, ...)
	return writerOption(func( *WriterConfig) { .BloomFilters =  })
}

// Compression creates a configuration option which sets the default compression
// codec used by a writer for columns where none were defined.
func ( compress.Codec) WriterOption {
	return writerOption(func( *WriterConfig) { .Compression =  })
}

// SortingWriterConfig is a writer option which applies configuration specific
// to sorting writers.
func ( ...SortingOption) WriterOption {
	 = append([]SortingOption{}, ...)
	return writerOption(func( *WriterConfig) { .Sorting.Apply(...) })
}

// SkipPageBounds lists the path to a column that shouldn't have bounds written to the
// footer of the parquet file. This is useful for data blobs, like a raw html file,
// where the bounds are not meaningful.
//
// This option is additive, it may be used multiple times to skip multiple columns.
func ( ...string) WriterOption {
	return writerOption(func( *WriterConfig) { .SkipPageBounds = append(.SkipPageBounds, ) })
}

// ColumnBufferCapacity creates a configuration option which defines the size of
// row group column buffers.
//
// Defaults to 16384.
func ( int) RowGroupOption {
	return rowGroupOption(func( *RowGroupConfig) { .ColumnBufferCapacity =  })
}

// SortingRowGroupConfig is a row group option which applies configuration
// specific sorting row groups.
func ( ...SortingOption) RowGroupOption {
	 = append([]SortingOption{}, ...)
	return rowGroupOption(func( *RowGroupConfig) { .Sorting.Apply(...) })
}

// SortingColumns creates a configuration option which defines the sorting order
// of columns in a row group.
//
// The order of sorting columns passed as argument defines the ordering
// hierarchy; when elements are equal in the first column, the second column is
// used to order rows, etc...
func ( ...SortingColumn) SortingOption {
	// Make a copy so that we do not retain the input slice generated implicitly
	// for the variable argument list, and also avoid having a nil slice when
	// the option is passed with no sorting columns, so we can differentiate it
	// from it not being passed.
	 = append([]SortingColumn{}, ...)
	return sortingOption(func( *SortingConfig) { .SortingColumns =  })
}

// SortingBuffers creates a configuration option which sets the pool of buffers
// used to hold intermediary state when sorting parquet rows.
//
// Defaults to using in-memory buffers.
func ( BufferPool) SortingOption {
	return sortingOption(func( *SortingConfig) { .SortingBuffers =  })
}

// DropDuplicatedRows configures whether a sorting writer will keep or remove
// duplicated rows.
//
// Two rows are considered duplicates if the values of their all their sorting
// columns are equal.
//
// Defaults to false
func ( bool) SortingOption {
	return sortingOption(func( *SortingConfig) { .DropDuplicatedRows =  })
}

type fileOption func(*FileConfig)

func ( fileOption) ( *FileConfig) { () }

type readerOption func(*ReaderConfig)

func ( readerOption) ( *ReaderConfig) { () }

type writerOption func(*WriterConfig)

func ( writerOption) ( *WriterConfig) { () }

type rowGroupOption func(*RowGroupConfig)

func ( rowGroupOption) ( *RowGroupConfig) { () }

type sortingOption func(*SortingConfig)

func ( sortingOption) ( *SortingConfig) { () }

func coalesceBool(,  bool) bool {
	return  || 
}

func coalesceInt(,  int) int {
	if  != 0 {
		return 
	}
	return 
}

func coalesceInt64(,  int64) int64 {
	if  != 0 {
		return 
	}
	return 
}

func coalesceString(,  string) string {
	if  != "" {
		return 
	}
	return 
}

func coalesceBytes(,  []byte) []byte {
	if  != nil {
		return 
	}
	return 
}

func coalesceBufferPool(,  BufferPool) BufferPool {
	if  != nil {
		return 
	}
	return 
}

func coalesceSchema(,  *Schema) *Schema {
	if  != nil {
		return 
	}
	return 
}

func coalesceSortingColumns(,  []SortingColumn) []SortingColumn {
	if  != nil {
		return 
	}
	return 
}

func coalesceSortingConfig(,  SortingConfig) SortingConfig {
	return SortingConfig{
		SortingBuffers:     coalesceBufferPool(.SortingBuffers, .SortingBuffers),
		SortingColumns:     coalesceSortingColumns(.SortingColumns, .SortingColumns),
		DropDuplicatedRows: .DropDuplicatedRows,
	}
}

func coalesceBloomFilters(,  []BloomFilterColumn) []BloomFilterColumn {
	if  != nil {
		return 
	}
	return 
}

func coalesceCompression(,  compress.Codec) compress.Codec {
	if  != nil {
		return 
	}
	return 
}

func validatePositiveInt( string,  int) error {
	if  > 0 {
		return nil
	}
	return errorInvalidOptionValue(, )
}

func validatePositiveInt64( string,  int64) error {
	if  > 0 {
		return nil
	}
	return errorInvalidOptionValue(, )
}

func validateOneOfInt( string,  int,  ...int) error {
	for ,  := range  {
		if  ==  {
			return nil
		}
	}
	return errorInvalidOptionValue(, )
}

func validateNotNil( string,  interface{}) error {
	if  != nil {
		return nil
	}
	return errorInvalidOptionValue(, )
}

func errorInvalidOptionValue( string,  interface{}) error {
	return fmt.Errorf("invalid option value: %s: %v", , )
}

func errorInvalidConfiguration( ...error) error {
	var  *invalidConfiguration

	for ,  := range  {
		if  != nil {
			if  == nil {
				 = new(invalidConfiguration)
			}
			.reasons = append(.reasons, )
		}
	}

	if  != nil {
		return 
	}

	return nil
}

type invalidConfiguration struct {
	reasons []error
}

func ( *invalidConfiguration) () string {
	 := new(strings.Builder)
	for ,  := range .reasons {
		.WriteString(.Error())
		.WriteString("\n")
	}
	 := .String()
	if  != "" {
		 = [:len()-1]
	}
	return 
}

var (
	_ FileOption     = (*FileConfig)(nil)
	_ ReaderOption   = (*ReaderConfig)(nil)
	_ WriterOption   = (*WriterConfig)(nil)
	_ RowGroupOption = (*RowGroupConfig)(nil)
	_ SortingOption  = (*SortingConfig)(nil)
)