github.imxd.top/openshift/source-to-image@v1.2.0/pkg/util/user/range.go (about) 1 package user 2 3 import ( 4 "errors" 5 "fmt" 6 "strconv" 7 "strings" 8 ) 9 10 // Range errors 11 var ( 12 ErrInvalidRange = errors.New("invalid range; a range must consist of positive integers and the upper bound must be greater than or equal to the lower bound") 13 ) 14 15 // ErrParseRange is an error encountered while parsing a Range 16 type ErrParseRange struct { 17 cause error 18 } 19 20 func (e *ErrParseRange) Error() string { 21 msg := "error parsing range; a range must be of one of the following formats: [n], [-n], [n-], [n:m] where n and m are positive numbers and m is greater than or equal to n" 22 if e.cause != nil { 23 msg = fmt.Sprintf("%s: %v", msg, e.cause) 24 } 25 return msg 26 } 27 28 // Range represents a range of user ids. It can be unbound at either end with a nil value 29 // I both From and To are present, To must be greater than or equal to From. Bounds are inclusive 30 type Range struct { 31 from *int 32 to *int 33 } 34 35 // NewRange creates a new range with lower and upper bound 36 func NewRange(from int, to int) (*Range, error) { 37 return (&rangeBuilder{}).from(from, nil).to(to, nil).Range() 38 } 39 40 // NewRangeTo creates a new range with only the upper bound 41 func NewRangeTo(to int) (*Range, error) { 42 return (&rangeBuilder{}).to(to, nil).Range() 43 } 44 45 // NewRangeFrom creates a new range with only the lower bound 46 func NewRangeFrom(from int) (*Range, error) { 47 return (&rangeBuilder{}).from(from, nil).Range() 48 } 49 50 func parseInt(str string) (int, error) { 51 num, err := strconv.Atoi(str) 52 if err != nil { 53 return 0, &ErrParseRange{cause: err} 54 } 55 return num, nil 56 } 57 58 type rangeBuilder struct { 59 r Range 60 err error 61 } 62 63 func (b *rangeBuilder) from(num int, err error) *rangeBuilder { 64 return b.setBound(num, err, &b.r.from) 65 } 66 67 func (b *rangeBuilder) to(num int, err error) *rangeBuilder { 68 return b.setBound(num, err, &b.r.to) 69 } 70 71 func (b *rangeBuilder) setBound(num int, err error, bound **int) *rangeBuilder { 72 if b.err != nil { 73 return b 74 } 75 if b.err = err; b.err != nil { 76 return b 77 } 78 if num < 0 { 79 b.err = ErrInvalidRange 80 return b 81 } 82 *bound = &num 83 return b 84 } 85 86 // Range returns the completed Range from the rangeBuilder. 87 func (b *rangeBuilder) Range() (*Range, error) { 88 if b.err != nil { 89 return nil, b.err 90 } 91 if b.r.from != nil && b.r.to != nil && *b.r.to < *b.r.from { 92 return nil, ErrInvalidRange 93 } 94 return &b.r, nil 95 } 96 97 // ParseRange creates a Range from a given string 98 func ParseRange(value string) (*Range, error) { 99 value = strings.TrimSpace(value) 100 b := &rangeBuilder{} 101 if value == "" { 102 return b.Range() 103 } 104 parts := strings.Split(value, "-") 105 switch len(parts) { 106 case 1: 107 num, err := parseInt(parts[0]) 108 return b.from(num, err).to(num, err).Range() 109 case 2: 110 if parts[0] != "" { 111 b.from(parseInt(parts[0])) 112 } 113 if parts[1] != "" { 114 b.to(parseInt(parts[1])) 115 } 116 return b.Range() 117 default: 118 return nil, &ErrParseRange{} 119 } 120 } 121 122 // Contains returns true if the argument falls inside the Range 123 func (r *Range) Contains(value int) bool { 124 if r.from == nil && r.to == nil { 125 return false 126 } 127 if r.from != nil && value < *r.from { 128 return false 129 } 130 if r.to != nil && value > *r.to { 131 return false 132 } 133 return true 134 } 135 136 // String returns a parse-able string representation of a Range 137 func (r *Range) String() string { 138 switch { 139 case r.from == nil && r.to == nil: 140 return "" 141 case r.from == nil: 142 return fmt.Sprintf("-%d", *r.to) 143 case r.to == nil: 144 return fmt.Sprintf("%d-", *r.from) 145 case *r.from == *r.to: 146 return fmt.Sprintf("%d", *r.to) 147 default: 148 return fmt.Sprintf("%d-%d", *r.from, *r.to) 149 } 150 } 151 152 // Type returns the type of a Range object 153 func (r *Range) Type() string { 154 return "user.Range" 155 } 156 157 // Set sets the value of a Range object 158 func (r *Range) Set(value string) error { 159 newRange, err := ParseRange(value) 160 if err != nil { 161 return err 162 } 163 *r = *newRange 164 return nil 165 } 166 167 // Empty returns true if the range has no bounds 168 func (r *Range) Empty() bool { 169 return r.from == nil && r.to == nil 170 }