Files
plexterraform/internal/provider/reflect/into.go

217 lines
8.6 KiB
Go

// Code generated by Speakeasy (https://speakeasyapi.dev). DO NOT EDIT.
package reflect
import (
"context"
"fmt"
"math/big"
"reflect"
"github.com/hashicorp/terraform-plugin-go/tftypes"
"github.com/hashicorp/terraform-plugin-framework/attr"
"github.com/hashicorp/terraform-plugin-framework/diag"
"github.com/hashicorp/terraform-plugin-framework/path"
)
// Into uses the data in `val` to populate `target`, using the reflection
// package to recursively reflect into structs and slices. If `target` is an
// attr.Value, its assignment method will be used instead of reflecting. If
// `target` is a tftypes.ValueConverter, the FromTerraformValue method will be
// used instead of using reflection. Primitives are set using the val.As
// method. Structs use reflection: each exported struct field must have a
// "tfsdk" tag with the name of the field in the tftypes.Value, and all fields
// in the tftypes.Value must have a corresponding property in the struct. Into
// will be called for each struct field. Slices will have Into called for each
// element.
func Into(ctx context.Context, typ attr.Type, val tftypes.Value, target interface{}, opts Options, path path.Path) diag.Diagnostics {
var diags diag.Diagnostics
v := reflect.ValueOf(target)
if v.Kind() != reflect.Ptr {
err := fmt.Errorf("target must be a pointer, got %T, which is a %s", target, v.Kind())
diags.AddAttributeError(
path,
"Value Conversion Error",
fmt.Sprintf("An unexpected error was encountered trying to convert the value. This is always an error in the provider. Please report the following to the provider developer:\n\nPath: %s\nError: %s", path.String(), err.Error()),
)
return diags
}
result, diags := BuildValue(ctx, typ, val, v.Elem(), opts, path)
if diags.HasError() {
return diags
}
v.Elem().Set(result)
return diags
}
// BuildValue constructs a reflect.Value of the same type as `target`,
// populated with the data in `val`. It will defensively instantiate new values
// to set, making it safe for use with pointer types which may be nil. It tries
// to give consumers the ability to override its default behaviors wherever
// possible.
func BuildValue(ctx context.Context, typ attr.Type, val tftypes.Value, target reflect.Value, opts Options, path path.Path) (reflect.Value, diag.Diagnostics) {
var diags diag.Diagnostics
// if this isn't a valid reflect.Value, bail before we accidentally
// panic
if !target.IsValid() {
err := fmt.Errorf("invalid target")
diags.AddAttributeError(
path,
"Value Conversion Error",
"An unexpected error was encountered trying to build a value. This is always an error in the provider. Please report the following to the provider developer:\n\n"+err.Error(),
)
return target, diags
}
// -------------------------
// -- Fork Start -----------
// -------------------------
if !val.IsKnown() {
return target, diags
}
// -------------------------
// -- Fork End - -----------
// -------------------------
// if this is an attr.Value, build the type from that
if target.Type().Implements(reflect.TypeOf((*attr.Value)(nil)).Elem()) {
return NewAttributeValue(ctx, typ, val, target, opts, path)
}
// if this tells tftypes how to build an instance of it out of a
// tftypes.Value, well, that's what we want, so do that instead of our
// default logic.
if target.Type().Implements(reflect.TypeOf((*tftypes.ValueConverter)(nil)).Elem()) {
return NewValueConverter(ctx, typ, val, target, opts, path)
}
// if this can explicitly be set to unknown, do that
if target.Type().Implements(reflect.TypeOf((*Unknownable)(nil)).Elem()) {
res, unknownableDiags := NewUnknownable(ctx, typ, val, target, opts, path)
diags.Append(unknownableDiags...)
if diags.HasError() {
return target, diags
}
target = res
// only return if it's unknown; we want to call SetUnknown
// either way, but if the value is unknown, there's nothing
// else to do, so bail
if !val.IsKnown() {
return target, nil
}
}
// if this can explicitly be set to null, do that
if target.Type().Implements(reflect.TypeOf((*Nullable)(nil)).Elem()) {
res, nullableDiags := NewNullable(ctx, typ, val, target, opts, path)
diags.Append(nullableDiags...)
if diags.HasError() {
return target, diags
}
target = res
// only return if it's null; we want to call SetNull either
// way, but if the value is null, there's nothing else to do,
// so bail
if val.IsNull() {
return target, nil
}
}
// -------------------------
// -- Fork Start -----------
// -------------------------
//if !val.IsKnown() {
// // we already handled unknown the only ways we can
// // we checked that target doesn't have a SetUnknown method we
// // can call
// // we checked that target isn't an attr.Value
// // all that's left to us now is to set it as an empty value or
// // throw an error, depending on what's in opts
// if !opts.UnhandledUnknownAsEmpty {
// diags.AddAttributeError(
// path,
// "Value Conversion Error",
// "An unexpected error was encountered trying to build a value. This is always an error in the provider. Please report the following to the provider developer:\n\n"+
// "Received unknown value, however the target type cannot handle unknown values. Use the corresponding `types` package type or a custom type that handles unknown values.\n\n"+
// fmt.Sprintf("Path: %s\nTarget Type: %s\nSuggested Type: %s", path.String(), target.Type(), reflect.TypeOf(typ.ValueType(ctx))),
// )
// return target, diags
// }
// // we want to set unhandled unknowns to the empty value
// return reflect.Zero(target.Type()), diags
//}
// -------------------------
// -- Fork End - -----------
// -------------------------
if val.IsNull() {
// we already handled null the only ways we can
// we checked that target doesn't have a SetNull method we can
// call
// we checked that target isn't an attr.Value
// all that's left to us now is to set it as an empty value or
// throw an error, depending on what's in opts
if canBeNil(target) || opts.UnhandledNullAsEmpty {
return reflect.Zero(target.Type()), nil
}
diags.AddAttributeError(
path,
"Value Conversion Error",
"An unexpected error was encountered trying to build a value. This is always an error in the provider. Please report the following to the provider developer:\n\n"+
"Received null value, however the target type cannot handle null values. Use the corresponding `types` package type, a pointer type or a custom type that handles null values.\n\n"+
fmt.Sprintf("Path: %s\nTarget Type: %s\nSuggested `types` Type: %s\nSuggested Pointer Type: *%s", path.String(), target.Type(), reflect.TypeOf(typ.ValueType(ctx)), target.Type()),
)
return target, diags
}
// *big.Float and *big.Int are technically pointers, but we want them
// handled as numbers
if target.Type() == reflect.TypeOf(big.NewFloat(0)) || target.Type() == reflect.TypeOf(big.NewInt(0)) {
return Number(ctx, typ, val, target, opts, path)
}
switch target.Kind() {
case reflect.Struct:
val, valDiags := Struct(ctx, typ, val, target, opts, path)
diags.Append(valDiags...)
return val, diags
case reflect.Bool, reflect.String:
val, valDiags := Primitive(ctx, typ, val, target, path)
diags.Append(valDiags...)
return val, diags
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32,
reflect.Int64, reflect.Uint, reflect.Uint8, reflect.Uint16,
reflect.Uint32, reflect.Uint64, reflect.Float32, reflect.Float64:
// numbers are the wooooorst and need their own special handling
// because we can't just hand them off to tftypes and also
// because we can't just make people use *big.Floats, because a
// nil *big.Float will crash everything if we don't handle it
// as a special case, so let's just special case numbers and
// let people use the types they want
val, valDiags := Number(ctx, typ, val, target, opts, path)
diags.Append(valDiags...)
return val, diags
case reflect.Slice:
val, valDiags := reflectSlice(ctx, typ, val, target, opts, path)
diags.Append(valDiags...)
return val, diags
case reflect.Map:
val, valDiags := Map(ctx, typ, val, target, opts, path)
diags.Append(valDiags...)
return val, diags
case reflect.Ptr:
val, valDiags := Pointer(ctx, typ, val, target, opts, path)
diags.Append(valDiags...)
return val, diags
default:
err := fmt.Errorf("don't know how to reflect %s into %s", val.Type(), target.Type())
diags.AddAttributeError(
path,
"Value Conversion Error",
"An unexpected error was encountered trying to build a value. This is always an error in the provider. Please report the following to the provider developer:\n\n"+err.Error(),
)
return target, diags
}
}