Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

tftypes: Guarantee Type interface MarshalJSON error safety #371

Merged
merged 2 commits into from
Jan 24, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
19 changes: 7 additions & 12 deletions tfprotov5/internal/toproto/dynamic_value.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,6 @@
package toproto

import (
"fmt"

"github.com/hashicorp/terraform-plugin-go/tfprotov5"
"github.com/hashicorp/terraform-plugin-go/tfprotov5/internal/tfplugin5"
"github.com/hashicorp/terraform-plugin-go/tftypes"
Expand All @@ -24,17 +22,14 @@ func DynamicValue(in *tfprotov5.DynamicValue) *tfplugin5.DynamicValue {
return resp
}

func CtyType(in tftypes.Type) ([]byte, error) {
func CtyType(in tftypes.Type) []byte {
if in == nil {
return nil, nil
return nil
}

switch {
case in.Is(tftypes.String), in.Is(tftypes.Bool), in.Is(tftypes.Number),
in.Is(tftypes.List{}), in.Is(tftypes.Map{}),
in.Is(tftypes.Set{}), in.Is(tftypes.Object{}),
in.Is(tftypes.Tuple{}), in.Is(tftypes.DynamicPseudoType):
return in.MarshalJSON() //nolint:staticcheck
}
return nil, fmt.Errorf("unknown type %s", in)
// MarshalJSON is always error safe.
// nolint:staticcheck // Intended first-party usage
resp, _ := in.MarshalJSON()

return resp
}
101 changes: 21 additions & 80 deletions tfprotov5/internal/toproto/function.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,6 @@
package toproto

import (
"fmt"

"github.com/hashicorp/terraform-plugin-go/tfprotov5"
"github.com/hashicorp/terraform-plugin-go/tfprotov5/internal/tfplugin5"
)
Expand All @@ -23,61 +21,31 @@ func CallFunction_Response(in *tfprotov5.CallFunctionResponse) *tfplugin5.CallFu
return resp
}

func Function(in *tfprotov5.Function) (*tfplugin5.Function, error) {
func Function(in *tfprotov5.Function) *tfplugin5.Function {
if in == nil {
return nil, nil
return nil
}

resp := &tfplugin5.Function{
Description: in.Description,
DescriptionKind: StringKind(in.DescriptionKind),
DeprecationMessage: in.DeprecationMessage,
Parameters: make([]*tfplugin5.Function_Parameter, 0, len(in.Parameters)),
Return: Function_Return(in.Return),
Summary: in.Summary,
VariadicParameter: Function_Parameter(in.VariadicParameter),
}

for position, parameter := range in.Parameters {
if parameter == nil {
return nil, fmt.Errorf("missing function parameter definition at position: %d", position)
}

functionParameter, err := Function_Parameter(parameter)

if err != nil {
return nil, fmt.Errorf("unable to marshal function parameter at position %d: %w", position, err)
}

resp.Parameters = append(resp.Parameters, functionParameter)
}

if in.Return == nil {
return nil, fmt.Errorf("missing function return definition")
}

functionReturn, err := Function_Return(in.Return)

if err != nil {
return nil, fmt.Errorf("unable to marshal function return: %w", err)
for _, parameter := range in.Parameters {
resp.Parameters = append(resp.Parameters, Function_Parameter(parameter))
}

resp.Return = functionReturn

if in.VariadicParameter != nil {
variadicParameter, err := Function_Parameter(in.VariadicParameter)

if err != nil {
return nil, fmt.Errorf("unable to marshal variadic function parameter: %w", err)
}

resp.VariadicParameter = variadicParameter
}

return resp, nil
return resp
}

func Function_Parameter(in *tfprotov5.FunctionParameter) (*tfplugin5.Function_Parameter, error) {
func Function_Parameter(in *tfprotov5.FunctionParameter) *tfplugin5.Function_Parameter {
if in == nil {
return nil, nil
return nil
}

resp := &tfplugin5.Function_Parameter{
Expand All @@ -86,66 +54,39 @@ func Function_Parameter(in *tfprotov5.FunctionParameter) (*tfplugin5.Function_Pa
Description: in.Description,
DescriptionKind: StringKind(in.DescriptionKind),
Name: in.Name,
Type: CtyType(in.Type),
}

if in.Type == nil {
return nil, fmt.Errorf("missing function parameter type definition")
}

ctyType, err := CtyType(in.Type)

if err != nil {
return resp, fmt.Errorf("error marshaling function parameter type: %w", err)
}

resp.Type = ctyType

return resp, nil
return resp
}

func Function_Return(in *tfprotov5.FunctionReturn) (*tfplugin5.Function_Return, error) {
func Function_Return(in *tfprotov5.FunctionReturn) *tfplugin5.Function_Return {
if in == nil {
return nil, nil
}

resp := &tfplugin5.Function_Return{}

if in.Type == nil {
return nil, fmt.Errorf("missing function return type definition")
return nil
}

ctyType, err := CtyType(in.Type)

if err != nil {
return resp, fmt.Errorf("error marshaling function return type: %w", err)
resp := &tfplugin5.Function_Return{
Type: CtyType(in.Type),
}

resp.Type = ctyType

return resp, nil
return resp
}

func GetFunctions_Response(in *tfprotov5.GetFunctionsResponse) (*tfplugin5.GetFunctions_Response, error) {
func GetFunctions_Response(in *tfprotov5.GetFunctionsResponse) *tfplugin5.GetFunctions_Response {
if in == nil {
return nil, nil
return nil
}

resp := &tfplugin5.GetFunctions_Response{
Diagnostics: Diagnostics(in.Diagnostics),
Functions: make(map[string]*tfplugin5.Function, len(in.Functions)),
}

for name, functionPtr := range in.Functions {
function, err := Function(functionPtr)

if err != nil {
return nil, fmt.Errorf("error marshaling function definition for %q: %w", name, err)
}

resp.Functions[name] = function
for name, function := range in.Functions {
resp.Functions[name] = Function(function)
}

return resp, nil
return resp
}

func GetMetadata_FunctionMetadata(in *tfprotov5.FunctionMetadata) *tfplugin5.GetMetadata_FunctionMetadata {
Expand Down