github.com/onflow/atree@v0.6.0/encode.go (about) 1 /* 2 * Atree - Scalable Arrays and Ordered Maps 3 * 4 * Copyright 2021 Dapper Labs, Inc. 5 * 6 * Licensed under the Apache License, Version 2.0 (the "License"); 7 * you may not use this file except in compliance with the License. 8 * You may obtain a copy of the License at 9 * 10 * http://www.apache.org/licenses/LICENSE-2.0 11 * 12 * Unless required by applicable law or agreed to in writing, software 13 * distributed under the License is distributed on an "AS IS" BASIS, 14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 * See the License for the specific language governing permissions and 16 * limitations under the License. 17 */ 18 19 package atree 20 21 import ( 22 "io" 23 "math" 24 25 "github.com/fxamacker/cbor/v2" 26 ) 27 28 // Encoder writes atree slabs to io.Writer. 29 type Encoder struct { 30 io.Writer 31 CBOR *cbor.StreamEncoder 32 Scratch [64]byte 33 } 34 35 func NewEncoder(w io.Writer, encMode cbor.EncMode) *Encoder { 36 streamEncoder := encMode.NewStreamEncoder(w) 37 return &Encoder{ 38 Writer: w, 39 CBOR: streamEncoder, 40 } 41 } 42 43 type StorableDecoder func( 44 decoder *cbor.StreamDecoder, 45 storableSlabStorageID StorageID, 46 ) ( 47 Storable, 48 error, 49 ) 50 51 func DecodeSlab( 52 id StorageID, 53 data []byte, 54 decMode cbor.DecMode, 55 decodeStorable StorableDecoder, 56 decodeTypeInfo TypeInfoDecoder, 57 ) ( 58 Slab, 59 error, 60 ) { 61 if len(data) < versionAndFlagSize { 62 return nil, NewDecodingErrorf("data is too short") 63 } 64 65 flag := data[1] 66 67 dataType := getSlabType(flag) 68 switch dataType { 69 70 case slabArray: 71 72 switch arrayDataType := getSlabArrayType(flag); arrayDataType { 73 case slabArrayData: 74 return newArrayDataSlabFromData(id, data, decMode, decodeStorable, decodeTypeInfo) 75 case slabArrayMeta: 76 return newArrayMetaDataSlabFromData(id, data, decMode, decodeTypeInfo) 77 case slabBasicArray: 78 return newBasicArrayDataSlabFromData(id, data, decMode, decodeStorable) 79 default: 80 return nil, NewDecodingErrorf("data has invalid flag 0x%x", flag) 81 } 82 83 case slabMap: 84 85 switch mapDataType := getSlabMapType(flag); mapDataType { 86 case slabMapData: 87 return newMapDataSlabFromData(id, data, decMode, decodeStorable, decodeTypeInfo) 88 case slabMapMeta: 89 return newMapMetaDataSlabFromData(id, data, decMode, decodeTypeInfo) 90 case slabMapCollisionGroup: 91 return newMapDataSlabFromData(id, data, decMode, decodeStorable, decodeTypeInfo) 92 default: 93 return nil, NewDecodingErrorf("data has invalid flag 0x%x", flag) 94 } 95 96 case slabStorable: 97 cborDec := decMode.NewByteStreamDecoder(data[versionAndFlagSize:]) 98 storable, err := decodeStorable(cborDec, id) 99 if err != nil { 100 // Wrap err as external error (if needed) because err is returned by StorableDecoder callback. 101 return nil, wrapErrorfAsExternalErrorIfNeeded(err, "failed to decode slab storable") 102 } 103 return StorableSlab{ 104 StorageID: id, 105 Storable: storable, 106 }, nil 107 108 default: 109 return nil, NewDecodingErrorf("data has invalid flag 0x%x", flag) 110 } 111 } 112 113 // TODO: make it inline 114 func GetUintCBORSize(n uint64) uint32 { 115 if n <= 23 { 116 return 1 117 } 118 if n <= math.MaxUint8 { 119 return 2 120 } 121 if n <= math.MaxUint16 { 122 return 3 123 } 124 if n <= math.MaxUint32 { 125 return 5 126 } 127 return 9 128 }