cuelang.org/go@v0.10.1/pkg/list/list.go (about) 1 // Copyright 2019 CUE Authors 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 // Package list contains functions for manipulating and examining lists. 16 package list 17 18 import ( 19 "fmt" 20 "slices" 21 "sort" 22 23 "cuelang.org/go/cue" 24 "cuelang.org/go/cue/errors" 25 "cuelang.org/go/cue/token" 26 "cuelang.org/go/internal/core/adt" 27 "cuelang.org/go/internal/pkg" 28 ) 29 30 // Drop reports the suffix of list x after the first n elements, 31 // or [] if n > len(x). 32 // 33 // For instance: 34 // 35 // Drop([1, 2, 3, 4], 2) 36 // 37 // results in 38 // 39 // [3, 4] 40 func Drop(x []cue.Value, n int) ([]cue.Value, error) { 41 if n < 0 { 42 return nil, fmt.Errorf("negative index") 43 } 44 45 if n > len(x) { 46 return []cue.Value{}, nil 47 } 48 49 return x[n:], nil 50 } 51 52 // TODO: disable Flatten until we know the right default for depth. 53 // The right time to determine is at least some point after the query 54 // extensions are introduced, which may provide flatten functionality 55 // natively. 56 // 57 // // Flatten reports a flattened sequence of the list xs by expanding any elements 58 // // that are lists. 59 // // 60 // // For instance: 61 // // 62 // // Flatten([1, [[2, 3], []], [4]]) 63 // // 64 // // results in 65 // // 66 // // [1, 2, 3, 4] 67 // // 68 // func Flatten(xs cue.Value) ([]cue.Value, error) { 69 // var flatten func(cue.Value) ([]cue.Value, error) 70 // flatten = func(xs cue.Value) ([]cue.Value, error) { 71 // var res []cue.Value 72 // iter, err := xs.List() 73 // if err != nil { 74 // return nil, err 75 // } 76 // for iter.Next() { 77 // val := iter.Value() 78 // if val.Kind() == cue.ListKind { 79 // vals, err := flatten(val) 80 // if err != nil { 81 // return nil, err 82 // } 83 // res = append(res, vals...) 84 // } else { 85 // res = append(res, val) 86 // } 87 // } 88 // return res, nil 89 // } 90 // return flatten(xs) 91 // } 92 93 // FlattenN reports a flattened sequence of the list xs by expanding any elements 94 // depth levels deep. If depth is negative all elements are expanded. 95 // 96 // For instance: 97 // 98 // FlattenN([1, [[2, 3], []], [4]], 1) 99 // 100 // results in 101 // 102 // [1, [2, 3], [], 4] 103 func FlattenN(xs cue.Value, depth int) ([]cue.Value, error) { 104 var flattenN func(cue.Value, int) ([]cue.Value, error) 105 flattenN = func(xs cue.Value, depth int) ([]cue.Value, error) { 106 var res []cue.Value 107 iter, err := xs.List() 108 if err != nil { 109 return nil, err 110 } 111 for iter.Next() { 112 val, _ := iter.Value().Default() 113 if val.Kind() == cue.ListKind && depth != 0 { 114 d := depth - 1 115 values, err := flattenN(val, d) 116 if err != nil { 117 return nil, err 118 } 119 res = append(res, values...) 120 } else { 121 res = append(res, val) 122 } 123 } 124 return res, nil 125 } 126 return flattenN(xs, depth) 127 } 128 129 // Repeat returns a new list consisting of count copies of list x. 130 // 131 // For instance: 132 // 133 // Repeat([1, 2], 2) 134 // 135 // results in 136 // 137 // [1, 2, 1, 2] 138 func Repeat(x []cue.Value, count int) ([]cue.Value, error) { 139 if count < 0 { 140 return nil, fmt.Errorf("negative count") 141 } 142 var a []cue.Value 143 for range count { 144 a = append(a, x...) 145 } 146 return a, nil 147 } 148 149 // Concat takes a list of lists and concatenates them. 150 // 151 // Concat([a, b, c]) is equivalent to 152 // 153 // [for x in a {x}, for x in b {x}, for x in c {x}] 154 func Concat(a []cue.Value) ([]cue.Value, error) { 155 var res []cue.Value 156 for _, e := range a { 157 iter, err := e.List() 158 if err != nil { 159 return nil, err 160 } 161 for iter.Next() { 162 res = append(res, iter.Value()) 163 } 164 } 165 return res, nil 166 } 167 168 // Take reports the prefix of length n of list x, or x itself if n > len(x). 169 // 170 // For instance: 171 // 172 // Take([1, 2, 3, 4], 2) 173 // 174 // results in 175 // 176 // [1, 2] 177 func Take(x []cue.Value, n int) ([]cue.Value, error) { 178 if n < 0 { 179 return nil, fmt.Errorf("negative index") 180 } 181 182 if n > len(x) { 183 return x, nil 184 } 185 186 return x[:n], nil 187 } 188 189 // Slice extracts the consecutive elements from list x starting from position i 190 // up till, but not including, position j, where 0 <= i < j <= len(x). 191 // 192 // For instance: 193 // 194 // Slice([1, 2, 3, 4], 1, 3) 195 // 196 // results in 197 // 198 // [2, 3] 199 func Slice(x []cue.Value, i, j int) ([]cue.Value, error) { 200 if i < 0 { 201 return nil, fmt.Errorf("negative index") 202 } 203 204 if i > j { 205 return nil, fmt.Errorf("invalid index: %v > %v", i, j) 206 } 207 208 if i > len(x) { 209 return nil, fmt.Errorf("slice bounds out of range") 210 } 211 212 if j > len(x) { 213 return nil, fmt.Errorf("slice bounds out of range") 214 } 215 216 return x[i:j], nil 217 } 218 219 // Reverse reverses a list. 220 // 221 // For instance: 222 // 223 // Reverse([1, 2, 3, 4]) 224 // 225 // results in 226 // 227 // [4, 3, 2, 1] 228 func Reverse(x []cue.Value) []cue.Value { 229 slices.Reverse(x) 230 return x 231 } 232 233 // MinItems reports whether a has at least n items. 234 func MinItems(list pkg.List, n int) (bool, error) { 235 count := len(list.Elems()) 236 if count >= n { 237 return true, nil 238 } 239 code := adt.EvalError 240 if list.IsOpen() { 241 code = adt.IncompleteError 242 } 243 return false, pkg.ValidationError{B: &adt.Bottom{ 244 Code: code, 245 Err: errors.Newf(token.NoPos, "len(list) < MinItems(%[2]d) (%[1]d < %[2]d)", count, n), 246 }} 247 } 248 249 // MaxItems reports whether a has at most n items. 250 func MaxItems(list pkg.List, n int) (bool, error) { 251 count := len(list.Elems()) 252 if count > n { 253 return false, pkg.ValidationError{B: &adt.Bottom{ 254 Code: adt.EvalError, 255 Err: errors.Newf(token.NoPos, "len(list) > MaxItems(%[2]d) (%[1]d > %[2]d)", count, n), 256 }} 257 } 258 259 return true, nil 260 } 261 262 // UniqueItems reports whether all elements in the list are unique. 263 func UniqueItems(a []cue.Value) bool { 264 b := []string{} 265 for _, v := range a { 266 b = append(b, fmt.Sprintf("%+v", v)) 267 } 268 sort.Strings(b) 269 for i := 1; i < len(b); i++ { 270 if b[i-1] == b[i] { 271 return false 272 } 273 } 274 return true 275 } 276 277 // Contains reports whether v is contained in a. The value must be a 278 // comparable value. 279 func Contains(a []cue.Value, v cue.Value) bool { 280 for _, w := range a { 281 if v.Equals(w) { 282 return true 283 } 284 } 285 return false 286 }