types/opt: support an explicit "unset" value for Bool
Updates #4843 Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
This commit is contained in:
committed by
Brad Fitzpatrick
parent
3bb57504af
commit
8e821d7aa8
+16
-9
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user