github.com/onflow/atree@v0.6.0/storable.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 "bytes" 23 "fmt" 24 25 "github.com/fxamacker/cbor/v2" 26 ) 27 28 type Storable interface { 29 Encode(*Encoder) error 30 31 ByteSize() uint32 32 33 StoredValue(storage SlabStorage) (Value, error) 34 35 // ChildStorables only returns child storables in this storable 36 // (not recursive). This function shouldn't load extra slabs. 37 ChildStorables() []Storable 38 } 39 40 const ( 41 CBORTagInlineCollisionGroup = 253 42 CBORTagExternalCollisionGroup = 254 43 44 CBORTagStorageID = 255 45 ) 46 47 type StorageIDStorable StorageID 48 49 var _ Storable = StorageIDStorable{} 50 51 func (v StorageIDStorable) ChildStorables() []Storable { 52 return nil 53 } 54 55 func (v StorageIDStorable) StoredValue(storage SlabStorage) (Value, error) { 56 id := StorageID(v) 57 if err := id.Valid(); err != nil { 58 // Don't need to wrap error as external error because err is already categorized by StorageID.Valid(). 59 return nil, err 60 } 61 62 slab, found, err := storage.Retrieve(id) 63 if err != nil { 64 // Wrap err as external error (if needed) because err is returned by SlabStorage interface. 65 return nil, wrapErrorfAsExternalErrorIfNeeded(err, fmt.Sprintf("failed to retrieve slab %s", id)) 66 } 67 if !found { 68 return nil, NewSlabNotFoundErrorf(id, "slab not found for stored value") 69 } 70 value, err := slab.StoredValue(storage) 71 if err != nil { 72 // Wrap err as external error (if needed) because err is returned by Storable interface. 73 return nil, wrapErrorfAsExternalErrorIfNeeded(err, "failed to get storable's stored value") 74 } 75 return value, nil 76 } 77 78 // Encode encodes StorageIDStorable as 79 // 80 // cbor.Tag{ 81 // Number: cborTagStorageID, 82 // Content: byte(v), 83 // } 84 func (v StorageIDStorable) Encode(enc *Encoder) error { 85 err := enc.CBOR.EncodeRawBytes([]byte{ 86 // tag number 87 0xd8, CBORTagStorageID, 88 }) 89 if err != nil { 90 return NewEncodingError(err) 91 } 92 93 copy(enc.Scratch[:], v.Address[:]) 94 copy(enc.Scratch[8:], v.Index[:]) 95 96 err = enc.CBOR.EncodeBytes(enc.Scratch[:storageIDSize]) 97 if err != nil { 98 return NewEncodingError(err) 99 } 100 101 return nil 102 } 103 104 func (v StorageIDStorable) ByteSize() uint32 { 105 // tag number (2 bytes) + byte string header (1 byte) + storage id (16 bytes) 106 return 2 + 1 + storageIDSize 107 } 108 109 func (v StorageIDStorable) String() string { 110 return fmt.Sprintf("StorageIDStorable(%d)", v) 111 } 112 113 // Encode is a wrapper for Storable.Encode() 114 func Encode(storable Storable, encMode cbor.EncMode) ([]byte, error) { 115 var buf bytes.Buffer 116 enc := NewEncoder(&buf, encMode) 117 118 err := storable.Encode(enc) 119 if err != nil { 120 // Wrap err as external error (if needed) because err is returned by Storable interface. 121 return nil, wrapErrorfAsExternalErrorIfNeeded(err, "failed to encode storable") 122 } 123 124 err = enc.CBOR.Flush() 125 if err != nil { 126 return nil, NewEncodingError(err) 127 } 128 129 return buf.Bytes(), nil 130 } 131 132 func DecodeStorageIDStorable(dec *cbor.StreamDecoder) (Storable, error) { 133 b, err := dec.DecodeBytes() 134 if err != nil { 135 return nil, NewDecodingError(err) 136 } 137 138 id, err := NewStorageIDFromRawBytes(b) 139 if err != nil { 140 // Don't need to wrap error as external error because err is already categorized by NewStorageIDFromRawBytes(). 141 return nil, err 142 } 143 144 return StorageIDStorable(id), nil 145 }