mirror of
https://github.com/ceph/ceph-csi.git
synced 2024-09-19 15:09:56 +00:00
63c4c05b35
updating the kubernetes to 1.31.0 in the api folder. Signed-off-by: Madhu Rajanna <madhupr007@gmail.com>
300 lines
7.5 KiB
Go
300 lines
7.5 KiB
Go
package cbor
|
|
|
|
import (
|
|
"errors"
|
|
"fmt"
|
|
"reflect"
|
|
"sync"
|
|
)
|
|
|
|
// Tag represents CBOR tag data, including tag number and unmarshaled tag content. Marshaling and
|
|
// unmarshaling of tag content is subject to any encode and decode options that would apply to
|
|
// enclosed data item if it were to appear outside of a tag.
|
|
type Tag struct {
|
|
Number uint64
|
|
Content interface{}
|
|
}
|
|
|
|
// RawTag represents CBOR tag data, including tag number and raw tag content.
|
|
// RawTag implements Unmarshaler and Marshaler interfaces.
|
|
type RawTag struct {
|
|
Number uint64
|
|
Content RawMessage
|
|
}
|
|
|
|
// UnmarshalCBOR sets *t with tag number and raw tag content copied from data.
|
|
func (t *RawTag) UnmarshalCBOR(data []byte) error {
|
|
if t == nil {
|
|
return errors.New("cbor.RawTag: UnmarshalCBOR on nil pointer")
|
|
}
|
|
|
|
// Decoding CBOR null and undefined to cbor.RawTag is no-op.
|
|
if len(data) == 1 && (data[0] == 0xf6 || data[0] == 0xf7) {
|
|
return nil
|
|
}
|
|
|
|
d := decoder{data: data, dm: defaultDecMode}
|
|
|
|
// Unmarshal tag number.
|
|
typ, _, num := d.getHead()
|
|
if typ != cborTypeTag {
|
|
return &UnmarshalTypeError{CBORType: typ.String(), GoType: typeRawTag.String()}
|
|
}
|
|
t.Number = num
|
|
|
|
// Unmarshal tag content.
|
|
c := d.data[d.off:]
|
|
t.Content = make([]byte, len(c))
|
|
copy(t.Content, c)
|
|
return nil
|
|
}
|
|
|
|
// MarshalCBOR returns CBOR encoding of t.
|
|
func (t RawTag) MarshalCBOR() ([]byte, error) {
|
|
if t.Number == 0 && len(t.Content) == 0 {
|
|
// Marshal uninitialized cbor.RawTag
|
|
b := make([]byte, len(cborNil))
|
|
copy(b, cborNil)
|
|
return b, nil
|
|
}
|
|
|
|
e := getEncodeBuffer()
|
|
|
|
encodeHead(e, byte(cborTypeTag), t.Number)
|
|
|
|
content := t.Content
|
|
if len(content) == 0 {
|
|
content = cborNil
|
|
}
|
|
|
|
buf := make([]byte, len(e.Bytes())+len(content))
|
|
n := copy(buf, e.Bytes())
|
|
copy(buf[n:], content)
|
|
|
|
putEncodeBuffer(e)
|
|
return buf, nil
|
|
}
|
|
|
|
// DecTagMode specifies how decoder handles tag number.
|
|
type DecTagMode int
|
|
|
|
const (
|
|
// DecTagIgnored makes decoder ignore tag number (skips if present).
|
|
DecTagIgnored DecTagMode = iota
|
|
|
|
// DecTagOptional makes decoder verify tag number if it's present.
|
|
DecTagOptional
|
|
|
|
// DecTagRequired makes decoder verify tag number and tag number must be present.
|
|
DecTagRequired
|
|
|
|
maxDecTagMode
|
|
)
|
|
|
|
func (dtm DecTagMode) valid() bool {
|
|
return dtm >= 0 && dtm < maxDecTagMode
|
|
}
|
|
|
|
// EncTagMode specifies how encoder handles tag number.
|
|
type EncTagMode int
|
|
|
|
const (
|
|
// EncTagNone makes encoder not encode tag number.
|
|
EncTagNone EncTagMode = iota
|
|
|
|
// EncTagRequired makes encoder encode tag number.
|
|
EncTagRequired
|
|
|
|
maxEncTagMode
|
|
)
|
|
|
|
func (etm EncTagMode) valid() bool {
|
|
return etm >= 0 && etm < maxEncTagMode
|
|
}
|
|
|
|
// TagOptions specifies how encoder and decoder handle tag number.
|
|
type TagOptions struct {
|
|
DecTag DecTagMode
|
|
EncTag EncTagMode
|
|
}
|
|
|
|
// TagSet is an interface to add and remove tag info. It is used by EncMode and DecMode
|
|
// to provide CBOR tag support.
|
|
type TagSet interface {
|
|
// Add adds given tag number(s), content type, and tag options to TagSet.
|
|
Add(opts TagOptions, contentType reflect.Type, num uint64, nestedNum ...uint64) error
|
|
|
|
// Remove removes given tag content type from TagSet.
|
|
Remove(contentType reflect.Type)
|
|
|
|
tagProvider
|
|
}
|
|
|
|
type tagProvider interface {
|
|
getTagItemFromType(t reflect.Type) *tagItem
|
|
getTypeFromTagNum(num []uint64) reflect.Type
|
|
}
|
|
|
|
type tagItem struct {
|
|
num []uint64
|
|
cborTagNum []byte
|
|
contentType reflect.Type
|
|
opts TagOptions
|
|
}
|
|
|
|
func (t *tagItem) equalTagNum(num []uint64) bool {
|
|
// Fast path to compare 1 tag number
|
|
if len(t.num) == 1 && len(num) == 1 && t.num[0] == num[0] {
|
|
return true
|
|
}
|
|
|
|
if len(t.num) != len(num) {
|
|
return false
|
|
}
|
|
|
|
for i := 0; i < len(t.num); i++ {
|
|
if t.num[i] != num[i] {
|
|
return false
|
|
}
|
|
}
|
|
|
|
return true
|
|
}
|
|
|
|
type (
|
|
tagSet map[reflect.Type]*tagItem
|
|
|
|
syncTagSet struct {
|
|
sync.RWMutex
|
|
t tagSet
|
|
}
|
|
)
|
|
|
|
func (t tagSet) getTagItemFromType(typ reflect.Type) *tagItem {
|
|
return t[typ]
|
|
}
|
|
|
|
func (t tagSet) getTypeFromTagNum(num []uint64) reflect.Type {
|
|
for typ, tag := range t {
|
|
if tag.equalTagNum(num) {
|
|
return typ
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// NewTagSet returns TagSet (safe for concurrency).
|
|
func NewTagSet() TagSet {
|
|
return &syncTagSet{t: make(map[reflect.Type]*tagItem)}
|
|
}
|
|
|
|
// Add adds given tag number(s), content type, and tag options to TagSet.
|
|
func (t *syncTagSet) Add(opts TagOptions, contentType reflect.Type, num uint64, nestedNum ...uint64) error {
|
|
if contentType == nil {
|
|
return errors.New("cbor: cannot add nil content type to TagSet")
|
|
}
|
|
for contentType.Kind() == reflect.Ptr {
|
|
contentType = contentType.Elem()
|
|
}
|
|
tag, err := newTagItem(opts, contentType, num, nestedNum...)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
t.Lock()
|
|
defer t.Unlock()
|
|
for typ, ti := range t.t {
|
|
if typ == contentType {
|
|
return errors.New("cbor: content type " + contentType.String() + " already exists in TagSet")
|
|
}
|
|
if ti.equalTagNum(tag.num) {
|
|
return fmt.Errorf("cbor: tag number %v already exists in TagSet", tag.num)
|
|
}
|
|
}
|
|
t.t[contentType] = tag
|
|
return nil
|
|
}
|
|
|
|
// Remove removes given tag content type from TagSet.
|
|
func (t *syncTagSet) Remove(contentType reflect.Type) {
|
|
for contentType.Kind() == reflect.Ptr {
|
|
contentType = contentType.Elem()
|
|
}
|
|
t.Lock()
|
|
delete(t.t, contentType)
|
|
t.Unlock()
|
|
}
|
|
|
|
func (t *syncTagSet) getTagItemFromType(typ reflect.Type) *tagItem {
|
|
t.RLock()
|
|
ti := t.t[typ]
|
|
t.RUnlock()
|
|
return ti
|
|
}
|
|
|
|
func (t *syncTagSet) getTypeFromTagNum(num []uint64) reflect.Type {
|
|
t.RLock()
|
|
rt := t.t.getTypeFromTagNum(num)
|
|
t.RUnlock()
|
|
return rt
|
|
}
|
|
|
|
func newTagItem(opts TagOptions, contentType reflect.Type, num uint64, nestedNum ...uint64) (*tagItem, error) {
|
|
if opts.DecTag == DecTagIgnored && opts.EncTag == EncTagNone {
|
|
return nil, errors.New("cbor: cannot add tag with DecTagIgnored and EncTagNone options to TagSet")
|
|
}
|
|
if contentType.PkgPath() == "" || contentType.Kind() == reflect.Interface {
|
|
return nil, errors.New("cbor: can only add named types to TagSet, got " + contentType.String())
|
|
}
|
|
if contentType == typeTime {
|
|
return nil, errors.New("cbor: cannot add time.Time to TagSet, use EncOptions.TimeTag and DecOptions.TimeTag instead")
|
|
}
|
|
if contentType == typeBigInt {
|
|
return nil, errors.New("cbor: cannot add big.Int to TagSet, it's built-in and supported automatically")
|
|
}
|
|
if contentType == typeTag {
|
|
return nil, errors.New("cbor: cannot add cbor.Tag to TagSet")
|
|
}
|
|
if contentType == typeRawTag {
|
|
return nil, errors.New("cbor: cannot add cbor.RawTag to TagSet")
|
|
}
|
|
if num == 0 || num == 1 {
|
|
return nil, errors.New("cbor: cannot add tag number 0 or 1 to TagSet, use EncOptions.TimeTag and DecOptions.TimeTag instead")
|
|
}
|
|
if num == 2 || num == 3 {
|
|
return nil, errors.New("cbor: cannot add tag number 2 or 3 to TagSet, it's built-in and supported automatically")
|
|
}
|
|
if num == tagNumSelfDescribedCBOR {
|
|
return nil, errors.New("cbor: cannot add tag number 55799 to TagSet, it's built-in and ignored automatically")
|
|
}
|
|
|
|
te := tagItem{num: []uint64{num}, opts: opts, contentType: contentType}
|
|
te.num = append(te.num, nestedNum...)
|
|
|
|
// Cache encoded tag numbers
|
|
e := getEncodeBuffer()
|
|
for _, n := range te.num {
|
|
encodeHead(e, byte(cborTypeTag), n)
|
|
}
|
|
te.cborTagNum = make([]byte, e.Len())
|
|
copy(te.cborTagNum, e.Bytes())
|
|
putEncodeBuffer(e)
|
|
|
|
return &te, nil
|
|
}
|
|
|
|
var (
|
|
typeTag = reflect.TypeOf(Tag{})
|
|
typeRawTag = reflect.TypeOf(RawTag{})
|
|
)
|
|
|
|
// WrongTagError describes mismatch between CBOR tag and registered tag.
|
|
type WrongTagError struct {
|
|
RegisteredType reflect.Type
|
|
RegisteredTagNum []uint64
|
|
TagNum []uint64
|
|
}
|
|
|
|
func (e *WrongTagError) Error() string {
|
|
return fmt.Sprintf("cbor: wrong tag number for %s, got %v, expected %v", e.RegisteredType.String(), e.TagNum, e.RegisteredTagNum)
|
|
}
|