pkg/strings: add ByteAt, ByteSlice, and Runes
To replace indexing and slicing of
string types.
Change-Id: I040966df5cd7a0367dac73bb1920ec81a42ff29a
Reviewed-on: https://cue-review.googlesource.com/c/cue/+/2879
Reviewed-by: Marcel van Lohuizen <mpvl@golang.org>
diff --git a/cue/builtin_test.go b/cue/builtin_test.go
index a2c9c8a..a9c467f 100644
--- a/cue/builtin_test.go
+++ b/cue/builtin_test.go
@@ -17,6 +17,7 @@
import (
"fmt"
"math/big"
+ "strconv"
"strings"
"testing"
)
@@ -141,6 +142,15 @@
test("strings", `strings.Join([1, 2], " ")`),
`_|_(invalid list element 0 in argument 0 to strings.Join: cannot use value 1 (type int) as string)`,
}, {
+ test("strings", `strings.ByteAt("a", 0)`),
+ strconv.Itoa('a'),
+ }, {
+ test("strings", `strings.ByteSlice("Hello", 2, 5)`),
+ `'llo'`,
+ }, {
+ test("strings", `strings.Runes("Café")`),
+ strings.Replace(fmt.Sprint([]rune{'C', 'a', 'f', 'é'}), " ", ",", -1),
+ }, {
test("math/bits", `bits.Or(0x8, 0x1)`),
`9`,
}, {
diff --git a/cue/builtins.go b/cue/builtins.go
index 40d446f..1fc722d 100644
--- a/cue/builtins.go
+++ b/cue/builtins.go
@@ -1977,6 +1977,42 @@
},
"strings": &builtinPkg{
native: []*builtin{{
+ Name: "ByteAt",
+ Params: []kind{stringKind, intKind},
+ Result: intKind,
+ Func: func(c *callCtxt) {
+ b, i := c.bytes(0), c.int(1)
+ c.ret, c.err = func() (interface{}, error) {
+ if i < 0 || i >= len(b) {
+ return 0, fmt.Errorf("index out of range")
+ }
+ return b[i], nil
+ }()
+ },
+ }, {
+ Name: "ByteSlice",
+ Params: []kind{stringKind, intKind, intKind},
+ Result: stringKind,
+ Func: func(c *callCtxt) {
+ b, start, end := c.bytes(0), c.int(1), c.int(2)
+ c.ret, c.err = func() (interface{}, error) {
+ if start < 0 || start > end || end > len(b) {
+ return nil, fmt.Errorf("index out of range")
+ }
+ return b[start:end], nil
+ }()
+ },
+ }, {
+ Name: "Runes",
+ Params: []kind{stringKind},
+ Result: listKind,
+ Func: func(c *callCtxt) {
+ s := c.string(0)
+ c.ret = func() interface{} {
+ return []rune(s)
+ }()
+ },
+ }, {
Name: "MinRunes",
Params: []kind{stringKind, intKind},
Result: boolKind,
diff --git a/pkg/strings/manual.go b/pkg/strings/manual.go
index 849a0e3..de3436d 100644
--- a/pkg/strings/manual.go
+++ b/pkg/strings/manual.go
@@ -26,10 +26,33 @@
package strings
import (
+ "fmt"
"strings"
"unicode"
)
+// ByteAt reports the ith byte of the underlying strings or byte.
+func ByteAt(b []byte, i int) (byte, error) {
+ if i < 0 || i >= len(b) {
+ return 0, fmt.Errorf("index out of range")
+ }
+ return b[i], nil
+}
+
+// ByteSlice reports the bytes of the underlying string data from the start
+// index up to but not including the end index.
+func ByteSlice(b []byte, start, end int) ([]byte, error) {
+ if start < 0 || start > end || end > len(b) {
+ return nil, fmt.Errorf("index out of range")
+ }
+ return b[start:end], nil
+}
+
+// Runes returns the Unicode code points of the given string.
+func Runes(s string) []rune {
+ return []rune(s)
+}
+
// MinRunes reports whether the number of runes (Unicode codepoints) in a string
// is at least a certain minimum. MinRunes can be used a a field constraint to
// except all strings for which this property holds.