// Copyright (C) 2020-2021  Nexedi SA and Contributors.
//                          Kirill Smelkov <kirr@nexedi.com>
//
// This program is free software: you can Use, Study, Modify and Redistribute
// it under the terms of the GNU General Public License version 3, or (at your
// option) any later version, as published by the Free Software Foundation.
//
// You can also Link and Combine this program with other software covered by
// the terms of any of the Free Software licenses or any of the Open Source
// Initiative approved licenses and Convey the resulting work. Corresponding
// source of such a combination shall include the source code for all other
// software used.
//
// This program is distributed WITHOUT ANY WARRANTY; without even the implied
// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
//
// See COPYING file for full licensing terms.
// See https://www.nexedi.com/licensing for rationale and options.

package proto
// runtime glue for msgpack support

import (
	"fmt"

	"github.com/tinylib/msgp/msgp"
	"lab.nexedi.com/kirr/neo/go/neo/internal/msgpack"
)


// mstructDecodeError represents decode error when decoder was expecting
// tuple<nfield> for structure named path.
type mstructDecodeError struct {
	path string     // "Type.field.field"
	op   msgpack.Op // op we got
	opOk msgpack.Op // op expected
}

func (e *mstructDecodeError) Error() string {
	return fmt.Sprintf("decode: M: struct %s: got opcode %02x; expect %02x", e.path, e.op, e.opOk)
}


// mdecodeErr is called to normilize error when msgp.ReadXXX returns err when decoding path.
func mdecodeErr(path string, err error) error {
	if err == msgp.ErrShortBytes {
		return ErrDecodeOverflow
	}
	return &mdecodeError{path, err}
}
type mdecodeError struct {
	path string // "Type.field.field"
	err  error
}
func (e *mdecodeError) Error() string {
	return fmt.Sprintf("decode: M: %s: %s", e.path, e.err)
}

// mOpError represents decode error when decoder faces unexpected operation.
type mOpError struct {
	op        msgpack.Op   // op we got
	expectedv []msgpack.Op // expected was any op from expectedv
}
func (e *mOpError) Error() string {
	return fmt.Sprintf("got opcode %02x;  expected any from %02x", e.op, e.expectedv)
}
func mdecodeOpErr(path string, op msgpack.Op, expectedv ...msgpack.Op) error {
	return mdecodeErr(path+"/op", &mOpError{op, expectedv})
}

// mLen8Error represents decode error when decoder faces unexpected length in Bin8.
type mLen8Error struct {
	l, lOk byte // len we got and expected
}
func (e *mLen8Error) Error() string {
	return fmt.Sprintf("expected length %d;  got %d", e.lOk, e.l)
}
func mdecodeLen8Err(path string, l, lOk uint8) error {
	return mdecodeErr(path+"/len", &mLen8Error{l, lOk})
}


func mdecodeEnumTypeErr(path string, enumType, enumTypeOk byte) error {
	return mdecodeErr(path+"/enumType",
		fmt.Errorf("expected %d;  got %d", enumTypeOk, enumType))
}

func mdecodeEnumValueErr(path string, v byte) error {
	return mdecodeErr(path, fmt.Errorf("invalid enum payload %02x", v))
}
