feature.go 1.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778
  1. // Copyright (c) Tailscale Inc & AUTHORS
  2. // SPDX-License-Identifier: BSD-3-Clause
  3. // Package feature tracks which features are linked into the binary.
  4. package feature
  5. import "reflect"
  6. var in = map[string]bool{}
  7. // Register notes that the named feature is linked into the binary.
  8. func Register(name string) {
  9. if _, ok := in[name]; ok {
  10. panic("duplicate feature registration for " + name)
  11. }
  12. in[name] = true
  13. }
  14. // Hook is a func that can only be set once.
  15. //
  16. // It is not safe for concurrent use.
  17. type Hook[Func any] struct {
  18. f Func
  19. ok bool
  20. }
  21. // IsSet reports whether the hook has been set.
  22. func (h *Hook[Func]) IsSet() bool {
  23. return h.ok
  24. }
  25. // Set sets the hook function, panicking if it's already been set
  26. // or f is the zero value.
  27. //
  28. // It's meant to be called in init.
  29. func (h *Hook[Func]) Set(f Func) {
  30. if h.ok {
  31. panic("Set on already-set feature hook")
  32. }
  33. if reflect.ValueOf(f).IsZero() {
  34. panic("Set with zero value")
  35. }
  36. h.f = f
  37. h.ok = true
  38. }
  39. // Get returns the hook function, or panics if it hasn't been set.
  40. // Use IsSet to check if it's been set.
  41. func (h *Hook[Func]) Get() Func {
  42. if !h.ok {
  43. panic("Get on unset feature hook, without IsSet")
  44. }
  45. return h.f
  46. }
  47. // GetOk returns the hook function and true if it has been set,
  48. // otherwise its zero value and false.
  49. func (h *Hook[Func]) GetOk() (f Func, ok bool) {
  50. return h.f, h.ok
  51. }
  52. // Hooks is a slice of funcs.
  53. //
  54. // As opposed to a single Hook, this is meant to be used when
  55. // multiple parties are able to install the same hook.
  56. type Hooks[Func any] []Func
  57. // Add adds a hook to the list of hooks.
  58. //
  59. // Add should only be called during early program
  60. // startup before Tailscale has started.
  61. // It is not safe for concurrent use.
  62. func (h *Hooks[Func]) Add(f Func) {
  63. if reflect.ValueOf(f).IsZero() {
  64. panic("Add with zero value")
  65. }
  66. *h = append(*h, f)
  67. }