summaryrefslogtreecommitdiffstats
path: root/vendor/github.com/pelletier/go-buffruneio
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/github.com/pelletier/go-buffruneio')
-rw-r--r--vendor/github.com/pelletier/go-buffruneio/.gitignore1
-rw-r--r--vendor/github.com/pelletier/go-buffruneio/.travis.yml7
-rw-r--r--vendor/github.com/pelletier/go-buffruneio/README.md62
-rw-r--r--vendor/github.com/pelletier/go-buffruneio/buffruneio.go117
-rw-r--r--vendor/github.com/pelletier/go-buffruneio/buffruneio_test.go145
5 files changed, 332 insertions, 0 deletions
diff --git a/vendor/github.com/pelletier/go-buffruneio/.gitignore b/vendor/github.com/pelletier/go-buffruneio/.gitignore
new file mode 100644
index 000000000..c56069fe2
--- /dev/null
+++ b/vendor/github.com/pelletier/go-buffruneio/.gitignore
@@ -0,0 +1 @@
+*.test \ No newline at end of file
diff --git a/vendor/github.com/pelletier/go-buffruneio/.travis.yml b/vendor/github.com/pelletier/go-buffruneio/.travis.yml
new file mode 100644
index 000000000..9720442cd
--- /dev/null
+++ b/vendor/github.com/pelletier/go-buffruneio/.travis.yml
@@ -0,0 +1,7 @@
+language: go
+sudo: false
+go:
+ - 1.3.3
+ - 1.4.3
+ - 1.5.3
+ - tip
diff --git a/vendor/github.com/pelletier/go-buffruneio/README.md b/vendor/github.com/pelletier/go-buffruneio/README.md
new file mode 100644
index 000000000..ff608b3ab
--- /dev/null
+++ b/vendor/github.com/pelletier/go-buffruneio/README.md
@@ -0,0 +1,62 @@
+# buffruneio
+
+[![Tests Status](https://travis-ci.org/pelletier/go-buffruneio.svg?branch=master)](https://travis-ci.org/pelletier/go-buffruneio)
+[![GoDoc](https://godoc.org/github.com/pelletier/go-buffruneio?status.svg)](https://godoc.org/github.com/pelletier/go-buffruneio)
+
+Buffruneio is a wrapper around bufio to provide buffered runes access with
+unlimited unreads.
+
+```go
+import "github.com/pelletier/go-buffruneio"
+```
+
+## Examples
+
+```go
+import (
+ "fmt"
+ "github.com/pelletier/go-buffruneio"
+ "strings"
+)
+
+reader := buffruneio.NewReader(strings.NewReader("abcd"))
+fmt.Println(reader.ReadRune()) // 'a'
+fmt.Println(reader.ReadRune()) // 'b'
+fmt.Println(reader.ReadRune()) // 'c'
+reader.UnreadRune()
+reader.UnreadRune()
+fmt.Println(reader.ReadRune()) // 'b'
+fmt.Println(reader.ReadRune()) // 'c'
+```
+
+## Documentation
+
+The documentation and additional examples are available at
+[godoc.org](http://godoc.org/github.com/pelletier/go-buffruneio).
+
+## Contribute
+
+Feel free to report bugs and patches using GitHub's pull requests system on
+[pelletier/go-toml](https://github.com/pelletier/go-buffruneio). Any feedback is
+much appreciated!
+
+## LICENSE
+
+Copyright (c) 2016 Thomas Pelletier
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of
+this software and associated documentation files (the "Software"), to deal in
+the Software without restriction, including without limitation the rights to
+use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+the Software, and to permit persons to whom the Software is furnished to do so,
+subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
diff --git a/vendor/github.com/pelletier/go-buffruneio/buffruneio.go b/vendor/github.com/pelletier/go-buffruneio/buffruneio.go
new file mode 100644
index 000000000..4e6d6ea61
--- /dev/null
+++ b/vendor/github.com/pelletier/go-buffruneio/buffruneio.go
@@ -0,0 +1,117 @@
+// Package buffruneio is a wrapper around bufio to provide buffered runes access with unlimited unreads.
+package buffruneio
+
+import (
+ "bufio"
+ "container/list"
+ "errors"
+ "io"
+)
+
+// Rune to indicate end of file.
+const (
+ EOF = -(iota + 1)
+)
+
+// ErrNoRuneToUnread is returned by UnreadRune() when the read index is already at the beginning of the buffer.
+var ErrNoRuneToUnread = errors.New("no rune to unwind")
+
+// Reader implements runes buffering for an io.Reader object.
+type Reader struct {
+ buffer *list.List
+ current *list.Element
+ input *bufio.Reader
+}
+
+// NewReader returns a new Reader.
+func NewReader(rd io.Reader) *Reader {
+ return &Reader{
+ buffer: list.New(),
+ input: bufio.NewReader(rd),
+ }
+}
+
+type runeWithSize struct {
+ r rune
+ size int
+}
+
+func (rd *Reader) feedBuffer() error {
+ r, size, err := rd.input.ReadRune()
+
+ if err != nil {
+ if err != io.EOF {
+ return err
+ }
+ r = EOF
+ }
+
+ newRuneWithSize := runeWithSize{r, size}
+
+ rd.buffer.PushBack(newRuneWithSize)
+ if rd.current == nil {
+ rd.current = rd.buffer.Back()
+ }
+ return nil
+}
+
+// ReadRune reads the next rune from buffer, or from the underlying reader if needed.
+func (rd *Reader) ReadRune() (rune, int, error) {
+ if rd.current == rd.buffer.Back() || rd.current == nil {
+ err := rd.feedBuffer()
+ if err != nil {
+ return EOF, 0, err
+ }
+ }
+
+ runeWithSize := rd.current.Value.(runeWithSize)
+ rd.current = rd.current.Next()
+ return runeWithSize.r, runeWithSize.size, nil
+}
+
+// UnreadRune pushes back the previously read rune in the buffer, extending it if needed.
+func (rd *Reader) UnreadRune() error {
+ if rd.current == rd.buffer.Front() {
+ return ErrNoRuneToUnread
+ }
+ if rd.current == nil {
+ rd.current = rd.buffer.Back()
+ } else {
+ rd.current = rd.current.Prev()
+ }
+ return nil
+}
+
+// Forget removes runes stored before the current stream position index.
+func (rd *Reader) Forget() {
+ if rd.current == nil {
+ rd.current = rd.buffer.Back()
+ }
+ for ; rd.current != rd.buffer.Front(); rd.buffer.Remove(rd.current.Prev()) {
+ }
+}
+
+// PeekRune 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) PeekRunes(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.(runeWithSize).r
+ res = append(res, r)
+ if r == EOF {
+ return res
+ }
+ cursor = cursor.Next()
+ }
+ }
+ return res
+}
diff --git a/vendor/github.com/pelletier/go-buffruneio/buffruneio_test.go b/vendor/github.com/pelletier/go-buffruneio/buffruneio_test.go
new file mode 100644
index 000000000..67b0cba9b
--- /dev/null
+++ b/vendor/github.com/pelletier/go-buffruneio/buffruneio_test.go
@@ -0,0 +1,145 @@
+package buffruneio
+
+import (
+ "runtime/debug"
+ "strings"
+ "testing"
+)
+
+func assertNoError(t *testing.T, err error) {
+ if err != nil {
+ t.Log("unexpected error", err)
+ debug.PrintStack()
+ t.FailNow()
+ }
+}
+
+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, size, err := rd.ReadRune()
+ assertNoError(t, err)
+ if gotRune != r {
+ t.Fatal("got", string(gotRune),
+ "(", []byte(string(gotRune)), ")",
+ "expected", string(r),
+ "(", []byte(string(r)), ")")
+ t.Fatal("got size", size,
+ "expected", len([]byte(string(r))))
+ }
+}
+
+func TestReadString(t *testing.T) {
+ s := "hello"
+ rd := NewReader(strings.NewReader(s))
+
+ assumeRune(t, rd, 'h')
+ assumeRune(t, rd, 'e')
+ assumeRune(t, rd, 'l')
+ assumeRune(t, rd, 'l')
+ assumeRune(t, rd, 'o')
+ assumeRune(t, rd, EOF)
+}
+
+func TestMultipleEOF(t *testing.T) {
+ s := ""
+ rd := NewReader(strings.NewReader(s))
+
+ assumeRune(t, rd, EOF)
+ assumeRune(t, rd, EOF)
+}
+
+func TestUnread(t *testing.T) {
+ s := "ab"
+ rd := NewReader(strings.NewReader(s))
+
+ assumeRune(t, rd, 'a')
+ assumeRune(t, rd, 'b')
+ assertNoError(t, rd.UnreadRune())
+ assumeRune(t, rd, 'b')
+ assumeRune(t, rd, EOF)
+}
+
+func TestUnreadEOF(t *testing.T) {
+ s := ""
+ rd := NewReader(strings.NewReader(s))
+
+ _ = rd.UnreadRune()
+ assumeRune(t, rd, EOF)
+ assumeRune(t, rd, EOF)
+ assertNoError(t, rd.UnreadRune())
+ assumeRune(t, rd, EOF)
+}
+
+func TestForget(t *testing.T) {
+ s := "hello"
+ rd := NewReader(strings.NewReader(s))
+
+ assumeRune(t, rd, 'h')
+ assumeRune(t, rd, 'e')
+ assumeRune(t, rd, 'l')
+ assumeRune(t, rd, 'l')
+ rd.Forget()
+ if rd.UnreadRune() != ErrNoRuneToUnread {
+ t.Fatal("no rune should be available")
+ }
+}
+
+func TestForgetEmpty(t *testing.T) {
+ s := ""
+ rd := NewReader(strings.NewReader(s))
+
+ rd.Forget()
+ assumeRune(t, rd, EOF)
+ rd.Forget()
+}
+
+func TestPeekEmpty(t *testing.T) {
+ s := ""
+ rd := NewReader(strings.NewReader(s))
+
+ runes := rd.PeekRunes(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.PeekRunes(1)
+ assumeRunesArray(t, []rune{'a'}, runes)
+
+ runes = rd.PeekRunes(1)
+ assumeRunesArray(t, []rune{'a'}, runes)
+
+ assumeRune(t, rd, 'a')
+ runes = rd.PeekRunes(1)
+ assumeRunesArray(t, []rune{EOF}, runes)
+
+ assumeRune(t, rd, EOF)
+}
+
+func TestPeekLarge(t *testing.T) {
+ s := "abcdefg"
+ rd := NewReader(strings.NewReader(s))
+
+ runes := rd.PeekRunes(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)
+}