types/opt: support an explicit "unset" value for Bool

Updates #4843

Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
This commit is contained in:
Brad Fitzpatrick
2022-08-09 12:49:02 -07:00
committed by Brad Fitzpatrick
parent 3bb57504af
commit 8e821d7aa8
2 changed files with 55 additions and 15 deletions
+16 -9
View File
@@ -10,9 +10,13 @@ import (
"strconv"
)
// Bool represents an optional boolean to be JSON-encoded.
// The string can be empty (for unknown or unspecified), or
// "true" or "false".
// Bool represents an optional boolean to be JSON-encoded. The string
// is either "true", "false", or the enmpty string to mean unset.
//
// As a special case, the underlying string may also be the string
// "unset" as as a synonym for the empty string. This lets the
// explicit unset value be exchanged over an encoding/json "omitempty"
// field without it being dropped.
type Bool string
func (b *Bool) Set(v bool) {
@@ -22,11 +26,14 @@ func (b *Bool) Set(v bool) {
func (b *Bool) Clear() { *b = "" }
func (b Bool) Get() (v bool, ok bool) {
if b == "" {
return
switch b {
case "true":
return true, true
case "false":
return false, true
default:
return false, false
}
v, err := strconv.ParseBool(string(b))
return v, err == nil
}
// Scan implements database/sql.Scanner.
@@ -74,7 +81,7 @@ func (b Bool) MarshalJSON() ([]byte, error) {
return trueBytes, nil
case "false":
return falseBytes, nil
case "":
case "", "unset":
return nullBytes, nil
}
return nil, fmt.Errorf("invalid opt.Bool value %q", string(b))
@@ -94,7 +101,7 @@ func (b *Bool) UnmarshalJSON(j []byte) error {
return nil
}
if string(j) == "null" {
*b = ""
*b = "unset"
return nil
}
return fmt.Errorf("invalid opt.Bool value %q", j)