mirror of
https://github.com/tailscale/tailscale.git
synced 2025-08-21 02:17:36 +00:00
tailcfg: add Hostinfo.HowUnequal method
Change-Id: I80ee49c2ab581feccc4aa6ab47bc3c8392d9989d Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
This commit is contained in:

committed by
Brad Fitzpatrick

parent
0aa4c6f147
commit
bc537adb1a
@@ -577,6 +577,68 @@ func (h *Hostinfo) Equal(h2 *Hostinfo) bool {
|
||||
return reflect.DeepEqual(h, h2)
|
||||
}
|
||||
|
||||
// HowUnequal returns a list of paths through Hostinfo where h and h2 differ.
|
||||
// If they differ in nil-ness, the path is "nil", otherwise the path is like
|
||||
// "ShieldsUp" or "NetInfo.nil" or "NetInfo.PCP".
|
||||
func (h *Hostinfo) HowUnequal(h2 *Hostinfo) (path []string) {
|
||||
return appendStructPtrDiff(nil, "", reflect.ValueOf(h), reflect.ValueOf(h2))
|
||||
}
|
||||
|
||||
func appendStructPtrDiff(base []string, pfx string, p1, p2 reflect.Value) (ret []string) {
|
||||
ret = base
|
||||
if p1.IsNil() && p2.IsNil() {
|
||||
return base
|
||||
}
|
||||
mkPath := func(b string) string {
|
||||
if pfx == "" {
|
||||
return b
|
||||
}
|
||||
return pfx + "." + b
|
||||
}
|
||||
if p1.IsNil() || p2.IsNil() {
|
||||
return append(base, mkPath("nil"))
|
||||
}
|
||||
v1, v2 := p1.Elem(), p2.Elem()
|
||||
t := v1.Type()
|
||||
for i, n := 0, t.NumField(); i < n; i++ {
|
||||
sf := t.Field(i)
|
||||
switch sf.Type.Kind() {
|
||||
case reflect.String:
|
||||
if v1.Field(i).String() != v2.Field(i).String() {
|
||||
ret = append(ret, mkPath(sf.Name))
|
||||
}
|
||||
continue
|
||||
case reflect.Bool:
|
||||
if v1.Field(i).Bool() != v2.Field(i).Bool() {
|
||||
ret = append(ret, mkPath(sf.Name))
|
||||
}
|
||||
continue
|
||||
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
||||
if v1.Field(i).Int() != v2.Field(i).Int() {
|
||||
ret = append(ret, mkPath(sf.Name))
|
||||
}
|
||||
continue
|
||||
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
|
||||
if v1.Field(i).Uint() != v2.Field(i).Uint() {
|
||||
ret = append(ret, mkPath(sf.Name))
|
||||
}
|
||||
continue
|
||||
case reflect.Slice, reflect.Map:
|
||||
if !reflect.DeepEqual(v1.Field(i).Interface(), v2.Field(i).Interface()) {
|
||||
ret = append(ret, mkPath(sf.Name))
|
||||
}
|
||||
continue
|
||||
case reflect.Ptr:
|
||||
if sf.Type.Elem().Kind() == reflect.Struct {
|
||||
ret = appendStructPtrDiff(ret, sf.Name, v1.Field(i), v2.Field(i))
|
||||
continue
|
||||
}
|
||||
}
|
||||
panic(fmt.Sprintf("unsupported type at %s: %s", mkPath(sf.Name), sf.Type.String()))
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
// SignatureType specifies a scheme for signing RegisterRequest messages. It
|
||||
// specifies the crypto algorithms to use, the contents of what is signed, and
|
||||
// any other relevant details. Historically, requests were unsigned so the zero
|
||||
|
Reference in New Issue
Block a user