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) +}