mak.go 1.8 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970
  1. // Copyright (c) Tailscale Inc & AUTHORS
  2. // SPDX-License-Identifier: BSD-3-Clause
  3. // Package mak helps make maps. It contains generic helpers to make/assign
  4. // things, notably to maps, but also slices.
  5. package mak
  6. import (
  7. "fmt"
  8. "reflect"
  9. )
  10. // Set populates an entry in a map, making the map if necessary.
  11. //
  12. // That is, it assigns (*m)[k] = v, making *m if it was nil.
  13. func Set[K comparable, V any, T ~map[K]V](m *T, k K, v V) {
  14. if *m == nil {
  15. *m = make(map[K]V)
  16. }
  17. (*m)[k] = v
  18. }
  19. // NonNil takes a pointer to a Go data structure
  20. // (currently only a slice or a map) and makes sure it's non-nil for
  21. // JSON serialization. (In particular, JavaScript clients usually want
  22. // the field to be defined after they decode the JSON.)
  23. //
  24. // Deprecated: use NonNilSliceForJSON or NonNilMapForJSON instead.
  25. func NonNil(ptr any) {
  26. if ptr == nil {
  27. panic("nil interface")
  28. }
  29. rv := reflect.ValueOf(ptr)
  30. if rv.Kind() != reflect.Ptr {
  31. panic(fmt.Sprintf("kind %v, not Ptr", rv.Kind()))
  32. }
  33. if rv.Pointer() == 0 {
  34. panic("nil pointer")
  35. }
  36. rv = rv.Elem()
  37. if rv.Pointer() != 0 {
  38. return
  39. }
  40. switch rv.Type().Kind() {
  41. case reflect.Slice:
  42. rv.Set(reflect.MakeSlice(rv.Type(), 0, 0))
  43. case reflect.Map:
  44. rv.Set(reflect.MakeMap(rv.Type()))
  45. }
  46. }
  47. // NonNilSliceForJSON makes sure that *slicePtr is non-nil so it will
  48. // won't be omitted from JSON serialization and possibly confuse JavaScript
  49. // clients expecting it to be present.
  50. func NonNilSliceForJSON[T any, S ~[]T](slicePtr *S) {
  51. if *slicePtr != nil {
  52. return
  53. }
  54. *slicePtr = make([]T, 0)
  55. }
  56. // NonNilMapForJSON makes sure that *slicePtr is non-nil so it will
  57. // won't be omitted from JSON serialization and possibly confuse JavaScript
  58. // clients expecting it to be present.
  59. func NonNilMapForJSON[K comparable, V any, M ~map[K]V](mapPtr *M) {
  60. if *mapPtr != nil {
  61. return
  62. }
  63. *mapPtr = make(M)
  64. }