// Copyright 2024 The Erigon Authors
// This file is part of Erigon.
//
// Erigon is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Erigon is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with Erigon. If not, see <http://www.gnu.org/licenses/>.

package cbor

import (
	"io"

	"github.com/ugorji/go/codec"

	"github.com/erigontech/erigon/common/log/v3"
)

var logger = log.New("package", "cbor")

// Pool of decoders
var decoderPool = make(chan *codec.Decoder, 128)

func Decoder(r io.Reader) *codec.Decoder {
	var d *codec.Decoder
	select {
	case d = <-decoderPool:
		d.Reset(r)
	default:
	}
	if d == nil {
		var handle codec.CborHandle
		handle.ReaderBufferSize = 64 * 1024
		handle.ZeroCopy = true // if you need access to object outside of db transaction - please copy bytes before deserialization
		d = codec.NewDecoder(r, &handle)
	}
	return d
}

func returnDecoderToPool(d *codec.Decoder) {
	if d == nil {
		return
	}
	select {
	case decoderPool <- d:
	default:
		logger.Trace("Allowing decoder to be garbage collected, pool is full")
	}
}

// Pool of encoders
var encoderPool = make(chan *codec.Encoder, 128)

func Encoder(w io.Writer) *codec.Encoder {
	var e *codec.Encoder
	select {
	case e = <-encoderPool:
		e.Reset(w)
	default:
	}
	if e == nil {
		var handle codec.CborHandle
		handle.WriterBufferSize = 64 * 1024
		handle.StructToArray = true
		handle.OptimumSize = true
		handle.StringToRaw = true

		e = codec.NewEncoder(w, &handle)
	}
	return e
}

func returnEncoderToPool(e *codec.Encoder) {
	if e == nil {
		return
	}
	select {
	case encoderPool <- e:
	default:
		logger.Trace("Allowing encoder to be garbage collected, pool is full")
	}
}
