/* Copyright (c) Edgeless Systems GmbH SPDX-License-Identifier: AGPL-3.0-only */ package config import ( "encoding/json" "fmt" "strings" "github.com/edgelesssys/constellation/v2/internal/encoding" ) type versionValue interface { encoding.HexBytes | uint8 | uint16 } func placeholderVersionValue[T versionValue]() T { var placeholder T return placeholder } // NewLatestPlaceholderVersion returns the latest version with a placeholder version value. func NewLatestPlaceholderVersion[T versionValue]() AttestationVersion[T] { return AttestationVersion[T]{ Value: placeholderVersionValue[T](), WantLatest: true, } } // AttestationVersion holds version information. type AttestationVersion[T versionValue] struct { Value T WantLatest bool } // MarshalYAML implements a custom marshaller to write "latest" as the type's value, if set. func (v AttestationVersion[T]) MarshalYAML() (any, error) { if v.WantLatest { return "latest", nil } return v.Value, nil } // UnmarshalYAML implements a custom unmarshaller to resolve "latest" values. func (v *AttestationVersion[T]) UnmarshalYAML(unmarshal func(any) error) error { return v.unmarshal(unmarshal) } // MarshalJSON implements a custom marshaller to write "latest" as the type's value, if set. func (v AttestationVersion[T]) MarshalJSON() ([]byte, error) { if v.WantLatest { return json.Marshal("latest") } return json.Marshal(v.Value) } // UnmarshalJSON implements a custom unmarshaller to resolve "latest" values. func (v *AttestationVersion[T]) UnmarshalJSON(data []byte) (err error) { return v.unmarshal(func(a any) error { return json.Unmarshal(data, a) }) } // unmarshal takes care of unmarshalling the value from YAML or JSON. func (v *AttestationVersion[T]) unmarshal(unmarshal func(any) error) error { // Start by trying to unmarshal to the distinct type var distinctType T if err := unmarshal(&distinctType); err == nil { v.Value = distinctType return nil } var unmarshalString string if err := unmarshal(&unmarshalString); err != nil { return fmt.Errorf("failed unmarshalling to %T or string: %w", distinctType, err) } if strings.ToLower(unmarshalString) == "latest" { v.WantLatest = true v.Value = placeholderVersionValue[T]() return nil } return fmt.Errorf("failed unmarshalling to %T or string: invalid value: %s", distinctType, unmarshalString) }