github.com/anthropics/anthropic-sdk-go@v1.70.1/internal/apijson/encoder.go (about)

     1  package apijson
     2  
     3  import (
     4  	"bytes"
     5  	"encoding/json"
     6  	"fmt"
     7  	"reflect"
     8  	"sort"
     9  	"strconv"
    10  	"strings"
    11  	"sync"
    12  	"time"
    13  
    14  	"github.com/tidwall/sjson"
    15  
    16  	shimjson "github.com/anthropics/anthropic-sdk-go/internal/encoding/json"
    17  )
    18  
    19  var encoders sync.Map // map[encoderEntry]encoderFunc
    20  
    21  // If we want to set a literal key value into JSON using sjson, we need to make sure it doesn't have
    22  // special characters that sjson interprets as a path.
    23  var EscapeSJSONKey = strings.NewReplacer("\\", "\\\\", "|", "\\|", "#", "\\#", "@", "\\@", "*", "\\*", ".", "\\.", ":", "\\:", "?", "\\?").Replace
    24  
    25  func Marshal(value any) ([]byte, error) {
    26  	e := &encoder{dateFormat: time.RFC3339}
    27  	return e.marshal(value)
    28  }
    29  
    30  func MarshalRoot(value any) ([]byte, error) {
    31  	e := &encoder{root: true, dateFormat: time.RFC3339}
    32  	return e.marshal(value)
    33  }
    34  
    35  type encoder struct {
    36  	dateFormat string
    37  	root       bool
    38  }
    39  
    40  type encoderFunc func(value reflect.Value) ([]byte, error)
    41  
    42  type encoderField struct {
    43  	tag parsedStructTag
    44  	fn  encoderFunc
    45  	idx []int
    46  }
    47  
    48  type encoderEntry struct {
    49  	typ        reflect.Type
    50  	dateFormat string
    51  	root       bool
    52  }
    53  
    54  func (e *encoder) marshal(value any) ([]byte, error) {
    55  	val := reflect.ValueOf(value)
    56  	if !val.IsValid() {
    57  		return nil, nil
    58  	}
    59  	typ := val.Type()
    60  	enc := e.typeEncoder(typ)
    61  	return enc(val)
    62  }
    63  
    64  func (e *encoder) typeEncoder(t reflect.Type) encoderFunc {
    65  	entry := encoderEntry{
    66  		typ:        t,
    67  		dateFormat: e.dateFormat,
    68  		root:       e.root,
    69  	}
    70  
    71  	if fi, ok := encoders.Load(entry); ok {
    72  		return fi.(encoderFunc)
    73  	}
    74  
    75  	// To deal with recursive types, populate the map with an
    76  	// indirect func before we build it. This type waits on the
    77  	// real func (f) to be ready and then calls it. This indirect
    78  	// func is only used for recursive types.
    79  	var (
    80  		wg sync.WaitGroup
    81  		f  encoderFunc
    82  	)
    83  	wg.Add(1)
    84  	fi, loaded := encoders.LoadOrStore(entry, encoderFunc(func(v reflect.Value) ([]byte, error) {
    85  		wg.Wait()
    86  		return f(v)
    87  	}))
    88  	if loaded {
    89  		return fi.(encoderFunc)
    90  	}
    91  
    92  	// Compute the real encoder and replace the indirect func with it.
    93  	f = e.newTypeEncoder(t)
    94  	wg.Done()
    95  	encoders.Store(entry, f)
    96  	return f
    97  }
    98  
    99  func marshalerEncoder(v reflect.Value) ([]byte, error) {
   100  	return v.Interface().(json.Marshaler).MarshalJSON()
   101  }
   102  
   103  func indirectMarshalerEncoder(v reflect.Value) ([]byte, error) {
   104  	return v.Addr().Interface().(json.Marshaler).MarshalJSON()
   105  }
   106  
   107  func (e *encoder) newTypeEncoder(t reflect.Type) encoderFunc {
   108  	if t.ConvertibleTo(reflect.TypeOf(time.Time{})) {
   109  		return e.newTimeTypeEncoder()
   110  	}
   111  	if !e.root && t.Implements(reflect.TypeOf((*json.Marshaler)(nil)).Elem()) {
   112  		return marshalerEncoder
   113  	}
   114  	if !e.root && reflect.PointerTo(t).Implements(reflect.TypeOf((*json.Marshaler)(nil)).Elem()) {
   115  		return indirectMarshalerEncoder
   116  	}
   117  	e.root = false
   118  	switch t.Kind() {
   119  	case reflect.Pointer:
   120  		inner := t.Elem()
   121  
   122  		innerEncoder := e.typeEncoder(inner)
   123  		return func(v reflect.Value) ([]byte, error) {
   124  			if !v.IsValid() || v.IsNil() {
   125  				return nil, nil
   126  			}
   127  			return innerEncoder(v.Elem())
   128  		}
   129  	case reflect.Struct:
   130  		return e.newStructTypeEncoder(t)
   131  	case reflect.Array:
   132  		fallthrough
   133  	case reflect.Slice:
   134  		return e.newArrayTypeEncoder(t)
   135  	case reflect.Map:
   136  		return e.newMapEncoder(t)
   137  	case reflect.Interface:
   138  		return e.newInterfaceEncoder()
   139  	default:
   140  		return e.newPrimitiveTypeEncoder(t)
   141  	}
   142  }
   143  
   144  func (e *encoder) newPrimitiveTypeEncoder(t reflect.Type) encoderFunc {
   145  	switch t.Kind() {
   146  	// Note that we could use `gjson` to encode these types but it would complicate our
   147  	// code more and this current code shouldn't cause any issues
   148  	case reflect.String:
   149  		return func(v reflect.Value) ([]byte, error) {
   150  			return json.Marshal(v.Interface())
   151  		}
   152  	case reflect.Bool:
   153  		return func(v reflect.Value) ([]byte, error) {
   154  			if v.Bool() {
   155  				return []byte("true"), nil
   156  			}
   157  			return []byte("false"), nil
   158  		}
   159  	case reflect.Int, reflect.Int16, reflect.Int32, reflect.Int64:
   160  		return func(v reflect.Value) ([]byte, error) {
   161  			return []byte(strconv.FormatInt(v.Int(), 10)), nil
   162  		}
   163  	case reflect.Uint, reflect.Uint16, reflect.Uint32, reflect.Uint64:
   164  		return func(v reflect.Value) ([]byte, error) {
   165  			return []byte(strconv.FormatUint(v.Uint(), 10)), nil
   166  		}
   167  	case reflect.Float32:
   168  		return func(v reflect.Value) ([]byte, error) {
   169  			return []byte(strconv.FormatFloat(v.Float(), 'f', -1, 32)), nil
   170  		}
   171  	case reflect.Float64:
   172  		return func(v reflect.Value) ([]byte, error) {
   173  			return []byte(strconv.FormatFloat(v.Float(), 'f', -1, 64)), nil
   174  		}
   175  	default:
   176  		return func(v reflect.Value) ([]byte, error) {
   177  			return nil, fmt.Errorf("unknown type received at primitive encoder: %s", t.String())
   178  		}
   179  	}
   180  }
   181  
   182  func (e *encoder) newArrayTypeEncoder(t reflect.Type) encoderFunc {
   183  	itemEncoder := e.typeEncoder(t.Elem())
   184  
   185  	return func(value reflect.Value) ([]byte, error) {
   186  		json := []byte("[]")
   187  		for i := 0; i < value.Len(); i++ {
   188  			var value, err = itemEncoder(value.Index(i))
   189  			if err != nil {
   190  				return nil, err
   191  			}
   192  			if value == nil {
   193  				// Assume that empty items should be inserted as `null` so that the output array
   194  				// will be the same length as the input array
   195  				value = []byte("null")
   196  			}
   197  
   198  			json, err = sjson.SetRawBytes(json, "-1", value)
   199  			if err != nil {
   200  				return nil, err
   201  			}
   202  		}
   203  
   204  		return json, nil
   205  	}
   206  }
   207  
   208  func (e *encoder) newStructTypeEncoder(t reflect.Type) encoderFunc {
   209  	encoderFields := []encoderField{}
   210  	extraEncoder := (*encoderField)(nil)
   211  
   212  	// This helper allows us to recursively collect field encoders into a flat
   213  	// array. The parameter `index` keeps track of the access patterns necessary
   214  	// to get to some field.
   215  	var collectEncoderFields func(r reflect.Type, index []int)
   216  	collectEncoderFields = func(r reflect.Type, index []int) {
   217  		for i := 0; i < r.NumField(); i++ {
   218  			idx := append(index, i)
   219  			field := t.FieldByIndex(idx)
   220  			if !field.IsExported() {
   221  				continue
   222  			}
   223  			// If this is an embedded struct, traverse one level deeper to extract
   224  			// the field and get their encoders as well.
   225  			if field.Anonymous {
   226  				collectEncoderFields(field.Type, idx)
   227  				continue
   228  			}
   229  			// If json tag is not present, then we skip, which is intentionally
   230  			// different behavior from the stdlib.
   231  			ptag, ok := parseJSONStructTag(field)
   232  			if !ok {
   233  				continue
   234  			}
   235  			// We only want to support unexported field if they're tagged with
   236  			// `extras` because that field shouldn't be part of the public API. We
   237  			// also want to only keep the top level extras
   238  			if ptag.extras && len(index) == 0 {
   239  				extraEncoder = &encoderField{ptag, e.typeEncoder(field.Type.Elem()), idx}
   240  				continue
   241  			}
   242  			if ptag.name == "-" {
   243  				continue
   244  			}
   245  
   246  			dateFormat, ok := parseFormatStructTag(field)
   247  			oldFormat := e.dateFormat
   248  			if ok {
   249  				switch dateFormat {
   250  				case "date-time":
   251  					e.dateFormat = time.RFC3339
   252  				case "date":
   253  					e.dateFormat = "2006-01-02"
   254  				}
   255  			}
   256  			encoderFields = append(encoderFields, encoderField{ptag, e.typeEncoder(field.Type), idx})
   257  			e.dateFormat = oldFormat
   258  		}
   259  	}
   260  	collectEncoderFields(t, []int{})
   261  
   262  	// Ensure deterministic output by sorting by lexicographic order
   263  	sort.Slice(encoderFields, func(i, j int) bool {
   264  		return encoderFields[i].tag.name < encoderFields[j].tag.name
   265  	})
   266  
   267  	return func(value reflect.Value) (json []byte, err error) {
   268  		json = []byte("{}")
   269  
   270  		for _, ef := range encoderFields {
   271  			field := value.FieldByIndex(ef.idx)
   272  			encoded, err := ef.fn(field)
   273  			if err != nil {
   274  				return nil, err
   275  			}
   276  			if ef.tag.defaultValue != nil && (!field.IsValid() || field.IsZero()) {
   277  				encoded, err = shimjson.Marshal(ef.tag.defaultValue)
   278  				if err != nil {
   279  					return nil, err
   280  				}
   281  			}
   282  			if encoded == nil {
   283  				continue
   284  			}
   285  			json, err = sjson.SetRawBytes(json, EscapeSJSONKey(ef.tag.name), encoded)
   286  			if err != nil {
   287  				return nil, err
   288  			}
   289  		}
   290  
   291  		if extraEncoder != nil {
   292  			json, err = e.encodeMapEntries(json, value.FieldByIndex(extraEncoder.idx))
   293  			if err != nil {
   294  				return nil, err
   295  			}
   296  		}
   297  		return json, err
   298  	}
   299  }
   300  
   301  func (e *encoder) newTimeTypeEncoder() encoderFunc {
   302  	format := e.dateFormat
   303  	return func(value reflect.Value) (json []byte, err error) {
   304  		return []byte(`"` + value.Convert(reflect.TypeOf(time.Time{})).Interface().(time.Time).Format(format) + `"`), nil
   305  	}
   306  }
   307  
   308  func (e encoder) newInterfaceEncoder() encoderFunc {
   309  	return func(value reflect.Value) ([]byte, error) {
   310  		value = value.Elem()
   311  		if !value.IsValid() {
   312  			return nil, nil
   313  		}
   314  		return e.typeEncoder(value.Type())(value)
   315  	}
   316  }
   317  
   318  // Given a []byte of json (may either be an empty object or an object that already contains entries)
   319  // encode all of the entries in the map to the json byte array.
   320  func (e *encoder) encodeMapEntries(json []byte, v reflect.Value) ([]byte, error) {
   321  	type mapPair struct {
   322  		key   []byte
   323  		value reflect.Value
   324  	}
   325  
   326  	pairs := []mapPair{}
   327  	keyEncoder := e.typeEncoder(v.Type().Key())
   328  
   329  	iter := v.MapRange()
   330  	for iter.Next() {
   331  		var encodedKeyString string
   332  		if iter.Key().Type().Kind() == reflect.String {
   333  			encodedKeyString = iter.Key().String()
   334  		} else {
   335  			var err error
   336  			encodedKeyBytes, err := keyEncoder(iter.Key())
   337  			if err != nil {
   338  				return nil, err
   339  			}
   340  			encodedKeyString = string(encodedKeyBytes)
   341  		}
   342  		encodedKey := []byte(encodedKeyString)
   343  		pairs = append(pairs, mapPair{key: encodedKey, value: iter.Value()})
   344  	}
   345  
   346  	// Ensure deterministic output
   347  	sort.Slice(pairs, func(i, j int) bool {
   348  		return bytes.Compare(pairs[i].key, pairs[j].key) < 0
   349  	})
   350  
   351  	elementEncoder := e.typeEncoder(v.Type().Elem())
   352  	for _, p := range pairs {
   353  		encodedValue, err := elementEncoder(p.value)
   354  		if err != nil {
   355  			return nil, err
   356  		}
   357  		if len(encodedValue) == 0 {
   358  			continue
   359  		}
   360  		json, err = sjson.SetRawBytes(json, EscapeSJSONKey(string(p.key)), encodedValue)
   361  		if err != nil {
   362  			return nil, err
   363  		}
   364  	}
   365  
   366  	return json, nil
   367  }
   368  
   369  func (e *encoder) newMapEncoder(_ reflect.Type) encoderFunc {
   370  	return func(value reflect.Value) ([]byte, error) {
   371  		json := []byte("{}")
   372  		var err error
   373  		json, err = e.encodeMapEntries(json, value)
   374  		if err != nil {
   375  			return nil, err
   376  		}
   377  		return json, nil
   378  	}
   379  }