openai/openai-go
Publicmirrored from https://github.com/openai/openai-goAvailable
packages/param/encoder.go
101lines · modecode
| 1 | package param |
| 2 | |
| 3 | import ( |
| 4 | "encoding/json" |
| 5 | "fmt" |
| 6 | "reflect" |
| 7 | "time" |
| 8 | |
| 9 | shimjson "github.com/openai/openai-go/internal/encoding/json" |
| 10 | |
| 11 | "github.com/tidwall/sjson" |
| 12 | ) |
| 13 | |
| 14 | // EncodedAsDate is not be stable and shouldn't be relied upon |
| 15 | type EncodedAsDate Opt[time.Time] |
| 16 | |
| 17 | type forceOmit int |
| 18 | |
| 19 | func (m EncodedAsDate) MarshalJSON() ([]byte, error) { |
| 20 | underlying := Opt[time.Time](m) |
| 21 | bytes := underlying.MarshalJSONWithTimeLayout("2006-01-02") |
| 22 | if len(bytes) > 0 { |
| 23 | return bytes, nil |
| 24 | } |
| 25 | return underlying.MarshalJSON() |
| 26 | } |
| 27 | |
| 28 | // MarshalObject uses a shimmed 'encoding/json' from Go 1.24, to support the 'omitzero' tag |
| 29 | // |
| 30 | // Stability for the API of MarshalObject is not guaranteed. |
| 31 | func MarshalObject[T ParamStruct](f T, underlying any) ([]byte, error) { |
| 32 | return MarshalWithExtras(f, underlying, f.extraFields()) |
| 33 | } |
| 34 | |
| 35 | // MarshalWithExtras is used to marshal a struct with additional properties. |
| 36 | // |
| 37 | // Stability for the API of MarshalWithExtras is not guaranteed. |
| 38 | func MarshalWithExtras[T ParamStruct, R any](f T, underlying any, extras map[string]R) ([]byte, error) { |
| 39 | if f.null() { |
| 40 | return []byte("null"), nil |
| 41 | } else if len(extras) > 0 { |
| 42 | bytes, err := shimjson.Marshal(underlying) |
| 43 | if err != nil { |
| 44 | return nil, err |
| 45 | } |
| 46 | for k, v := range extras { |
| 47 | var a any = v |
| 48 | if a == Omit { |
| 49 | // Errors when handling ForceOmitted are ignored. |
| 50 | if b, e := sjson.DeleteBytes(bytes, k); e == nil { |
| 51 | bytes = b |
| 52 | } |
| 53 | continue |
| 54 | } |
| 55 | bytes, err = sjson.SetBytes(bytes, k, v) |
| 56 | if err != nil { |
| 57 | return nil, err |
| 58 | } |
| 59 | } |
| 60 | return bytes, nil |
| 61 | } else if ovr, ok := f.Overrides(); ok { |
| 62 | return shimjson.Marshal(ovr) |
| 63 | } else { |
| 64 | return shimjson.Marshal(underlying) |
| 65 | } |
| 66 | } |
| 67 | |
| 68 | // MarshalUnion uses a shimmed 'encoding/json' from Go 1.24, to support the 'omitzero' tag |
| 69 | // |
| 70 | // Stability for the API of MarshalUnion is not guaranteed. |
| 71 | func MarshalUnion[T ParamStruct](metadata T, variants ...any) ([]byte, error) { |
| 72 | nPresent := 0 |
| 73 | presentIdx := -1 |
| 74 | for i, variant := range variants { |
| 75 | if !IsOmitted(variant) { |
| 76 | nPresent++ |
| 77 | presentIdx = i |
| 78 | } |
| 79 | } |
| 80 | if nPresent == 0 || presentIdx == -1 { |
| 81 | if ovr, ok := metadata.Overrides(); ok { |
| 82 | return shimjson.Marshal(ovr) |
| 83 | } |
| 84 | return []byte(`null`), nil |
| 85 | } else if nPresent > 1 { |
| 86 | return nil, &json.MarshalerError{ |
| 87 | Type: typeFor[T](), |
| 88 | Err: fmt.Errorf("expected union to have only one present variant, got %d", nPresent), |
| 89 | } |
| 90 | } |
| 91 | return shimjson.Marshal(variants[presentIdx]) |
| 92 | } |
| 93 | |
| 94 | // typeFor is shimmed from Go 1.23 "reflect" package |
| 95 | func typeFor[T any]() reflect.Type { |
| 96 | var v T |
| 97 | if t := reflect.TypeOf(v); t != nil { |
| 98 | return t // optimize for T being a non-interface kind |
| 99 | } |
| 100 | return reflect.TypeOf((*T)(nil)).Elem() // only for an interface kind |
| 101 | } |
| 102 | |