openai/openai-go

Public

mirrored from https://github.com/openai/openai-goAvailable

CodeCommitsIssuesPull requestsActionsInsightsSecurity
release-please--branches--main--changes--next

Branches

Tags

  • No tags available.
0Branches0Tags
Go to file
Add file
Code

Clone

HTTPS

Download ZIP

packages/param/encoder.go

109lines · modecode

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