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  }