Files
libopenapi/datamodel/high/base/dynamic_value.go
Dave Shanley c3cf5f1e38 Added support for unevaluatedProperties as Schema and bool #118
Also ran `gofmt` across the entire project. Things need cleaning up.

Signed-off-by: Dave Shanley <dave@quobix.com>
2023-06-17 14:12:27 -04:00

101 lines
2.6 KiB
Go

// Copyright 2023 Princess B33f Heavy Industries / Dave Shanley
// SPDX-License-Identifier: MIT
package base
import (
"github.com/pb33f/libopenapi/datamodel/high"
"gopkg.in/yaml.v3"
"reflect"
)
// DynamicValue is used to hold multiple possible values for a schema property. There are two values, a left
// value (A) and a right value (B). The left value (A) is a 3.0 schema property value, the right value (B) is a 3.1
// schema value.
//
// OpenAPI 3.1 treats a Schema as a real JSON schema, which means some properties become incompatible, or others
// now support more than one primitive type or structure.
// The N value is a bit to make it each to know which value (A or B) is used, this prevents having to
// if/else on the value to determine which one is set.
type DynamicValue[A any, B any] struct {
N int // 0 == A, 1 == B
A A
B B
inline bool
}
// IsA will return true if the 'A' or left value is set. (OpenAPI 3)
func (d *DynamicValue[A, B]) IsA() bool {
return d.N == 0
}
// IsB will return true if the 'B' or right value is set (OpenAPI 3.1)
func (d *DynamicValue[A, B]) IsB() bool {
return d.N == 1
}
func (d *DynamicValue[A, B]) Render() ([]byte, error) {
d.inline = false
return yaml.Marshal(d)
}
func (d *DynamicValue[A, B]) RenderInline() ([]byte, error) {
d.inline = true
return yaml.Marshal(d)
}
// MarshalYAML will create a ready to render YAML representation of the DynamicValue object.
func (d *DynamicValue[A, B]) MarshalYAML() (interface{}, error) {
// this is a custom renderer, we can't use the NodeBuilder out of the gate.
var n yaml.Node
var err error
var value any
if d.IsA() {
value = d.A
}
if d.IsB() {
value = d.B
}
to := reflect.TypeOf(value)
switch to.Kind() {
case reflect.Ptr:
if d.inline {
if r, ok := value.(high.RenderableInline); ok {
return r.MarshalYAMLInline()
} else {
_ = n.Encode(value)
}
} else {
if r, ok := value.(high.Renderable); ok {
return r.MarshalYAML()
} else {
_ = n.Encode(value)
}
}
case reflect.Bool:
_ = n.Encode(value.(bool))
case reflect.Int:
_ = n.Encode(value.(int))
case reflect.String:
_ = n.Encode(value.(string))
case reflect.Int64:
_ = n.Encode(value.(int64))
case reflect.Float64:
_ = n.Encode(value.(float64))
case reflect.Float32:
_ = n.Encode(value.(float32))
case reflect.Int32:
_ = n.Encode(value.(int32))
}
return &n, err
}
// MarshalYAMLInline will create a ready to render YAML representation of the DynamicValue object. The
// references will be inlined instead of kept as references.
func (d *DynamicValue[A, B]) MarshalYAMLInline() (interface{}, error) {
d.inline = true
return d.MarshalYAML()
}