/*
 *
 * Copyright 2024 gRPC authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 */

package mem

import (
	
)

const (
	// 32 KiB is what io.Copy uses.
	readAllBufSize = 32 * 1024
)

// BufferSlice offers a means to represent data that spans one or more Buffer
// instances. A BufferSlice is meant to be immutable after creation, and methods
// like Ref create and return copies of the slice. This is why all methods have
// value receivers rather than pointer receivers.
//
// Note that any of the methods that read the underlying buffers such as Ref,
// Len or CopyTo etc., will panic if any underlying buffers have already been
// freed. It is recommended to not directly interact with any of the underlying
// buffers directly, rather such interactions should be mediated through the
// various methods on this type.
//
// By convention, any APIs that return (mem.BufferSlice, error) should reduce
// the burden on the caller by never returning a mem.BufferSlice that needs to
// be freed if the error is non-nil, unless explicitly stated.
type BufferSlice []Buffer

// Len returns the sum of the length of all the Buffers in this slice.
//
// # Warning
//
// Invoking the built-in len on a BufferSlice will return the number of buffers
// in the slice, and *not* the value returned by this function.
func ( BufferSlice) () int {
	var  int
	for ,  := range  {
		 += .Len()
	}
	return 
}

// Ref invokes Ref on each buffer in the slice.
func ( BufferSlice) () {
	for ,  := range  {
		.Ref()
	}
}

// Free invokes Buffer.Free() on each Buffer in the slice.
func ( BufferSlice) () {
	for ,  := range  {
		.Free()
	}
}

// CopyTo copies each of the underlying Buffer's data into the given buffer,
// returning the number of bytes copied. Has the same semantics as the copy
// builtin in that it will copy as many bytes as it can, stopping when either dst
// is full or s runs out of data, returning the minimum of s.Len() and len(dst).
func ( BufferSlice) ( []byte) int {
	 := 0
	for ,  := range  {
		 += copy([:], .ReadOnlyData())
	}
	return 
}

// Materialize concatenates all the underlying Buffer's data into a single
// contiguous buffer using CopyTo.
func ( BufferSlice) () []byte {
	 := .Len()
	if  == 0 {
		return nil
	}
	 := make([]byte, )
	.CopyTo()
	return 
}

// MaterializeToBuffer functions like Materialize except that it writes the data
// to a single Buffer pulled from the given BufferPool.
//
// As a special case, if the input BufferSlice only actually has one Buffer, this
// function simply increases the refcount before returning said Buffer. Freeing this
// buffer won't release it until the BufferSlice is itself released.
func ( BufferSlice) ( BufferPool) Buffer {
	if len() == 1 {
		[0].Ref()
		return [0]
	}
	 := .Len()
	if  == 0 {
		return emptyBuffer{}
	}
	 := .Get()
	.CopyTo(*)
	return NewBuffer(, )
}

// Reader returns a new Reader for the input slice after taking references to
// each underlying buffer.
func ( BufferSlice) () Reader {
	.Ref()
	return &sliceReader{
		data: ,
		len:  .Len(),
	}
}

// Reader exposes a BufferSlice's data as an io.Reader, allowing it to interface
// with other parts systems. It also provides an additional convenience method
// Remaining(), which returns the number of unread bytes remaining in the slice.
// Buffers will be freed as they are read.
type Reader interface {
	io.Reader
	io.ByteReader
	// Close frees the underlying BufferSlice and never returns an error. Subsequent
	// calls to Read will return (0, io.EOF).
	Close() error
	// Remaining returns the number of unread bytes remaining in the slice.
	Remaining() int
	// Reset frees the currently held buffer slice and starts reading from the
	// provided slice. This allows reusing the reader object.
	Reset(s BufferSlice)
}

type sliceReader struct {
	data BufferSlice
	len  int
	// The index into data[0].ReadOnlyData().
	bufferIdx int
}

func ( *sliceReader) () int {
	return .len
}

func ( *sliceReader) ( BufferSlice) {
	.data.Free()
	.Ref()
	.data = 
	.len = .Len()
	.bufferIdx = 0
}

func ( *sliceReader) () error {
	.data.Free()
	.data = nil
	.len = 0
	return nil
}

func ( *sliceReader) () bool {
	if len(.data) == 0 || .bufferIdx != len(.data[0].ReadOnlyData()) {
		return false
	}

	.data[0].Free()
	.data = .data[1:]
	.bufferIdx = 0
	return true
}

func ( *sliceReader) ( []byte) ( int,  error) {
	if .len == 0 {
		return 0, io.EOF
	}

	for len() != 0 && .len != 0 {
		// Copy as much as possible from the first Buffer in the slice into the
		// given byte slice.
		 := .data[0].ReadOnlyData()
		 := copy(, [.bufferIdx:])
		.len -=        // Reduce len by the number of bytes copied.
		.bufferIdx +=  // Increment the buffer index.
		 +=            // Increment the total number of bytes read.
		 = [:]    // Shrink the given byte slice.

		// If we have copied all the data from the first Buffer, free it and advance to
		// the next in the slice.
		.freeFirstBufferIfEmpty()
	}

	return , nil
}

func ( *sliceReader) () (byte, error) {
	if .len == 0 {
		return 0, io.EOF
	}

	// There may be any number of empty buffers in the slice, clear them all until a
	// non-empty buffer is reached. This is guaranteed to exit since r.len is not 0.
	for .freeFirstBufferIfEmpty() {
	}

	 := .data[0].ReadOnlyData()[.bufferIdx]
	.len--
	.bufferIdx++
	// Free the first buffer in the slice if the last byte was read
	.freeFirstBufferIfEmpty()
	return , nil
}

var _ io.Writer = (*writer)(nil)

type writer struct {
	buffers *BufferSlice
	pool    BufferPool
}

func ( *writer) ( []byte) ( int,  error) {
	 := Copy(, .pool)
	*.buffers = append(*.buffers, )
	return .Len(), nil
}

// NewWriter wraps the given BufferSlice and BufferPool to implement the
// io.Writer interface. Every call to Write copies the contents of the given
// buffer into a new Buffer pulled from the given pool and the Buffer is
// added to the given BufferSlice.
func ( *BufferSlice,  BufferPool) io.Writer {
	return &writer{buffers: , pool: }
}

// ReadAll reads from r until an error or EOF and returns the data it read.
// A successful call returns err == nil, not err == EOF. Because ReadAll is
// defined to read from src until EOF, it does not treat an EOF from Read
// as an error to be reported.
//
// Important: A failed call returns a non-nil error and may also return
// partially read buffers. It is the responsibility of the caller to free the
// BufferSlice returned, or its memory will not be reused.
func ( io.Reader,  BufferPool) (BufferSlice, error) {
	var  BufferSlice
	if ,  := .(io.WriterTo);  {
		// This is more optimal since wt knows the size of chunks it wants to
		// write and, hence, we can allocate buffers of an optimal size to fit
		// them. E.g. might be a single big chunk, and we wouldn't chop it
		// into pieces.
		 := NewWriter(&, )
		,  := .WriteTo()
		return , 
	}
:
	for {
		 := .Get(readAllBufSize)
		// We asked for 32KiB but may have been given a bigger buffer.
		// Use all of it if that's the case.
		* = (*)[:cap(*)]
		 := 0
		for {
			,  := .Read((*)[:])
			 += 
			if  != nil {
				if  == 0 {
					// Nothing in this buf, put it back
					.Put()
				} else {
					* = (*)[:]
					 = append(, NewBuffer(, ))
				}
				if  == io.EOF {
					 = nil
				}
				return , 
			}
			if len(*) ==  {
				 = append(, NewBuffer(, ))
				continue 
			}
		}
	}
}