-
Notifications
You must be signed in to change notification settings - Fork 211
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
starlark: require go1.23 for new iterators
The correct type for new iterators is iter.Seq, which depends on a go1.23-only package, so we must limit the new functions to new toolchains. In principle this is (yet another) breaking change, but I suspect only users of (pre-)go1.23 will notice, and they are living on the bleeding edge by choice. Also, fix a couple of doc links.
- Loading branch information
Showing
3 changed files
with
121 additions
and
111 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,118 @@ | ||
// Copyright 2024 The Bazel Authors. All rights reserved. | ||
// Use of this source code is governed by a BSD-style | ||
// license that can be found in the LICENSE file. | ||
|
||
//go:build go1.23 | ||
|
||
package starlark | ||
|
||
import ( | ||
"fmt" | ||
"iter" | ||
) | ||
|
||
func (d *Dict) Entries() iter.Seq2[Value, Value] { return d.ht.entries } | ||
|
||
// Elements returns a go1.23 iterator over the elements of the list. | ||
// | ||
// Example: | ||
// | ||
// for elem := range list.Elements() { ... } | ||
func (l *List) Elements() func(yield func(Value) bool) { | ||
return func(yield func(Value) bool) { | ||
if !l.frozen { | ||
l.itercount++ | ||
defer func() { l.itercount-- }() | ||
} | ||
for _, x := range l.elems { | ||
if !yield(x) { | ||
break | ||
} | ||
} | ||
} | ||
} | ||
|
||
// Elements returns a go1.23 iterator over the elements of the tuple. | ||
// | ||
// (A Tuple is a slice, so it is of course directly iterable. This | ||
// method exists to provide a fast path for the [Elements] standalone | ||
// function.) | ||
func (t Tuple) Elements() iter.Seq[Value] { | ||
return func(yield func(Value) bool) { | ||
for _, x := range t { | ||
if !yield(x) { | ||
break | ||
} | ||
} | ||
} | ||
} | ||
|
||
func (s *Set) Elements() func(yield func(k Value) bool) { | ||
return func(yield func(k Value) bool) { | ||
s.ht.entries(func(k, _ Value) bool { return yield(k) }) | ||
} | ||
} | ||
|
||
// Elements returns an iterator for the elements of the iterable value. | ||
// | ||
// Example of go1.23 iteration: | ||
// | ||
// for elem := range Elements(iterable) { ... } | ||
// | ||
// Push iterators are provided as a convenience for Go client code. The | ||
// core iteration behavior of Starlark for-loops is defined by the | ||
// [Iterable] interface. | ||
func Elements(iterable Iterable) iter.Seq[Value] { | ||
// Use specialized push iterator if available (*List, Tuple, *Set). | ||
type hasElements interface { | ||
Elements() iter.Seq[Value] | ||
} | ||
if iterable, ok := iterable.(hasElements); ok { | ||
return iterable.Elements() | ||
} | ||
|
||
iter := iterable.Iterate() | ||
return func(yield func(Value) bool) { | ||
defer iter.Done() | ||
var x Value | ||
for iter.Next(&x) && yield(x) { | ||
} | ||
} | ||
} | ||
|
||
// Entries returns an iterator over the entries (key/value pairs) of | ||
// the iterable mapping. | ||
// | ||
// Example of go1.23 iteration: | ||
// | ||
// for k, v := range Entries(mapping) { ... } | ||
// | ||
// Push iterators are provided as a convenience for Go client code. The | ||
// core iteration behavior of Starlark for-loops is defined by the | ||
// [Iterable] interface. | ||
func Entries(mapping IterableMapping) iter.Seq2[Value, Value] { | ||
// If available (e.g. *Dict), use specialized push iterator, | ||
// as it gets k and v in one shot. | ||
type hasEntries interface { | ||
Entries() iter.Seq2[Value, Value] | ||
} | ||
if mapping, ok := mapping.(hasEntries); ok { | ||
return mapping.Entries() | ||
} | ||
|
||
iter := mapping.Iterate() | ||
return func(yield func(k, v Value) bool) { | ||
defer iter.Done() | ||
var k Value | ||
for iter.Next(&k) { | ||
v, found, err := mapping.Get(k) | ||
if err != nil || !found { | ||
panic(fmt.Sprintf("Iterate and Get are inconsistent (mapping=%v, key=%v)", | ||
mapping.Type(), k.Type())) | ||
} | ||
if !yield(k, v) { | ||
break | ||
} | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters