File: bits.go

package info (click to toggle)
rclone 1.69.3%2Bdfsg-1
  • links: PTS, VCS
  • area: main
  • in suites:
  • size: 45,716 kB
  • sloc: sh: 1,115; xml: 857; python: 754; javascript: 612; makefile: 299; ansic: 101; php: 74
file content (153 lines) | stat: -rw-r--r-- 3,356 bytes parent folder | download | duplicates (3)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
package fs

import (
	"encoding/json"
	"fmt"
	"strings"
)

// Bits is an option which can be any combination of the Choices.
//
// Suggested implementation is something like this:
//
//	type bits = Bits[bitsChoices]
//
//	const (
//		bitA bits = 1 << iota
//		bitB
//		bitC
//	)
//
//	type bitsChoices struct{}
//
//	func (bitsChoices) Choices() []BitsChoicesInfo {
//		return []BitsChoicesInfo{
//			{Bit: uint64(0), Name: "OFF"}, // Optional Off value - "" if not defined
//			{Bit: uint64(bitA), Name: "A"},
//			{Bit: uint64(bitB), Name: "B"},
//			{Bit: uint64(bitC), Name: "C"},
//		}
//	}
type Bits[C BitsChoices] uint64

// BitsChoicesInfo should be returned from the Choices method
type BitsChoicesInfo struct {
	Bit  uint64
	Name string
}

// BitsChoices returns the valid choices for this type.
//
// It must work on the zero value.
//
// Note that when using this in an Option the ExampleBitsChoices will be
// filled in automatically.
type BitsChoices interface {
	// Choices returns the valid choices for each bit of this type
	Choices() []BitsChoicesInfo
}

// String turns a Bits into a string
func (b Bits[C]) String() string {
	var out []string
	choices := b.Choices()
	// Return an off value if set
	if b == 0 {
		for _, info := range choices {
			if info.Bit == 0 {
				return info.Name
			}
		}
	}
	for _, info := range choices {
		if info.Bit == 0 {
			continue
		}
		if b&Bits[C](info.Bit) != 0 {
			out = append(out, info.Name)
			b &^= Bits[C](info.Bit)
		}
	}
	if b != 0 {
		out = append(out, fmt.Sprintf("Unknown-0x%X", int(b)))
	}
	return strings.Join(out, ",")
}

// Help returns a comma separated list of all possible bits.
func (b Bits[C]) Help() string {
	var out []string
	for _, info := range b.Choices() {
		out = append(out, info.Name)
	}
	return strings.Join(out, ", ")
}

// Choices returns the possible values of the Bits.
func (b Bits[C]) Choices() []BitsChoicesInfo {
	var c C
	return c.Choices()
}

// Set a Bits as a comma separated list of flags
func (b *Bits[C]) Set(s string) error {
	var flags Bits[C]
	parts := strings.Split(s, ",")
	choices := b.Choices()
	for _, part := range parts {
		found := false
		part = strings.TrimSpace(part)
		if part == "" {
			continue
		}
		for _, info := range choices {
			if strings.EqualFold(info.Name, part) {
				found = true
				flags |= Bits[C](info.Bit)
			}
		}
		if !found {
			return fmt.Errorf("invalid choice %q from: %s", part, b.Help())
		}
	}
	*b = flags
	return nil
}

// IsSet returns true all the bits in mask are set in b.
func (b Bits[C]) IsSet(mask Bits[C]) bool {
	return (b & mask) == mask
}

// Type of the value.
//
// If C has a Type() string method then it will be used instead.
func (b Bits[C]) Type() string {
	var c C
	if do, ok := any(c).(typer); ok {
		return do.Type()
	}
	return "Bits"
}

// Scan implements the fmt.Scanner interface
func (b *Bits[C]) Scan(s fmt.ScanState, ch rune) error {
	token, err := s.Token(true, nil)
	if err != nil {
		return err
	}
	return b.Set(string(token))
}

// UnmarshalJSON makes sure the value can be parsed as a string or integer in JSON
func (b *Bits[C]) UnmarshalJSON(in []byte) error {
	return UnmarshalJSONFlag(in, b, func(i int64) error {
		*b = (Bits[C])(i)
		return nil
	})
}

// MarshalJSON encodes it as string
func (b *Bits[C]) MarshalJSON() ([]byte, error) {
	return json.Marshal(b.String())
}