github.com/rclone/rclone@v1.66.1-0.20240517100346-7b89735ae726/fs/tristate.go (about) 1 package fs 2 3 import ( 4 "encoding/json" 5 "fmt" 6 "strconv" 7 "strings" 8 ) 9 10 // Tristate is a boolean that can has the states, true, false and 11 // unset/invalid/nil 12 type Tristate struct { 13 Value bool 14 Valid bool 15 } 16 17 // String renders the tristate as true/false/unset 18 func (t Tristate) String() string { 19 if !t.Valid { 20 return "unset" 21 } 22 if t.Value { 23 return "true" 24 } 25 return "false" 26 } 27 28 // Set the List entries 29 func (t *Tristate) Set(s string) error { 30 s = strings.ToLower(s) 31 if s == "" || s == "nil" || s == "null" || s == "unset" { 32 t.Valid = false 33 return nil 34 } 35 value, err := strconv.ParseBool(s) 36 if err != nil { 37 return fmt.Errorf("failed to parse Tristate %q: %w", s, err) 38 } 39 t.Value = value 40 t.Valid = true 41 return nil 42 } 43 44 // Type of the value 45 func (Tristate) Type() string { 46 return "Tristate" 47 } 48 49 // Scan implements the fmt.Scanner interface 50 func (t *Tristate) Scan(s fmt.ScanState, ch rune) error { 51 token, err := s.Token(true, nil) 52 if err != nil { 53 return err 54 } 55 return t.Set(string(token)) 56 } 57 58 // UnmarshalJSON parses it as a bool or nil for unset 59 func (t *Tristate) UnmarshalJSON(in []byte) error { 60 var b *bool 61 err := json.Unmarshal(in, &b) 62 if err != nil { 63 return err 64 } 65 if b != nil { 66 t.Valid = true 67 t.Value = *b 68 } else { 69 t.Valid = false 70 } 71 return nil 72 } 73 74 // MarshalJSON encodes it as a bool or nil for unset 75 func (t *Tristate) MarshalJSON() ([]byte, error) { 76 if !t.Valid { 77 return json.Marshal(nil) 78 } 79 return json.Marshal(t.Value) 80 }