github.com/m4gshm/gollections@v0.0.10/break/loop/api.go (about) 1 // Package loop provides helpers for loop operation and iterator implementations 2 package loop 3 4 import ( 5 "errors" 6 7 "github.com/m4gshm/gollections/break/predicate/always" 8 "github.com/m4gshm/gollections/c" 9 "github.com/m4gshm/gollections/convert" 10 "github.com/m4gshm/gollections/convert/as" 11 "github.com/m4gshm/gollections/map_/resolv" 12 "github.com/m4gshm/gollections/notsafe" 13 "github.com/m4gshm/gollections/op" 14 "github.com/m4gshm/gollections/op/check/not" 15 ) 16 17 // ErrBreak is the 'break' statement of the For, Track methods 18 var ErrBreak = c.ErrBreak 19 20 // Looper provides an iterable loop function 21 type Looper[T any, I interface{ Next() (T, bool, error) }] interface { 22 Loop() I 23 } 24 25 // Of wrap the elements by loop function 26 func Of[T any](elements ...T) func() (e T, ok bool, err error) { 27 l := len(elements) 28 i := 0 29 if l == 0 || i < 0 || i >= l { 30 return func() (e T, ok bool, err error) { return e, false, nil } 31 } 32 return func() (e T, ok bool, err error) { 33 if i < l { 34 e, ok = elements[i], true 35 i++ 36 } 37 return e, ok, nil 38 } 39 } 40 41 // From wrap the next loop to a breakable loop 42 func From[T any](next func() (T, bool)) func() (T, bool, error) { 43 return func() (T, bool, error) { 44 e, ok := next() 45 return e, ok, nil 46 } 47 } 48 49 // To transforms a breakable loop to a simple loop. 50 // The errConsumer is a function that is called when an error occurs. 51 func To[T any](next func() (T, bool, error), errConsumer func(error)) func() (T, bool) { 52 return func() (T, bool) { 53 e, ok, err := next() 54 if err != nil { 55 errConsumer(err) 56 return e, false 57 } 58 return e, ok 59 } 60 } 61 62 // For applies the 'walker' function for the elements retrieved by the 'next' function. Return the c.ErrBreak to stop 63 func For[T any](next func() (T, bool, error), walker func(T) error) error { 64 for { 65 if v, ok, err := next(); err != nil || !ok { 66 return err 67 } else if err := walker(v); err != nil { 68 return brk(err) 69 } 70 } 71 } 72 73 // ForFiltered applies the 'walker' function to the elements retrieved by the 'next' function that satisfy the 'predicate' function condition 74 func ForFiltered[T any](next func() (T, bool, error), walker func(T) error, predicate func(T) bool) error { 75 for { 76 if v, ok, err := next(); err != nil || !ok { 77 return err 78 } else if ok := predicate(v); ok { 79 if err := walker(v); err != nil { 80 return brk(err) 81 } 82 } 83 } 84 } 85 86 // First returns the first element that satisfies the condition of the 'predicate' function 87 func First[T any](next func() (T, bool, error), predicate func(T) bool) (T, bool, error) { 88 for { 89 if out, ok, err := next(); err != nil || !ok { 90 return out, false, err 91 } else if ok := predicate(out); ok { 92 return out, true, nil 93 } 94 } 95 } 96 97 // Firstt returns the first element that satisfies the condition of the 'predicate' function 98 func Firstt[T any](next func() (T, bool, error), predicate func(T) (bool, error)) (T, bool, error) { 99 for { 100 if out, ok, err := next(); err != nil || !ok { 101 return out, false, err 102 } else if ok, err := predicate(out); err != nil || ok { 103 return out, ok, err 104 } 105 } 106 } 107 108 // Track applies the 'tracker' function to position/element pairs retrieved by the 'next' function. Return the c.ErrBreak to stop tracking.. 109 func Track[I, T any](next func() (I, T, bool, error), tracker func(I, T) error) error { 110 for { 111 if p, v, ok, err := next(); err != nil || !ok { 112 return err 113 } else if err := tracker(p, v); err != nil { 114 return brk(err) 115 } 116 } 117 } 118 119 // Slice collects the elements retrieved by the 'next' function into a slice 120 func Slice[T any](next func() (T, bool, error)) (out []T, err error) { 121 for { 122 v, ok, err := next() 123 if ok { 124 out = append(out, v) 125 } 126 if !ok || err != nil { 127 return out, err 128 } 129 } 130 } 131 132 // SliceCap collects the elements retrieved by the 'next' function into a new slice with predefined capacity 133 func SliceCap[T any](next func() (T, bool, error), cap int) (out []T, err error) { 134 if cap > 0 { 135 out = make([]T, 0, cap) 136 } 137 return Append(next, out) 138 } 139 140 // Append collects the elements retrieved by the 'next' function into the specified 'out' slice 141 func Append[T any, TS ~[]T](next func() (T, bool, error), out TS) (TS, error) { 142 for v, ok, err := next(); ok; v, ok, err = next() { 143 if err != nil { 144 return out, err 145 } 146 out = append(out, v) 147 } 148 return out, nil 149 } 150 151 // Reduce reduces the elements retrieved by the 'next' function into an one using the 'merge' function 152 func Reduce[T any](next func() (T, bool, error), merger func(T, T) T) (out T, e error) { 153 v, ok, err := next() 154 if err != nil || !ok { 155 return out, err 156 } 157 out = v 158 for { 159 v, ok, err := next() 160 if err != nil || !ok { 161 return out, err 162 } 163 out = merger(out, v) 164 } 165 } 166 167 // Reducee reduces the elements retrieved by the 'next' function into an one using the 'merge' function 168 func Reducee[T any](next func() (T, bool, error), merger func(T, T) (T, error)) (out T, e error) { 169 v, ok, err := next() 170 if err != nil || !ok { 171 return out, err 172 } 173 out = v 174 for { 175 if v, ok, err := next(); err != nil || !ok { 176 return out, err 177 } else if out, err = merger(out, v); err != nil { 178 return out, err 179 } 180 } 181 } 182 183 // Sum returns the sum of all elements 184 func Sum[T c.Summable](next func() (T, bool, error)) (T, error) { 185 return Reduce(next, op.Sum[T]) 186 } 187 188 // HasAny finds the first element that satisfies the 'predicate' function condition and returns true if successful 189 func HasAny[T any](next func() (T, bool, error), predicate func(T) bool) (bool, error) { 190 _, ok, err := First(next, predicate) 191 return ok, err 192 } 193 194 // HasAnyy finds the first element that satisfies the 'predicate' function condition and returns true if successful 195 func HasAnyy[T any](next func() (T, bool, error), predicate func(T) (bool, error)) (bool, error) { 196 _, ok, err := Firstt(next, predicate) 197 return ok, err 198 } 199 200 // Contains finds the first element that equal to the example and returns true 201 func Contains[T comparable](next func() (T, bool, error), example T) (bool, error) { 202 for { 203 if one, ok, err := next(); err != nil || !ok { 204 return false, err 205 } else if one == example { 206 return true, nil 207 } 208 } 209 } 210 211 // Conv instantiates an iterator that converts elements with a converter and returns them. 212 func Conv[From, To any](next func() (From, bool, error), converter func(From) (To, error)) ConvertIter[From, To] { 213 return ConvertIter[From, To]{next: next, converter: converter} 214 } 215 216 // Convert instantiates an iterator that converts elements with a converter and returns them. 217 func Convert[From, To any](next func() (From, bool, error), converter func(From) To) ConvertIter[From, To] { 218 return ConvertIter[From, To]{next: next, converter: func(f From) (To, error) { return converter(f), nil }} 219 } 220 221 // ConvCheck is similar to ConvertFilt, but it checks and transforms elements together 222 func ConvCheck[From, To any](next func() (From, bool, error), converter func(from From) (To, bool, error)) ConvertCheckIter[From, To] { 223 return ConvertCheckIter[From, To]{next: next, converter: converter} 224 } 225 226 // ConvertCheck is similar to ConvFilt, but it checks and transforms elements together 227 func ConvertCheck[From, To any](next func() (From, bool, error), converter func(from From) (To, bool)) ConvertCheckIter[From, To] { 228 return ConvertCheckIter[From, To]{next: next, converter: func(f From) (To, bool, error) { c, ok := converter(f); return c, ok, nil }} 229 } 230 231 // FiltAndConv returns a stream that filters source elements and converts them 232 func FiltAndConv[From, To any](next func() (From, bool, error), filter func(From) (bool, error), converter func(From) (To, error)) ConvFiltIter[From, To] { 233 return FilterConvertFilter(next, filter, converter, always.True[To]) 234 } 235 236 // FilterAndConvert returns a stream that filters source elements and converts them 237 func FilterAndConvert[From, To any](next func() (From, bool, error), filter func(From) bool, converter func(From) To) ConvFiltIter[From, To] { 238 return FilterConvertFilter(next, func(f From) (bool, error) { return filter(f), nil }, func(f From) (To, error) { return converter(f), nil }, always.True[To]) 239 } 240 241 // FilterConvertFilter filters source, converts, and filters converted elements 242 func FilterConvertFilter[From, To any](next func() (From, bool, error), filter func(From) (bool, error), converter func(From) (To, error), filterTo func(To) (bool, error)) ConvFiltIter[From, To] { 243 return ConvFiltIter[From, To]{next: next, converter: converter, filterFrom: filter, filterTo: filterTo} 244 } 245 246 // ConvertAndFilter additionally filters 'To' elements 247 func ConvertAndFilter[From, To any](next func() (From, bool, error), converter func(From) (To, error), filter func(To) (bool, error)) ConvFiltIter[From, To] { 248 return FilterConvertFilter(next, always.True[From], converter, filter) 249 } 250 251 // Flatt instantiates an iterator that extracts slices of 'To' by a flattener from elements of 'From' and flattens as one iterable collection of 'To' elements. 252 func Flatt[From, To any](next func() (From, bool, error), flattener func(From) ([]To, error)) *FlatIter[From, To] { 253 return &FlatIter[From, To]{next: next, flattener: flattener, elemSizeTo: notsafe.GetTypeSize[To]()} 254 } 255 256 // Flat instantiates an iterator that extracts slices of 'To' by a flattener from elements of 'From' and flattens as one iterable collection of 'To' elements. 257 func Flat[From, To any](next func() (From, bool, error), flattener func(From) []To) *FlatIter[From, To] { 258 return &FlatIter[From, To]{next: next, flattener: func(f From) ([]To, error) { return flattener(f), nil }, elemSizeTo: notsafe.GetTypeSize[To]()} 259 } 260 261 // FiltAndFlat filters source elements and extracts slices of 'To' by the 'flattener' function 262 func FiltAndFlat[From, To any](next func() (From, bool, error), filter func(From) (bool, error), flattener func(From) ([]To, error)) *FlattFiltIter[From, To] { 263 return FiltFlattFilt(next, filter, flattener, always.True[To]) 264 } 265 266 // FilterAndFlat filters source elements and extracts slices of 'To' by the 'flattener' function 267 func FilterAndFlat[From, To any](next func() (From, bool, error), filter func(From) bool, flattener func(From) []To) *FlattFiltIter[From, To] { 268 return FiltFlattFilt(next, func(f From) (bool, error) { return filter(f), nil }, func(f From) ([]To, error) { return flattener(f), nil }, always.True[To]) 269 } 270 271 // FlatAndFilt extracts slices of 'To' by the 'flattener' function and filters extracted elements 272 func FlatAndFilt[From, To any](next func() (From, bool, error), flattener func(From) ([]To, error), filterTo func(To) (bool, error)) *FlattFiltIter[From, To] { 273 return FiltFlattFilt(next, always.True[From], flattener, filterTo) 274 } 275 276 // FlattAndFilter extracts slices of 'To' by the 'flattener' function and filters extracted elements 277 func FlattAndFilter[From, To any](next func() (From, bool, error), flattener func(From) []To, filterTo func(To) bool) *FlattFiltIter[From, To] { 278 return FiltFlattFilt(next, always.True[From], func(f From) ([]To, error) { return flattener(f), nil }, func(t To) (bool, error) { return filterTo(t), nil }) 279 } 280 281 // FiltFlattFilt filters source elements, extracts slices of 'To' by the 'flattener' function and filters extracted elements 282 func FiltFlattFilt[From, To any](next func() (From, bool, error), filterFrom func(From) (bool, error), flattener func(From) ([]To, error), filterTo func(To) (bool, error)) *FlattFiltIter[From, To] { 283 return &FlattFiltIter[From, To]{next: next, filterFrom: filterFrom, flattener: flattener, filterTo: filterTo, elemSizeTo: notsafe.GetTypeSize[To]()} 284 } 285 286 // FilterFlatFilter filters source elements, extracts slices of 'To' by the 'flattener' function and filters extracted elements 287 func FilterFlatFilter[From, To any](next func() (From, bool, error), filterFrom func(From) bool, flattener func(From) []To, filterTo func(To) bool) *FlattFiltIter[From, To] { 288 return &FlattFiltIter[From, To]{ 289 next: next, 290 filterFrom: func(f From) (bool, error) { return filterFrom(f), nil }, 291 flattener: func(f From) ([]To, error) { return flattener(f), nil }, 292 filterTo: func(t To) (bool, error) { return filterTo(t), nil }, 293 elemSizeTo: notsafe.GetTypeSize[To](), 294 } 295 } 296 297 // Filt creates an iterator that checks elements by the 'filter' function and returns successful ones. 298 func Filt[T any](next func() (T, bool, error), filter func(T) (bool, error)) FiltIter[T] { 299 return FiltIter[T]{next: next, filter: filter} 300 } 301 302 // Filter creates an iterator that checks elements by the 'filter' function and returns successful ones. 303 func Filter[T any](next func() (T, bool, error), filter func(T) bool) FiltIter[T] { 304 return FiltIter[T]{next: next, filter: as.ErrTail(filter)} 305 } 306 307 // NotNil creates an iterator that filters nullable elements. 308 func NotNil[T any](next func() (*T, bool, error)) FiltIter[*T] { 309 return Filt(next, as.ErrTail(not.Nil[T])) 310 } 311 312 // PtrVal creates an iterator that transform pointers to the values referenced by those pointers. 313 // Nil pointers are transformet to zero values. 314 func PtrVal[T any](next func() (*T, bool, error)) ConvertIter[*T, T] { 315 return Convert(next, convert.PtrVal[T]) 316 } 317 318 // NoNilPtrVal creates an iterator that transform only not nil pointers to the values referenced referenced by those pointers. 319 // Nil pointers are ignored. 320 func NoNilPtrVal[T any](next func() (*T, bool, error)) ConvertCheckIter[*T, T] { 321 return ConvertCheck(next, convert.NoNilPtrVal[T]) 322 } 323 324 // KeyValue transforms iterable elements to key/value iterator based on applying key, value extractors to the elements 325 func KeyValue[T any, K, V any](next func() (T, bool, error), keyExtractor func(T) K, valExtractor func(T) V) KeyValuer[T, K, V] { 326 return KeyValuee(next, as.ErrTail(keyExtractor), as.ErrTail(valExtractor)) 327 } 328 329 // KeyValuee transforms iterable elements to key/value iterator based on applying key, value extractors to the elements 330 func KeyValuee[T any, K, V any](next func() (T, bool, error), keyExtractor func(T) (K, error), valExtractor func(T) (V, error)) KeyValuer[T, K, V] { 331 return NewKeyValuer(next, keyExtractor, valExtractor) 332 } 333 334 // KeysValues transforms iterable elements to key/value iterator based on applying multiple keys, values extractor to the elements 335 func KeysValues[T, K, V any](next func() (T, bool, error), keysExtractor func(T) ([]K, error), valsExtractor func(T) ([]V, error)) *MultipleKeyValuer[T, K, V] { 336 return NewMultipleKeyValuer(next, keysExtractor, valsExtractor) 337 } 338 339 // KeysValue transforms iterable elements to key/value iterator based on applying key, value extractor to the elements 340 func KeysValue[T, K, V any](next func() (T, bool, error), keysExtractor func(T) []K, valExtractor func(T) V) *MultipleKeyValuer[T, K, V] { 341 return KeysValues(next, as.ErrTail(keysExtractor), convSlice(as.ErrTail(valExtractor))) 342 } 343 344 // KeysValuee transforms iterable elements to key/value iterator based on applying key, value extractor to the elements 345 func KeysValuee[T, K, V any](next func() (T, bool, error), keysExtractor func(T) ([]K, error), valExtractor func(T) (V, error)) *MultipleKeyValuer[T, K, V] { 346 return KeysValues(next, keysExtractor, convSlice(valExtractor)) 347 } 348 349 // KeyValues transforms iterable elements to key/value iterator based on applying key, value extractor to the elements 350 func KeyValues[T, K, V any](next func() (T, bool, error), keyExtractor func(T) K, valsExtractor func(T) []V) *MultipleKeyValuer[T, K, V] { 351 return KeysValues(next, convSlice(as.ErrTail(keyExtractor)), as.ErrTail(valsExtractor)) 352 } 353 354 // KeyValuess transforms iterable elements to key/value iterator based on applying key, value extractor to the elements 355 func KeyValuess[T, K, V any](next func() (T, bool, error), keyExtractor func(T) (K, error), valsExtractor func(T) ([]V, error)) *MultipleKeyValuer[T, K, V] { 356 return KeysValues(next, convSlice(keyExtractor), valsExtractor) 357 } 358 359 // ExtraVals transforms iterable elements to key/value iterator based on applying value extractor to the elements 360 func ExtraVals[T, V any](next func() (T, bool, error), valsExtractor func(T) []V) *MultipleKeyValuer[T, T, V] { 361 return KeyValues(next, as.Is[T], valsExtractor) 362 } 363 364 // ExtraValss transforms iterable elements to key/value iterator based on applying values extractor to the elements 365 func ExtraValss[T, V any](next func() (T, bool, error), valsExtractor func(T) ([]V, error)) *MultipleKeyValuer[T, T, V] { 366 return KeyValuess(next, as.ErrTail(as.Is[T]), valsExtractor) 367 } 368 369 // ExtraKeys transforms iterable elements to key/value iterator based on applying key extractor to the elements 370 func ExtraKeys[T, K any](next func() (T, bool, error), keysExtractor func(T) []K) *MultipleKeyValuer[T, K, T] { 371 return KeysValue(next, keysExtractor, as.Is[T]) 372 } 373 374 // ExtraKeyss transforms iterable elements to key/value iterator based on applying key extractor to the elements 375 func ExtraKeyss[T, K any](next func() (T, bool, error), keyExtractor func(T) (K, error)) *MultipleKeyValuer[T, K, T] { 376 return KeyValuess(next, keyExtractor, as.ErrTail(convert.AsSlice[T])) 377 } 378 379 // ExtraKey transforms iterable elements to key/value iterator based on applying key extractor to the elements 380 func ExtraKey[T, K any](next func() (T, bool, error), keysExtractor func(T) K) KeyValuer[T, K, T] { 381 return KeyValue(next, keysExtractor, as.Is[T]) 382 } 383 384 // ExtraKeyy transforms iterable elements to key/value iterator based on applying key extractor to the elements 385 func ExtraKeyy[T, K any](next func() (T, bool, error), keyExtractor func(T) (K, error)) KeyValuer[T, K, T] { 386 return KeyValuee[T, K](next, keyExtractor, as.ErrTail(as.Is[T])) 387 } 388 389 // ExtraValue transforms iterable elements to key/value iterator based on applying value extractor to the elements 390 func ExtraValue[T, V any](next func() (T, bool, error), valueExtractor func(T) V) KeyValuer[T, T, V] { 391 return KeyValue(next, as.Is[T], valueExtractor) 392 } 393 394 // ExtraValuee transforms iterable elements to key/value iterator based on applying value extractor to the elements 395 func ExtraValuee[T, V any](next func() (T, bool, error), valExtractor func(T) (V, error)) KeyValuer[T, T, V] { 396 return KeyValuee[T, T, V](next, as.ErrTail(as.Is[T]), valExtractor) 397 } 398 399 // Group converts elements retrieved by the 'next' function into a map, extracting a key for each element applying the converter 'keyExtractor'. 400 // The keyExtractor converts an element to a key. 401 // The valExtractor converts an element to an value. 402 func Group[T any, K comparable, V any](next func() (T, bool, error), keyExtractor func(T) K, valExtractor func(T) V) (map[K][]V, error) { 403 return Groupp(next, as.ErrTail(keyExtractor), as.ErrTail(valExtractor)) 404 } 405 406 // Groupp converts elements retrieved by the 'next' function into a map, extracting a key for each element applying the converter 'keyExtractor'. 407 // The keyExtractor converts an element to a key. 408 // The valExtractor converts an element to an value. 409 func Groupp[T any, K comparable, V any](next func() (T, bool, error), keyExtractor func(T) (K, error), valExtractor func(T) (V, error)) (map[K][]V, error) { 410 return ToMapResolvv(next, keyExtractor, valExtractor, func(ok bool, k K, rv []V, v V) ([]V, error) { 411 return resolv.Append(ok, k, rv, v), nil 412 }) 413 } 414 415 // GroupByMultiple converts elements retrieved by the 'next' function into a map, extracting multiple keys, values per each element applying the 'keysExtractor' and 'valsExtractor' functions. 416 // The keysExtractor retrieves one or more keys per element. 417 // The valsExtractor retrieves one or more values per element. 418 func GroupByMultiple[T any, K comparable, V any](next func() (T, bool, error), keysExtractor func(T) []K, valsExtractor func(T) []V) (map[K][]V, error) { 419 groups := map[K][]V{} 420 for { 421 if e, ok, err := next(); err != nil || !ok { 422 return groups, err 423 } else if keys, vals := keysExtractor(e), valsExtractor(e); len(keys) == 0 { 424 var key K 425 for _, v := range vals { 426 initGroup(key, v, groups) 427 } 428 } else { 429 for _, key := range keys { 430 if len(vals) == 0 { 431 var v V 432 initGroup(key, v, groups) 433 } else { 434 for _, v := range vals { 435 initGroup(key, v, groups) 436 } 437 } 438 } 439 } 440 } 441 } 442 443 // GroupByMultipleKeys converts elements retrieved by the 'next' function into a map, extracting multiple keys, one value per each element applying the 'keysExtractor' and 'valExtractor' functions. 444 // The keysExtractor retrieves one or more keys per element. 445 // The valExtractor converts an element to a value. 446 func GroupByMultipleKeys[T any, K comparable, V any](next func() (T, bool, error), keysExtractor func(T) []K, valExtractor func(T) V) (map[K][]V, error) { 447 groups := map[K][]V{} 448 for { 449 if e, ok, err := next(); err != nil || !ok { 450 return groups, err 451 } else if keys, v := keysExtractor(e), valExtractor(e); len(keys) == 0 { 452 var key K 453 initGroup(key, v, groups) 454 } else { 455 for _, key := range keys { 456 initGroup(key, v, groups) 457 } 458 } 459 } 460 } 461 462 // GroupByMultipleValues converts elements retrieved by the 'next' function into a map, extracting one key, multiple values per each element applying the 'keyExtractor' and 'valsExtractor' functions. 463 // The keyExtractor converts an element to a key. 464 // The valsExtractor retrieves one or more values per element. 465 func GroupByMultipleValues[T any, K comparable, V any](next func() (T, bool, error), keyExtractor func(T) K, valsExtractor func(T) []V) (map[K][]V, error) { 466 groups := map[K][]V{} 467 for { 468 if e, ok, err := next(); err != nil || !ok { 469 return groups, err 470 } else if key, vals := keyExtractor(e), valsExtractor(e); len(vals) == 0 { 471 var v V 472 initGroup(key, v, groups) 473 } else { 474 for _, v := range vals { 475 initGroup(key, v, groups) 476 } 477 } 478 } 479 } 480 481 func initGroup[T any, K comparable, TS ~[]T](key K, e T, groups map[K]TS) { 482 groups[key] = append(groups[key], e) 483 } 484 485 // ToMap collects key\value elements to a map by iterating over the elements 486 func ToMap[T any, K comparable, V any](next func() (T, bool), keyExtractor func(T) K, valExtractor func(T) V) (map[K]V, error) { 487 return ToMapp(From(next), as.ErrTail(keyExtractor), as.ErrTail(valExtractor)) 488 } 489 490 // ToMapp collects key\value elements to a map by iterating over the elements 491 func ToMapp[T any, K comparable, V any](next func() (T, bool, error), keyExtractor func(T) (K, error), valExtractor func(T) (V, error)) (map[K]V, error) { 492 return ToMapResolvv(next, keyExtractor, valExtractor, func(ok bool, k K, rv V, v V) (V, error) { return resolv.First(ok, k, rv, v), nil }) 493 } 494 495 // ToMapResolvv collects key\value elements to a map by iterating over the elements with resolving of duplicated key values 496 func ToMapResolvv[T any, K comparable, V, VR any]( 497 next func() (T, bool, error), keyExtractor func(T) (K, error), valExtractor func(T) (V, error), 498 resolver func(bool, K, VR, V) (VR, error), 499 ) (m map[K]VR, err error) { 500 m = map[K]VR{} 501 for { 502 if e, ok, err := next(); err != nil || !ok { 503 return m, err 504 } else if k, err := keyExtractor(e); err != nil { 505 return m, err 506 } else if v, err := valExtractor(e); err != nil { 507 return m, err 508 } else { 509 exists, ok := m[k] 510 if m[k], err = resolver(ok, k, exists, v); err != nil { 511 return m, err 512 } 513 } 514 } 515 } 516 517 // New is the main breakable loop constructor 518 func New[S, T any](source S, hasNext func(S) bool, getNext func(S) (T, error)) func() (T, bool, error) { 519 return func() (out T, ok bool, err error) { 520 if ok := hasNext(source); !ok { 521 return out, false, nil 522 } else if n, err := getNext(source); err != nil { 523 return out, false, err 524 } else { 525 return n, true, nil 526 } 527 } 528 } 529 530 // ConvertAndReduce converts each elements and merges them into one 531 func ConvertAndReduce[From, To any](next func() (From, bool, error), converter func(From) To, merger func(To, To) To) (out To, err error) { 532 return Reduce(Convert(next, converter).Next, merger) 533 } 534 535 // ConvAndReduce converts each elements and merges them into one 536 func ConvAndReduce[From, To any](next func() (From, bool, error), converter func(From) (To, error), merger func(To, To) To) (out To, err error) { 537 return Reduce(Conv(next, converter).Next, merger) 538 } 539 540 func brk(err error) error { 541 if errors.Is(err, c.ErrBreak) { 542 return nil 543 } 544 return err 545 } 546 547 func convSlice[T, V any](conv func(T) (V, error)) func(t T) ([]V, error) { 548 return func(t T) ([]V, error) { 549 v, err := conv(t) 550 if err != nil { 551 return nil, err 552 } 553 return convert.AsSlice(v), nil 554 } 555 }