diff options
author | anon5 <anon5clam@protonmail.com> | 2021-02-22 21:09:59 +0000 |
---|---|---|
committer | anon5 <anon5clam@protonmail.com> | 2021-02-22 21:09:59 +0000 |
commit | 1c1d58d864cb769e19d1bcfb0ec1968e7bf2ee62 (patch) | |
tree | e3b0936d6191495d3321ce912da6dc062671cc19 /readrune.go | |
parent | 8b61ee961a9191fd2731a48d46f33b561a316032 (diff) | |
download | mt-1c1d58d864cb769e19d1bcfb0ec1968e7bf2ee62.tar.xz |
Add inv (de)serialization
Diffstat (limited to 'readrune.go')
-rw-r--r-- | readrune.go | 116 |
1 files changed, 116 insertions, 0 deletions
diff --git a/readrune.go b/readrune.go new file mode 100644 index 0000000..775e06f --- /dev/null +++ b/readrune.go @@ -0,0 +1,116 @@ +/* +Based on go1.16/src/fmt/scan.go. + +Copyright (c) 2009 The Go Authors. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. + * Neither the name of Google Inc. nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +package mt + +import ( + "errors" + "io" + "unicode/utf8" +) + +// readRune is a structure to enable reading UTF-8 encoded code points +// from an io.Reader. It is used if the Reader given to the scanner does +// not already implement io.RuneScanner. +type readRune struct { + io.Reader + buf [utf8.UTFMax]byte // used only inside ReadRune + pending int // number of bytes in pendBuf; only >0 for bad UTF-8 + pendBuf [utf8.UTFMax]byte // bytes left over + peekRune rune // if >=0 next rune; when <0 is ^(previous Rune) +} + +// readByte returns the next byte from the input, which may be +// left over from a previous read if the UTF-8 was ill-formed. +func (r *readRune) readByte() (b byte, err error) { + if r.pending > 0 { + b = r.pendBuf[0] + copy(r.pendBuf[0:], r.pendBuf[1:]) + r.pending-- + return + } + n, err := io.ReadFull(r, r.pendBuf[:1]) + if n != 1 { + return 0, err + } + return r.pendBuf[0], err +} + +// ReadRune returns the next UTF-8 encoded code point from the +// io.Reader inside r. +func (r *readRune) ReadRune() (rr rune, size int, err error) { + if r.peekRune >= 0 { + rr = r.peekRune + r.peekRune = ^r.peekRune + size = utf8.RuneLen(rr) + return + } + r.buf[0], err = r.readByte() + if err != nil { + return + } + if r.buf[0] < utf8.RuneSelf { // fast check for common ASCII case + rr = rune(r.buf[0]) + size = 1 // Known to be 1. + // Flip the bits of the rune so it's available to UnreadRune. + r.peekRune = ^rr + return + } + var n int + for n = 1; !utf8.FullRune(r.buf[:n]); n++ { + r.buf[n], err = r.readByte() + if err != nil { + if err == io.EOF { + err = nil + break + } + return + } + } + rr, size = utf8.DecodeRune(r.buf[:n]) + if size < n { // an error, save the bytes for the next read + copy(r.pendBuf[r.pending:], r.buf[size:n]) + r.pending += n - size + } + // Flip the bits of the rune so it's available to UnreadRune. + r.peekRune = ^rr + return +} + +func (r *readRune) UnreadRune() error { + if r.peekRune >= 0 { + return errors.New("fmt: scanning called UnreadRune with no rune available") + } + // Reverse bit flip of previously read rune to obtain valid >=0 state. + r.peekRune = ^r.peekRune + return nil +} |