Created
April 24, 2020 14:38
-
-
Save plvhx/ea05893feda5ee0600f987a606fae94f to your computer and use it in GitHub Desktop.
io.ReadCloser and io.WriteCloser being wrapped together in io.TeeReader
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package main | |
import ( | |
"errors" | |
"fmt" | |
"io" | |
"io/ioutil" | |
"log" | |
) | |
const ( | |
ReadStateOpen = iota | |
ReadStateClose | |
WriteStateOpen | |
WriteStateClose | |
) | |
var ( | |
ErrOnClosedState = errors.New("Cannot read/write or re-close on closed state.") | |
) | |
type ReaderContract interface { | |
io.ReadCloser | |
} | |
type WriterContract interface { | |
io.WriteCloser | |
Bytes() []byte | |
String() string | |
Length() int | |
} | |
type Reader struct { | |
Data []byte | |
Off int | |
Len int | |
State int8 | |
} | |
type Writer struct { | |
Data []byte | |
Len int | |
State int8 | |
} | |
func NewReader(data string) ReaderContract { | |
return &Reader{ | |
Data: []byte(data), | |
Len: len(data), | |
State: ReadStateOpen, | |
} | |
} | |
func NewWriter() WriterContract { | |
return &Writer{ | |
Data: make([]byte, 0), | |
State: WriteStateOpen, | |
} | |
} | |
func (r *Reader) Close() error { | |
if r.State == ReadStateClose { | |
return ErrOnClosedState | |
} | |
r.Data = nil | |
r.Off = 0 | |
r.Len = 0 | |
r.State = ReadStateClose | |
return nil | |
} | |
func (r *Reader) Read(p []byte) (n int, err error) { | |
if r.State == ReadStateClose { | |
n = 0 | |
err = ErrOnClosedState | |
return | |
} | |
if r.Off >= r.Len { | |
n = 0 | |
err = io.EOF | |
return | |
} | |
for i := 0; i < len(p); i++ { | |
p[i] = 0 | |
} | |
copy(p, r.Data[r.Off:]) | |
rlen := len(p) | |
roff := r.Len - r.Off | |
if roff < rlen { | |
rlen = roff | |
} | |
r.Off += rlen | |
n = rlen | |
err = nil | |
return | |
} | |
func (w *Writer) Close() error { | |
if w.State == WriteStateClose { | |
return ErrOnClosedState | |
} | |
w.Data = nil | |
w.Len = 0 | |
w.State = WriteStateClose | |
return nil | |
} | |
func (w *Writer) Write(p []byte) (n int, err error) { | |
if w.State == WriteStateClose { | |
n = 0 | |
err = ErrOnClosedState | |
return | |
} | |
for i := 0; i < len(p); i++ { | |
w.Data = append(w.Data, p[i]) | |
w.Len++ | |
} | |
n = w.Len | |
err = nil | |
return | |
} | |
func (w Writer) Bytes() []byte { | |
if w.State == WriteStateClose { | |
return nil | |
} | |
return w.Data | |
} | |
func (w Writer) String() string { | |
if w.State == WriteStateClose { | |
return "" | |
} | |
return string(w.Data) | |
} | |
func (w Writer) Length() int { | |
if w.State == WriteStateClose { | |
return 0 | |
} | |
return w.Len | |
} | |
func Log(r io.Reader) { | |
b, err := ioutil.ReadAll(r) | |
if err != nil { | |
log.Fatal(err) | |
} | |
fmt.Printf("%s\n", b) | |
} | |
func main() { | |
r := NewReader("this is a text; otherwise, this is a shit.") | |
w := NewWriter() | |
t := io.TeeReader(r, w) | |
defer func(_r ReaderContract, _w WriterContract) { | |
if err := _r.Close(); err != nil { | |
panic(err) | |
} | |
if err := _w.Close(); err != nil { | |
panic(err) | |
} | |
}(r, w) | |
Log(t) | |
fmt.Println(w.String()) | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment