From 060151a3aca04351853c83b07c88fca4b8613ec8 Mon Sep 17 00:00:00 2001 From: Alejandro Mery Date: Mon, 28 Aug 2023 23:16:01 +0000 Subject: [PATCH 1/2] runes: Implement UnreadRune() and PeekRune() Signed-off-by: Alejandro Mery --- runes/reader.go | 43 ++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 42 insertions(+), 1 deletion(-) diff --git a/runes/reader.go b/runes/reader.go index 1e73048..8da0f08 100644 --- a/runes/reader.go +++ b/runes/reader.go @@ -2,6 +2,7 @@ package runes import ( "bytes" + "errors" "io" "strings" "unicode/utf8" @@ -18,7 +19,14 @@ const ( // implemented interfaces var ( - _ io.RuneReader = (*Reader)(nil) + _ io.RuneReader = (*Reader)(nil) + _ io.RuneScanner = (*Reader)(nil) +) + +var ( + // ErrInvalidUnreadRune indicates UnreadRune() was calls after an + // action other than a successful ReadRune() + ErrInvalidUnreadRune = errors.New("invalid UnreadRune() call") ) // Reader is a RuneReader aimed at implementing text parsers @@ -28,6 +36,8 @@ type Reader struct { buf []byte off int cursor int + + lastRuneSize int } // String returns what's already Read but not yet emitted or discarded @@ -54,6 +64,9 @@ func (b *Reader) Discard() { // step b.off = b.cursor } + + // and prevent UnreadRune() + b.lastRuneSize = -1 } // ready tells how many bytes are ready to decode @@ -139,6 +152,8 @@ func (b *Reader) ReadRune() (rune, int, error) { for { err := b.needsBytes(count) if err != nil { + b.lastRuneSize = -1 + return 0, 0, err } @@ -153,9 +168,35 @@ func (b *Reader) ReadRune() (rune, int, error) { // decode rune r, l := utf8.DecodeRune(b.buf[b.cursor:]) + + // and remember for UnreadRune() + b.lastRuneSize = l + return r, l, nil } +// UnreadRune moves the cursor where it was before the last call to ReadRune +func (b *Reader) UnreadRune() error { + if b.lastRuneSize > 0 { + b.cursor -= b.lastRuneSize + b.lastRuneSize = -1 + return nil + } + + return ErrInvalidUnreadRune +} + +// PeekRune returns information about the next rune without moving the +// cursor +func (b *Reader) PeekRune() (rune, int, error) { + r, l, err := b.ReadRune() + if err != nil { + return r, l, err + } + err = b.UnreadRune() + return r, l, err +} + // NewReader creates a new runes [Reader] using the given [io.Reader] func NewReader(r io.Reader) *Reader { if r == nil { -- 2.17.1 From 6e866caa75c06939b240e083434bf8e0c741f6c4 Mon Sep 17 00:00:00 2001 From: Alejandro Mery Date: Tue, 29 Aug 2023 00:45:52 +0000 Subject: [PATCH 2/2] runes: fix ReadRune() to actually move the cursor Signed-off-by: Alejandro Mery --- runes/reader.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/runes/reader.go b/runes/reader.go index 8da0f08..2b37873 100644 --- a/runes/reader.go +++ b/runes/reader.go @@ -168,7 +168,8 @@ func (b *Reader) ReadRune() (rune, int, error) { // decode rune r, l := utf8.DecodeRune(b.buf[b.cursor:]) - + // step over + b.cursor += l // and remember for UnreadRune() b.lastRuneSize = l -- 2.17.1