consul/internal/protohcl/blocks.go

116 lines
2.9 KiB
Go
Raw Normal View History

// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: BUSL-1.1
package protohcl
import (
"fmt"
"github.com/hashicorp/hcl/v2"
"google.golang.org/protobuf/reflect/protoreflect"
)
func (u UnmarshalOptions) decodeBlocks(ctx *UnmarshalContext, blocks hcl.Blocks, msg protoreflect.Message, f protoreflect.FieldDescriptor) (protoreflect.Value, error) {
if f.Kind() != protoreflect.MessageKind {
return protoreflect.Value{}, fmt.Errorf("only protobuf message kinds can use HCL block syntax")
}
if f.IsMap() {
return u.decodeBlocksToMap(ctx, blocks, msg, f)
}
if f.IsList() {
return u.decodeBlocksToList(ctx, blocks, msg, f)
}
return u.decodeBlocksToMessage(ctx, blocks, msg, f)
}
func (u UnmarshalOptions) decodeBlocksToMap(ctx *UnmarshalContext, blocks hcl.Blocks, msg protoreflect.Message, f protoreflect.FieldDescriptor) (protoreflect.Value, error) {
val := msg.NewField(f)
mapVal := val.Map()
for _, block := range blocks {
if len(block.Labels) != 1 {
return protoreflect.Value{}, fmt.Errorf("protobuf map fields must have 1 HCL block label")
}
key := protoreflect.ValueOfString(block.Labels[0])
value := mapVal.NewValue()
msgVal := value.Message()
err := u.decodeMessage(
&UnmarshalContext{
Parent: ctx,
Name: fmt.Sprintf("%s[%q]", u.FieldNamer.NameField(f), block.Labels[0]),
Message: msgVal,
Range: block.DefRange,
},
u.bodyDecoder(block.Body),
msgVal,
)
if err != nil {
return protoreflect.Value{}, err
}
mapVal.Set(key.MapKey(), value)
}
return val, nil
}
func (u UnmarshalOptions) decodeBlocksToList(ctx *UnmarshalContext, blocks hcl.Blocks, msg protoreflect.Message, f protoreflect.FieldDescriptor) (protoreflect.Value, error) {
val := msg.NewField(f)
listVal := val.List()
var err error
for idx, block := range blocks {
if len(block.Labels) > 0 {
return protoreflect.Value{}, fmt.Errorf("repeated protobuf fields must not have HCL block labels")
}
elem := listVal.NewElement()
elemMsg := elem.Message()
err = u.decodeMessage(
&UnmarshalContext{
Parent: ctx,
Name: fmt.Sprintf("%s[%d]", u.FieldNamer.NameField(f), idx),
Message: elemMsg,
Range: block.DefRange,
},
u.bodyDecoder(block.Body),
elemMsg,
)
if err != nil {
return protoreflect.Value{}, err
}
listVal.Append(elem)
}
return val, nil
}
func (u UnmarshalOptions) decodeBlocksToMessage(ctx *UnmarshalContext, blocks hcl.Blocks, msg protoreflect.Message, f protoreflect.FieldDescriptor) (protoreflect.Value, error) {
if len(blocks) > 1 {
return protoreflect.Value{}, fmt.Errorf("only one HCL block may be specified for a non-repeated protobuf Message")
}
val := msg.NewField(f)
valMsg := val.Message()
err := u.decodeMessage(
&UnmarshalContext{
Parent: ctx,
Name: blocks[0].Type,
Message: valMsg,
Range: blocks[0].DefRange,
},
u.bodyDecoder(blocks[0].Body),
valMsg,
)
if err != nil {
return protoreflect.Value{}, err
}
return val, nil
}