2023-08-22 22:23:54 +00:00
|
|
|
// Copyright (c) HashiCorp, Inc.
|
|
|
|
// SPDX-License-Identifier: BUSL-1.1
|
|
|
|
|
2023-08-11 19:52:51 +00:00
|
|
|
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
|
|
|
|
}
|