Skip to content

Instantly share code, notes, and snippets.

@plvhx
Created April 24, 2020 14:38
Show Gist options
  • Save plvhx/ea05893feda5ee0600f987a606fae94f to your computer and use it in GitHub Desktop.
Save plvhx/ea05893feda5ee0600f987a606fae94f to your computer and use it in GitHub Desktop.
io.ReadCloser and io.WriteCloser being wrapped together in io.TeeReader
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