Skip to content

Commit

Permalink
Merge pull request #3009 from onflow/feature/range-type
Browse files Browse the repository at this point in the history
  • Loading branch information
turbolent authored Jan 11, 2024
2 parents 581d56f + def44e7 commit bf15275
Show file tree
Hide file tree
Showing 60 changed files with 5,937 additions and 357 deletions.
373 changes: 373 additions & 0 deletions encoding/ccf/ccf_test.go

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions encoding/ccf/consts.go
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ const (
CBORTagReferenceType
CBORTagIntersectionType
CBORTagCapabilityType
_
CBORTagInclusiveRangeType
_
_
_
Expand Down Expand Up @@ -120,7 +120,7 @@ const (
CBORTagIntersectionTypeValue
CBORTagCapabilityTypeValue
CBORTagFunctionTypeValue
_
CBORTagInclusiveRangeTypeValue // InclusiveRange is stored as a composite value.
_
_
_
Expand Down
54 changes: 54 additions & 0 deletions encoding/ccf/decode.go
Original file line number Diff line number Diff line change
Expand Up @@ -358,6 +358,7 @@ func (d *Decoder) decodeTypeAndValue(types *cadenceTypeByCCFTypeID) (cadence.Val
// / path-value
// / path-capability-value
// / id-capability-value
// / inclusiverange-value
// / function-value
// / type-value
//
Expand Down Expand Up @@ -549,6 +550,9 @@ func (d *Decoder) decodeValue(t cadence.Type, types *cadenceTypeByCCFTypeID) (ca
// When static type is a reference type, encoded value is its deferenced type.
return d.decodeValue(t.Type, types)

case *cadence.InclusiveRangeType:
return d.decodeInclusiveRange(t, types)

default:
nt, err := d.dec.NextType()
if err != nil {
Expand Down Expand Up @@ -1311,6 +1315,52 @@ func (d *Decoder) decodeEnum(typ *cadence.EnumType, types *cadenceTypeByCCFTypeI
return v.WithType(typ), nil
}

// decodeInclusiveRange decodes encoded inclusiverange-value as
// language=CDDL
// inclusiverange-value = [
//
// start: value,
// end: value,
// step: value,
//
// ]
func (d *Decoder) decodeInclusiveRange(typ *cadence.InclusiveRangeType, types *cadenceTypeByCCFTypeID) (cadence.Value, error) {
// Decode array head of length 3.
err := decodeCBORArrayWithKnownSize(d.dec, 3)
if err != nil {
return nil, err
}

elementType := typ.ElementType

// Decode start.
start, err := d.decodeValue(elementType, types)
if err != nil {
return nil, err
}

// Decode end.
end, err := d.decodeValue(elementType, types)
if err != nil {
return nil, err
}

// Decode step.
step, err := d.decodeValue(elementType, types)
if err != nil {
return nil, err
}

v := cadence.NewMeteredInclusiveRange(
d.gauge,
start,
end,
step,
)

return v.WithType(typ), nil
}

// decodePath decodes path-value as
// language=CDDL
// path-value = [
Expand Down Expand Up @@ -1423,6 +1473,7 @@ func (d *Decoder) decodeCapability(typ *cadence.CapabilityType, types *cadenceTy
// / varsized-array-type-value
// / constsized-array-type-value
// / dict-type-value
// / inclusiverange-type-value
// / struct-type-value
// / resource-type-value
// / contract-type-value
Expand Down Expand Up @@ -1463,6 +1514,9 @@ func (d *Decoder) decodeTypeValue(visited *cadenceTypeByCCFTypeID) (cadence.Type
case CBORTagDictTypeValue:
return d.decodeDictType(visited, d.decodeTypeValue)

case CBORTagInclusiveRangeTypeValue:
return d.decodeInclusiveRangeType(visited, d.decodeTypeValue)

case CBORTagCapabilityTypeValue:
return d.decodeCapabilityType(visited, d.decodeNullableTypeValue)

Expand Down
34 changes: 34 additions & 0 deletions encoding/ccf/decode_type.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ type decodeTypeFn func(types *cadenceTypeByCCFTypeID) (cadence.Type, error)
// / reference-type
// / intersection-type
// / capability-type
// / inclusiverange-type
// / type-ref
//
// All exported Cadence types needs to be handled in this function,
Expand All @@ -71,6 +72,9 @@ func (d *Decoder) decodeInlineType(types *cadenceTypeByCCFTypeID) (cadence.Type,
case CBORTagDictType:
return d.decodeDictType(types, d.decodeInlineType)

case CBORTagInclusiveRangeType:
return d.decodeInclusiveRangeType(types, d.decodeInlineType)

case CBORTagReferenceType:
return d.decodeReferenceType(types, d.decodeInlineType)

Expand Down Expand Up @@ -273,6 +277,36 @@ func (d *Decoder) decodeDictType(
return cadence.NewMeteredDictionaryType(d.gauge, keyType, elementType), nil
}

// decodeInclusiveRangeType decodes inclusiverange-type or inclusiverange-type-value as
// language=CDDL
// inclusiverange-type =
//
// ; cbor-tag-inclusiverange-type
// #6.145(inline-type)
//
// inclusiverange-type-value =
//
// ; cbor-tag-inclusiverange-type-value
// #6.194(type-value)
//
// NOTE: decodeTypeFn is responsible for decoding inline-type or type-value.
func (d *Decoder) decodeInclusiveRangeType(
types *cadenceTypeByCCFTypeID,
decodeTypeFn decodeTypeFn,
) (cadence.Type, error) {
// element 0: element type (inline-type or type-value)
elementType, err := decodeTypeFn(types)
if err != nil {
return nil, err
}

if elementType == nil {
return nil, errors.New("unexpected nil type as inclusiverange element type")
}

return cadence.NewMeteredInclusiveRangeType(d.gauge, elementType), nil
}

// decodeCapabilityType decodes capability-type or capability-type-value as
// language=CDDL
// capability-type =
Expand Down
52 changes: 52 additions & 0 deletions encoding/ccf/encode.go
Original file line number Diff line number Diff line change
Expand Up @@ -378,6 +378,7 @@ func (e *Encoder) encodeTypeDefs(types []cadence.Type, tids ccfTypeIDByCadenceTy
// / path-value
// / path-capability-value
// / id-capability-value
// / inclusiverange-value
// / function-value
// / type-value
//
Expand Down Expand Up @@ -563,6 +564,9 @@ func (e *Encoder) encodeValue(
case cadence.Dictionary:
return e.encodeDictionary(v, tids)

case *cadence.InclusiveRange:
return e.encodeInclusiveRange(v, tids)

case cadence.Struct:
return e.encodeStruct(v, tids)

Expand Down Expand Up @@ -974,6 +978,34 @@ func encodeAndSortKeyValuePairs(
return encodedPairs, nil
}

// encodeInclusiveRange encodes cadence.InclusiveRange as
// language=CDDL
// inclusiverange-value = [3*3 (key: value, value: value)]
func (e *Encoder) encodeInclusiveRange(v *cadence.InclusiveRange, tids ccfTypeIDByCadenceType) error {
staticElementType := v.InclusiveRangeType.ElementType

// Encode array head with array size of 3.
err := e.enc.EncodeArrayHead(3)
if err != nil {
return err
}

// Encode start key as value.
err = e.encodeValue(v.Start, staticElementType, tids)
if err != nil {
return err
}

// Encode end as value.
err = e.encodeValue(v.End, staticElementType, tids)
if err != nil {
return err
}

// Encode step key as value.
return e.encodeValue(v.Step, staticElementType, tids)
}

// encodeStruct encodes cadence.Struct as
// language=CDDL
// composite-value = [* (field: value)]
Expand Down Expand Up @@ -1201,6 +1233,7 @@ func (e *Encoder) encodeFunction(typ *cadence.FunctionType, visited ccfTypeIDByC
// / reference-type-value
// / intersection-type-value
// / capability-type-value
// / inclusiverange-type-value
// / type-value-ref
//
// TypeValue is used differently from inline type or type definition.
Expand Down Expand Up @@ -1251,6 +1284,9 @@ func (e *Encoder) encodeTypeValue(typ cadence.Type, visited ccfTypeIDByCadenceTy
case *cadence.ContractType:
return e.encodeContractTypeValue(typ, visited)

case *cadence.InclusiveRangeType:
return e.encodeInclusiveRangeTypeValue(typ, visited)

case *cadence.StructInterfaceType:
return e.encodeStructInterfaceTypeValue(typ, visited)

Expand Down Expand Up @@ -1380,6 +1416,22 @@ func (e *Encoder) encodeDictTypeValue(typ *cadence.DictionaryType, visited ccfTy
)
}

// encodeInclusiveRangeTypeValue encodes cadence.InclusiveRangeType as
// language=CDDL
// inclusiverange-type-value =
//
// ; cbor-tag-inclusiverange-type-value
// #6.194(type-value)
func (e *Encoder) encodeInclusiveRangeTypeValue(typ *cadence.InclusiveRangeType, visited ccfTypeIDByCadenceType) error {
rawTagNum := []byte{0xd8, CBORTagInclusiveRangeTypeValue}
return e.encodeInclusiveRangeTypeWithRawTag(
typ,
visited,
e.encodeTypeValue,
rawTagNum,
)
}

// encodeReferenceTypeValue encodes cadence.ReferenceType as
// language=CDDL
// reference-type-value =
Expand Down
41 changes: 41 additions & 0 deletions encoding/ccf/encode_type.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ type encodeTypeFn func(typ cadence.Type, tids ccfTypeIDByCadenceType) error
// / reference-type
// / intersection-type
// / capability-type
// / inclusiverange-type
// / type-ref
//
// All exported Cadence types need to be supported by this function,
Expand All @@ -62,6 +63,9 @@ func (e *Encoder) encodeInlineType(typ cadence.Type, tids ccfTypeIDByCadenceType
case *cadence.DictionaryType:
return e.encodeDictType(typ, tids)

case *cadence.InclusiveRangeType:
return e.encodeInclusiveRangeType(typ, tids)

case cadence.CompositeType, cadence.InterfaceType:
id, err := tids.id(typ)
if err != nil {
Expand Down Expand Up @@ -296,6 +300,43 @@ func (e *Encoder) encodeDictTypeWithRawTag(
return encodeTypeFn(typ.ElementType, tids)
}

// encodeInclusiveRangeType encodes cadence.InclusiveRangeType as
// language=CDDL
// inclusiverange-type =
//
// ; cbor-tag-inclusiverange-type
// #6.145(inline-type)
func (e *Encoder) encodeInclusiveRangeType(
typ *cadence.InclusiveRangeType,
tids ccfTypeIDByCadenceType,
) error {
rawTagNum := []byte{0xd8, CBORTagInclusiveRangeType}
return e.encodeInclusiveRangeTypeWithRawTag(
typ,
tids,
e.encodeInlineType,
rawTagNum,
)
}

// encodeInclusiveRangeTypeWithRawTag encodes cadence.InclusiveRangeType
// with given tag number and encode type function.
func (e *Encoder) encodeInclusiveRangeTypeWithRawTag(
typ *cadence.InclusiveRangeType,
tids ccfTypeIDByCadenceType,
encodeTypeFn encodeTypeFn,
rawTagNumber []byte,
) error {
// Encode CBOR tag number.
err := e.enc.EncodeRawBytes(rawTagNumber)
if err != nil {
return err
}

// Encode element type with given encodeTypeFn
return encodeTypeFn(typ.ElementType, tids)
}

// encodeReferenceType encodes cadence.ReferenceType as
// language=CDDL
// reference-type =
Expand Down
3 changes: 2 additions & 1 deletion encoding/ccf/traverse_value.go
Original file line number Diff line number Diff line change
Expand Up @@ -181,7 +181,8 @@ func (ct *compositeTypes) traverseType(typ cadence.Type) (checkRuntimeType bool)
return true

case cadence.BytesType,
*cadence.FunctionType:
*cadence.FunctionType,
*cadence.InclusiveRangeType:
// TODO: Maybe there are more types that we can skip checking runtime type for composite type.

return false
Expand Down
31 changes: 31 additions & 0 deletions encoding/json/decode.go
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,10 @@ const (
typeBoundKey = "typeBound"
purityKey = "purity"
functionTypeKey = "functionType"
elementKey = "element"
startKey = "start"
endKey = "end"
stepKey = "step"
)

func (d *Decoder) decodeJSON(v any) cadence.Value {
Expand Down Expand Up @@ -225,6 +229,8 @@ func (d *Decoder) decodeJSON(v any) cadence.Value {
return d.decodeEvent(valueJSON)
case contractTypeStr:
return d.decodeContract(valueJSON)
case inclusiveRangeTypeStr:
return d.decodeInclusiveRange(valueJSON)
case pathTypeStr:
return d.decodePath(valueJSON)
case typeTypeStr:
Expand Down Expand Up @@ -869,6 +875,26 @@ func (d *Decoder) decodeEnum(valueJSON any) cadence.Enum {
))
}

func (d *Decoder) decodeInclusiveRange(valueJSON any) *cadence.InclusiveRange {
obj := toObject(valueJSON)

start := obj.GetValue(d, startKey)
end := obj.GetValue(d, endKey)
step := obj.GetValue(d, stepKey)

value := cadence.NewMeteredInclusiveRange(
d.gauge,
start,
end,
step,
)

return value.WithType(cadence.NewMeteredInclusiveRangeType(
d.gauge,
start.Type(),
))
}

func (d *Decoder) decodePath(valueJSON any) cadence.Path {
obj := toObject(valueJSON)

Expand Down Expand Up @@ -1263,6 +1289,11 @@ func (d *Decoder) decodeType(valueJSON any, results typeDecodingResults) cadence
d.decodeType(obj.Get(keyKey), results),
d.decodeType(obj.Get(valueKey), results),
)
case "InclusiveRange":
return cadence.NewMeteredInclusiveRangeType(
d.gauge,
d.decodeType(obj.Get(elementKey), results),
)
case "ConstantSizedArray":
size := toUInt(obj.Get(sizeKey))
return cadence.NewMeteredConstantSizedArrayType(
Expand Down
Loading

0 comments on commit bf15275

Please sign in to comment.