github.com/aacfactory/fns@v1.2.86-0.20240310083819-80d667fc0a17/commons/versions/interval.go (about) 1 /* 2 * Copyright 2023 Wang Min Xiang 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 * 16 */ 17 18 package versions 19 20 import ( 21 "bytes" 22 "fmt" 23 "github.com/aacfactory/errors" 24 "github.com/aacfactory/fns/commons/bytex" 25 "github.com/valyala/bytebufferpool" 26 ) 27 28 type Interval []Version 29 30 func (interval Interval) Accept(target Version) (ok bool) { 31 n := len(interval) 32 if n == 0 { // [v0.0.0, latest) 33 ok = true 34 return 35 } 36 if n == 1 { // [{left}, latest) 37 ok = target.Between(interval[0], Latest()) 38 return 39 } 40 // [{left}, {right}}) 41 ok = target.Between(interval[0], interval[1]) 42 return 43 } 44 45 func (interval Interval) String() string { 46 n := len(interval) 47 if n == 0 { 48 return "[v0.0.0, latest)" 49 } 50 if n == 1 { 51 return fmt.Sprintf("[%s, latest)", interval[0].String()) 52 } 53 return fmt.Sprintf("[%s, %s)", interval[0].String(), interval[1].String()) 54 } 55 56 // ParseInterval 57 // left:right 58 func ParseInterval(source []byte) (interval Interval, err error) { 59 ss := bytes.Split(source, []byte{':'}) 60 n := len(ss) 61 if n == 0 { 62 interval = Interval{Origin(), Latest()} 63 return 64 } 65 if n == 1 { 66 ver, parseErr := Parse(ss[0]) 67 if parseErr != nil { 68 err = errors.Warning("fns: parse interval failed").WithMeta("source", bytex.ToString(source)).WithCause(parseErr) 69 return 70 } 71 interval = Interval{ver, Latest()} 72 return 73 } 74 if n == 2 { 75 left, leftErr := Parse(ss[0]) 76 if leftErr != nil { 77 err = errors.Warning("fns: parse interval failed").WithMeta("source", bytex.ToString(source)).WithCause(leftErr) 78 return 79 } 80 right, rightErr := Parse(ss[1]) 81 if rightErr != nil { 82 err = errors.Warning("fns: parse interval failed").WithMeta("source", bytex.ToString(source)).WithCause(rightErr) 83 return 84 } 85 if right.LessThan(left) { 86 err = errors.Warning("fns: parse interval failed").WithMeta("source", bytex.ToString(source)).WithCause(fmt.Errorf("invalid interval")) 87 return 88 } 89 interval = Interval{left, right} 90 return 91 } 92 err = errors.Warning("fns: parse interval failed").WithMeta("source", bytex.ToString(source)).WithCause(fmt.Errorf("invalid interval")) 93 return 94 } 95 96 type NamedInterval struct { 97 Name []byte `json:"name"` 98 Value Interval `json:"value"` 99 } 100 101 type Intervals []NamedInterval 102 103 func (intervals Intervals) Accept(name []byte, target Version) (ok bool) { 104 if len(intervals) == 0 { 105 ok = true 106 return 107 } 108 for _, interval := range intervals { 109 if bytes.Equal(name, interval.Name) { 110 ok = interval.Value.Accept(target) 111 break 112 } 113 } 114 return 115 } 116 117 func (intervals Intervals) Get(name []byte) (interval Interval, has bool) { 118 if len(intervals) == 0 { 119 return 120 } 121 for _, namedInterval := range intervals { 122 if bytes.Equal(name, namedInterval.Name) { 123 interval = namedInterval.Value 124 has = true 125 return 126 } 127 } 128 return 129 } 130 131 func (intervals Intervals) Bytes() []byte { 132 if len(intervals) == 0 { 133 return []byte{} 134 } 135 p := bytebufferpool.Get() 136 defer bytebufferpool.Put(p) 137 for _, interval := range intervals { 138 _, _ = p.Write([]byte{',', ' '}) 139 _, _ = p.Write(interval.Name) 140 _, _ = p.Write([]byte{'='}) 141 _, _ = p.Write(bytex.FromString(interval.Value.String())) 142 } 143 return p.Bytes()[2:] 144 } 145 146 func (intervals Intervals) String() string { 147 return bytex.ToString(intervals.Bytes()) 148 } 149 150 // ParseIntervals 151 // key=left:right, ... 152 func ParseIntervals(source []byte) (intervals Intervals, err error) { 153 if len(source) == 0 { 154 return 155 } 156 ss := bytes.Split(source, []byte{','}) 157 for _, s := range ss { 158 s = bytes.TrimSpace(s) 159 idx := bytes.IndexByte(s, '=') 160 if idx < 1 { 161 err = errors.Warning("fns: parse intervals failed").WithMeta("source", bytex.ToString(source)).WithCause(fmt.Errorf("invalid intervals")) 162 return 163 } 164 name := bytes.TrimSpace(s[0:idx]) 165 interval, parseErr := ParseInterval(s[idx+1:]) 166 if parseErr != nil { 167 err = errors.Warning("fns: parse intervals failed").WithMeta("source", bytex.ToString(source)).WithCause(parseErr) 168 return 169 } 170 if intervals == nil { 171 intervals = make(Intervals, 0, 1) 172 } 173 intervals = append(intervals, NamedInterval{ 174 Name: name, 175 Value: interval, 176 }) 177 } 178 return 179 }