Peek support
diff --git a/buffruneio.go b/buffruneio.go
index 9e47ca2..41cab87 100644
--- a/buffruneio.go
+++ b/buffruneio.go
@@ -83,3 +83,28 @@
for ; rd.current != rd.buffer.Front(); rd.buffer.Remove(rd.current.Prev()) {
}
}
+
+// Peek returns at most the next n runes, reading from the uderlying source if
+// needed. Does not move the current index. It includes EOF if reached.
+func (rd *Reader) Peek(n int) []rune {
+ res := make([]rune, 0, n)
+ cursor := rd.current
+ for i := 0; i < n; i++ {
+ if cursor == nil {
+ err := rd.feedBuffer()
+ if err != nil {
+ return res
+ }
+ cursor = rd.buffer.Back()
+ }
+ if cursor != nil {
+ r := cursor.Value.(rune)
+ res = append(res, r)
+ if r == EOF {
+ return res
+ }
+ cursor = cursor.Next()
+ }
+ }
+ return res
+}
diff --git a/buffruneio_test.go b/buffruneio_test.go
index 95946b6..f912149 100644
--- a/buffruneio_test.go
+++ b/buffruneio_test.go
@@ -5,6 +5,17 @@
"testing"
)
+func assumeRunesArray(t *testing.T, expected []rune, got []rune) {
+ if len(expected) != len(got) {
+ t.Fatal("expected", len(expected), "runes, but got", len(got))
+ }
+ for i := 0; i < len(got); i++ {
+ if expected[i] != got[i] {
+ t.Fatal("expected rune", expected[i], "at index", i, "but got", got[i])
+ }
+ }
+}
+
func assumeRune(t *testing.T, rd *Reader, r rune) {
gotRune, err := rd.ReadRune()
if err != nil {
@@ -82,3 +93,44 @@
assumeRune(t, rd, EOF)
rd.Forget()
}
+
+func TestPeekEmpty(t *testing.T) {
+ s := ""
+ rd := NewReader(strings.NewReader(s))
+
+ runes := rd.Peek(1)
+ if len(runes) != 1 {
+ t.Fatal("incorrect number of runes", len(runes))
+ }
+ if runes[0] != EOF {
+ t.Fatal("incorrect rune", runes[0])
+ }
+}
+
+func TestPeek(t *testing.T) {
+ s := "a"
+ rd := NewReader(strings.NewReader(s))
+
+ runes := rd.Peek(1)
+ assumeRunesArray(t, []rune{'a'}, runes)
+
+ runes = rd.Peek(1)
+ assumeRunesArray(t, []rune{'a'}, runes)
+
+ assumeRune(t, rd, 'a')
+ runes = rd.Peek(1)
+ assumeRunesArray(t, []rune{EOF}, runes)
+
+ assumeRune(t, rd, EOF)
+}
+
+func TestPeekLarge(t *testing.T) {
+ s := "abcdefg"
+ rd := NewReader(strings.NewReader(s))
+
+ runes := rd.Peek(100)
+ if len(runes) != len(s)+1 {
+ t.Fatal("incorrect number of runes", len(runes))
+ }
+ assumeRunesArray(t, []rune{'a', 'b', 'c', 'd', 'e', 'f', 'g', EOF}, runes)
+}