diff --git a/cmd/cgat/main.go b/cmd/cgat/main.go
index 4f09e52123cdc4be9444b7af999de8c7d2b2fb04..f0cdd8c9fdfae987b27a6ce0840bb84a293debcb 100644
--- a/cmd/cgat/main.go
+++ b/cmd/cgat/main.go
@@ -9,7 +9,6 @@ import (
 	"pggat2/lib/bouncer/backends/v0"
 	"pggat2/lib/bouncer/bouncers/v2"
 	"pggat2/lib/bouncer/frontends/v0"
-	"pggat2/lib/middleware"
 	"pggat2/lib/middleware/interceptor"
 	"pggat2/lib/middleware/middlewares/eqp"
 	"pggat2/lib/middleware/middlewares/ps"
@@ -17,7 +16,6 @@ import (
 	"pggat2/lib/rob"
 	"pggat2/lib/rob/schedulers/v1"
 	"pggat2/lib/zap"
-	"pggat2/lib/zap/onebuffer"
 	"pggat2/lib/zap/zio"
 )
 
@@ -48,17 +46,18 @@ func testServer(r rob.Scheduler) {
 		panic(err)
 	}
 	rw := zio.MakeReadWriter(conn)
-	eqps := eqp.MakeServer()
-	pss := ps.MakeServer()
-	mw := interceptor.MakeInterceptor(&rw, []middleware.Middleware{
-		&eqps,
-		&pss,
-	})
-	backends.Accept(&mw, "postgres", "password", "uniswap")
+	eqps := eqp.NewServer()
+	pss := ps.NewServer()
+	mw := interceptor.NewInterceptor(
+		rw,
+		eqps,
+		pss,
+	)
+	backends.Accept(mw, "postgres", "password", "uniswap")
 	r.AddSink(0, server{
-		rw:   &mw,
-		eqps: &eqps,
-		pss:  &pss,
+		rw:   mw,
+		eqps: eqps,
+		pss:  pss,
 	})
 }
 
@@ -106,27 +105,22 @@ func main() {
 		go func() {
 			source := r.NewSource()
 			client := zio.MakeReadWriter(conn)
-			defer client.Done()
-			ob := onebuffer.MakeOnebuffer(&client)
-			eqpc := eqp.MakeClient()
+			eqpc := eqp.NewClient()
 			defer eqpc.Done()
-			psc := ps.MakeClient()
-			defer psc.Done()
-			mw := interceptor.MakeInterceptor(&ob, []middleware.Middleware{
+			psc := ps.NewClient()
+			mw := interceptor.NewInterceptor(
+				client,
 				unterminate.Unterminate,
-				&eqpc,
-				&psc,
-			})
-			frontends.Accept(&mw, DefaultParameterStatus)
+				eqpc,
+				psc,
+			)
+			frontends.Accept(mw, DefaultParameterStatus)
 			for {
-				err = ob.Buffer()
-				if err != nil {
-					break
-				}
+				// TODO(garet) sleep until more work is available
 				source.Do(0, work{
-					rw:   &mw,
-					eqpc: &eqpc,
-					psc:  &psc,
+					rw:   mw,
+					eqpc: eqpc,
+					psc:  psc,
 				})
 			}
 		}()
diff --git a/lib/middleware/context.go b/lib/middleware/context.go
index ba696bc9390a106ee1ff476db3b04a2dcb733c87..6df9341ed51526be3b63c7dfa4695894422b2039 100644
--- a/lib/middleware/context.go
+++ b/lib/middleware/context.go
@@ -6,6 +6,6 @@ type Context interface {
 	// Cancel the current packet
 	Cancel()
 
-	// Send to underlying writer
-	Send(out zap.Out) error
+	BuildBefore(typed bool) zap.Builder
+	BuildAfter(typed bool) zap.Builder
 }
diff --git a/lib/middleware/interceptor/context.go b/lib/middleware/interceptor/context.go
index 3df2fe1f8a492359b99b05b8ce864f4241bbf085..4c975b95d0f6fbb8c80a53b4cae3ec2ff18255fb 100644
--- a/lib/middleware/interceptor/context.go
+++ b/lib/middleware/interceptor/context.go
@@ -3,20 +3,16 @@ package interceptor
 import (
 	"pggat2/lib/middleware"
 	"pggat2/lib/util/decorator"
-	"pggat2/lib/zap"
 )
 
 type Context struct {
 	noCopy decorator.NoCopy
 
 	cancelled bool
-	zap.ReadWriter
 }
 
-func makeContext(rw zap.ReadWriter) Context {
-	return Context{
-		ReadWriter: rw,
-	}
+func makeContext() Context {
+	return Context{}
 }
 
 func (T *Context) reset() {
diff --git a/lib/middleware/interceptor/interceptor.go b/lib/middleware/interceptor/interceptor.go
index 3b0cb01753f5a342a4adafc2a6411b0f84419a41..1183bd9c8f6756e4abd70e63ca1e0f14f73bff55 100644
--- a/lib/middleware/interceptor/interceptor.go
+++ b/lib/middleware/interceptor/interceptor.go
@@ -1,88 +1,75 @@
 package interceptor
 
 import (
+	"time"
+
 	"pggat2/lib/middleware"
 	"pggat2/lib/zap"
 )
 
 type Interceptor struct {
 	middlewares []middleware.Middleware
-	Context
+	context     Context
+	rw          zap.ReadWriter
 }
 
-func MakeInterceptor(rw zap.ReadWriter, middlewares []middleware.Middleware) Interceptor {
-	return Interceptor{
+func NewInterceptor(rw zap.ReadWriter, middlewares ...middleware.Middleware) *Interceptor {
+	return &Interceptor{
 		middlewares: middlewares,
-		Context:     makeContext(rw),
+		context:     makeContext(),
 	}
 }
 
-func (T *Interceptor) Read() (zap.In, error) {
-	for {
-		in, err := T.ReadWriter.Read()
-		if err != nil {
-			return zap.In{}, err
-		}
+func (T *Interceptor) ReadInto(buffer *zap.Buffer, typed bool) error {
+	pre := buffer.Count()
+
+	if err := T.rw.ReadInto(buffer, typed); err != nil {
+		return err
+	}
+
+	post := buffer.Count()
 
-		T.Context.reset()
+	for i := pre; i < post; i++ {
 		for _, mw := range T.middlewares {
-			err = mw.Read(&T.Context, in)
-			if err != nil {
-				return zap.In{}, err
-			}
-			if T.cancelled {
-				break
+			T.context.reset()
+			if err := mw.Read(&T.context, buffer.Inspect(i)); err != nil {
+				return err
 			}
-			in.Reset()
-		}
 
-		if !T.cancelled {
-			return in, nil
+			if T.context.cancelled {
+				// TODO(garet) cancel packet
+				panic("TODO")
+			}
 		}
 	}
+
+	return nil
 }
 
-func (T *Interceptor) ReadUntyped() (zap.In, error) {
-	for {
-		in, err := T.ReadWriter.ReadUntyped()
-		if err != nil {
-			return zap.In{}, err
-		}
+func (T *Interceptor) SetReadDeadline(time time.Time) error {
+	return T.rw.SetReadDeadline(time)
+}
 
-		T.Context.reset()
+func (T *Interceptor) WriteFrom(buffer *zap.Buffer) error {
+	for i := 0; i < buffer.Count(); i++ {
 		for _, mw := range T.middlewares {
-			err = mw.Read(&T.Context, in)
-			if err != nil {
-				return zap.In{}, err
-			}
-			if T.cancelled {
-				break
+			T.context.reset()
+			if err := mw.Write(&T.context, buffer.Inspect(i)); err != nil {
+				return err
 			}
-			in.Reset()
-		}
 
-		if !T.cancelled {
-			return in, nil
+			if T.context.cancelled {
+				// TODO(garet) cancel packet
+				panic("TODO")
+			}
 		}
 	}
-}
 
-func (T *Interceptor) Send(out zap.Out) error {
-	T.Context.reset()
-	for _, mw := range T.middlewares {
-		err := mw.Send(&T.Context, out)
-		if err != nil {
-			return err
-		}
-		if T.cancelled {
-			break
-		}
-	}
+	return T.rw.WriteFrom(buffer)
+}
 
-	if !T.cancelled {
-		return T.Context.ReadWriter.Send(out)
-	}
-	return nil
+func (T *Interceptor) SetWriteDeadline(time time.Time) error {
+	return T.rw.SetWriteDeadline(time)
 }
 
 var _ zap.ReadWriter = (*Interceptor)(nil)
diff --git a/lib/middleware/middleware.go b/lib/middleware/middleware.go
index dac5eb766260235209e453e2bde9b8ce65a864fb..c0623c9d04f191a33b0b2d48e3e9752538c75604 100644
--- a/lib/middleware/middleware.go
+++ b/lib/middleware/middleware.go
@@ -3,6 +3,6 @@ package middleware
 import "pggat2/lib/zap"
 
 type Middleware interface {
-	Send(ctx Context, out zap.Out) error
-	Read(ctx Context, in zap.In) error
+	Write(ctx Context, packet zap.Inspector) error
+	Read(ctx Context, packet zap.Inspector) error
 }
diff --git a/lib/middleware/middlewares/eqp/client.go b/lib/middleware/middlewares/eqp/client.go
index d70fa978adbae2246ef4cb6f32089468a256beae..46569f5045f6fa17e319862422e81be129de36e6 100644
--- a/lib/middleware/middlewares/eqp/client.go
+++ b/lib/middleware/middlewares/eqp/client.go
@@ -13,8 +13,8 @@ type Client struct {
 	portals            map[string]Portal
 }
 
-func MakeClient() Client {
-	return Client{
+func NewClient() *Client {
+	return &Client{
 		preparedStatements: make(map[string]PreparedStatement),
 		portals:            make(map[string]Portal),
 	}
@@ -47,8 +47,7 @@ func (T *Client) Done() {
 	}
 }
 
-func (T *Client) Send(_ middleware.Context, out zap.Out) error {
-	in := zap.OutToIn(out)
+func (T *Client) Write(_ middleware.Context, in zap.Inspector) error {
 	switch in.Type() {
 	case packets.ReadyForQuery:
 		state, ok := packets.ReadReadyForQuery(in)
@@ -68,7 +67,7 @@ func (T *Client) Send(_ middleware.Context, out zap.Out) error {
 	return nil
 }
 
-func (T *Client) Read(ctx middleware.Context, in zap.In) error {
+func (T *Client) Read(ctx middleware.Context, in zap.Inspector) error {
 	switch in.Type() {
 	case packets.Query:
 		// clobber unnamed portal and unnamed prepared statement
diff --git a/lib/middleware/middlewares/eqp/portal.go b/lib/middleware/middlewares/eqp/portal.go
index 4b8c89ed0c780c4325a4f276d0736a7ee78728f8..ec3b8696de7e2f1f7c44a15225bc3f7a7421d175 100644
--- a/lib/middleware/middlewares/eqp/portal.go
+++ b/lib/middleware/middlewares/eqp/portal.go
@@ -14,7 +14,7 @@ type Portal struct {
 	hash   uint64
 }
 
-func ReadBind(in zap.In) (destination string, portal Portal, ok bool) {
+func ReadBind(in zap.Inspector) (destination string, portal Portal, ok bool) {
 	in.Reset()
 	if in.Type() != packets.Bind {
 		return
@@ -27,7 +27,7 @@ func ReadBind(in zap.In) (destination string, portal Portal, ok bool) {
 	if !ok {
 		return
 	}
-	full := zap.InToOut(in).Full()
+	full := in.Payload()
 	portal.hash = maphash.Bytes(seed, full)
 	portal.raw = global.GetBytes(int32(len(full)))
 	copy(portal.raw, full)
diff --git a/lib/middleware/middlewares/eqp/preparedStatement.go b/lib/middleware/middlewares/eqp/preparedStatement.go
index 2f354918cf8fa80b8faf6de54c6603dd433419bc..c6e9f9359fb165679d81b7df4e4fc8b336a531fe 100644
--- a/lib/middleware/middlewares/eqp/preparedStatement.go
+++ b/lib/middleware/middlewares/eqp/preparedStatement.go
@@ -13,7 +13,7 @@ type PreparedStatement struct {
 	hash uint64
 }
 
-func ReadParse(in zap.In) (destination string, preparedStatement PreparedStatement, ok bool) {
+func ReadParse(in zap.Inspector) (destination string, preparedStatement PreparedStatement, ok bool) {
 	in.Reset()
 	if in.Type() != packets.Parse {
 		return
@@ -22,7 +22,7 @@ func ReadParse(in zap.In) (destination string, preparedStatement PreparedStateme
 	if !ok {
 		return
 	}
-	full := zap.InToOut(in).Full()
+	full := in.Payload()
 	preparedStatement.hash = maphash.Bytes(seed, full)
 	preparedStatement.raw = global.GetBytes(int32(len(full)))
 	copy(preparedStatement.raw, full)
diff --git a/lib/middleware/middlewares/eqp/server.go b/lib/middleware/middlewares/eqp/server.go
index db0809adfb905c714e838d764f2278f40313622e..4cad60714beaf6ec9d507bc04f4d8cbf450f0193 100644
--- a/lib/middleware/middlewares/eqp/server.go
+++ b/lib/middleware/middlewares/eqp/server.go
@@ -22,13 +22,11 @@ type Server struct {
 	pendingPortals            ring.Ring[string]
 	pendingCloses             ring.Ring[Close]
 
-	buf zap.Buf
-
 	peer *Client
 }
 
-func MakeServer() Server {
-	return Server{
+func NewServer() *Server {
+	return &Server{
 		preparedStatements: make(map[string]uint64),
 		portals:            make(map[string]HashedPortal),
 	}
@@ -214,8 +212,7 @@ func (T *Server) syncPortal(ctx middleware.Context, target string) error {
 	return T.bindPortal(ctx, target, expected)
 }
 
-func (T *Server) Send(ctx middleware.Context, out zap.Out) error {
-	in := zap.OutToIn(out)
+func (T *Server) Write(ctx middleware.Context, in zap.Inspector) error {
 	switch in.Type() {
 	case packets.Query:
 		// clobber unnamed portal and unnamed prepared statement
@@ -263,7 +260,7 @@ func (T *Server) Send(ctx middleware.Context, out zap.Out) error {
 	return nil
 }
 
-func (T *Server) Read(ctx middleware.Context, in zap.In) error {
+func (T *Server) Read(ctx middleware.Context, in zap.Inspector) error {
 	switch in.Type() {
 	case packets.ParseComplete:
 		ctx.Cancel()
@@ -315,7 +312,6 @@ func (T *Server) Read(ctx middleware.Context, in zap.In) error {
 }
 
 func (T *Server) Done() {
-	T.buf.Done()
 	for name := range T.preparedStatements {
 		T.deletePreparedStatement(name)
 	}
diff --git a/lib/middleware/middlewares/ps/client.go b/lib/middleware/middlewares/ps/client.go
index bcf9302af916005b27f086ffc8b46f1b4757c7f5..86bf0003654d73a3c25984d1cec50b586e6d3b17 100644
--- a/lib/middleware/middlewares/ps/client.go
+++ b/lib/middleware/middlewares/ps/client.go
@@ -10,7 +10,6 @@ import (
 
 type Client struct {
 	parameters map[string]string
-	buf        zap.Buf
 
 	peer  *Server
 	dirty bool
@@ -18,16 +17,12 @@ type Client struct {
 	middleware.Nil
 }
 
-func MakeClient() Client {
-	return Client{
+func NewClient() *Client {
+	return &Client{
 		parameters: make(map[string]string),
 	}
 }
 
-func (T *Client) Done() {
-	T.buf.Done()
-}
-
 func (T *Client) SetServer(peer *Server) {
 	T.dirty = true
 	T.peer = peer
@@ -81,8 +76,7 @@ func (T *Client) sync(ctx middleware.Context) error {
 	return nil
 }
 
-func (T *Client) Send(ctx middleware.Context, out zap.Out) error {
-	in := zap.OutToIn(out)
+func (T *Client) Send(ctx middleware.Context, in zap.Inspector) error {
 	switch in.Type() {
 	case packets.ParameterStatus:
 		key, value, ok := packets.ReadParameterStatus(in)
diff --git a/lib/middleware/middlewares/ps/server.go b/lib/middleware/middlewares/ps/server.go
index 29f8990be50f9cb1aa5775b2028743e57c8597f6..aa7d9cb109bcaea63d395c22ea9f05b66f4ac83b 100644
--- a/lib/middleware/middlewares/ps/server.go
+++ b/lib/middleware/middlewares/ps/server.go
@@ -14,13 +14,13 @@ type Server struct {
 	middleware.Nil
 }
 
-func MakeServer() Server {
-	return Server{
+func NewServer() *Server {
+	return &Server{
 		parameters: make(map[string]string),
 	}
 }
 
-func (T *Server) Read(_ middleware.Context, in zap.In) error {
+func (T *Server) Read(_ middleware.Context, in zap.Inspector) error {
 	switch in.Type() {
 	case packets.ParameterStatus:
 		key, value, ok := packets.ReadParameterStatus(in)
diff --git a/lib/middleware/middlewares/unterminate/unterminate.go b/lib/middleware/middlewares/unterminate/unterminate.go
index 0f3e0b7cae55077856efb3280e6673370708eaa0..2dc5b2aadd9fca4f6551ca522d45bfce5717a07f 100644
--- a/lib/middleware/middlewares/unterminate/unterminate.go
+++ b/lib/middleware/middlewares/unterminate/unterminate.go
@@ -14,7 +14,7 @@ type unterm struct {
 	middleware.Nil
 }
 
-func (unterm) Read(_ middleware.Context, in zap.In) error {
+func (unterm) Read(_ middleware.Context, in zap.Inspector) error {
 	if in.Type() == packets.Terminate {
 		return io.EOF
 	}
diff --git a/lib/middleware/nil.go b/lib/middleware/nil.go
index f749bcd7389e0c894bbad38691927353414fa01a..b8ea179ce1d77db77733e90c35e2b1c9d9ca5ea8 100644
--- a/lib/middleware/nil.go
+++ b/lib/middleware/nil.go
@@ -4,11 +4,11 @@ import "pggat2/lib/zap"
 
 type Nil struct{}
 
-func (Nil) Send(_ Context, _ zap.Out) error {
+func (Nil) Write(_ Context, _ zap.Inspector) error {
 	return nil
 }
 
-func (Nil) Read(_ Context, _ zap.In) error {
+func (Nil) Read(_ Context, _ zap.Inspector) error {
 	return nil
 }
 
diff --git a/lib/zap/buf.go b/lib/zap/buf.go
deleted file mode 100644
index 38646535a58962a000703da9295b54c956bfca17..0000000000000000000000000000000000000000
--- a/lib/zap/buf.go
+++ /dev/null
@@ -1,363 +0,0 @@
-package zap
-
-import (
-	"encoding/binary"
-	"io"
-	"math"
-
-	"pggat2/lib/global"
-	"pggat2/lib/util/decorator"
-	"pggat2/lib/util/slices"
-)
-
-type Buf struct {
-	noCopy decorator.NoCopy
-
-	pos int
-	buf []byte
-	rev int
-}
-
-func (T *Buf) assertRev(rev int) {
-	// this check can be turned off when in production mode (for dev, this is helpful though)
-	if T.rev != rev {
-		panic("use after resource release")
-	}
-}
-
-func (T *Buf) setBufLen(length int) {
-	if cap(T.buf) < length {
-		newBuf := global.GetBytes(int32(length))
-		copy(newBuf, T.buf)
-		global.PutBytes(T.buf)
-		T.buf = newBuf
-		return
-	}
-	T.buf = slices.Resize(T.buf, length)
-}
-
-func (T *Buf) ensureBufExtra(extra int) {
-	if cap(T.buf) < len(T.buf)+extra {
-		newBuf := global.GetBytes(int32(len(T.buf) + extra))
-		copy(newBuf, T.buf)
-		newBuf = newBuf[:len(T.buf)]
-		global.PutBytes(T.buf)
-		T.buf = newBuf
-	}
-}
-
-func (T *Buf) In() In {
-	return In{
-		buf: T,
-		rev: T.rev,
-	}
-}
-
-func (T *Buf) Out() Out {
-	return Out{
-		buf: T,
-		rev: T.rev,
-	}
-}
-
-func (T *Buf) ReadByte(reader io.Reader) (byte, error) {
-	T.rev++
-	T.pos = 0
-
-	T.setBufLen(1)
-	_, err := io.ReadFull(reader, T.buf)
-	if err != nil {
-		return 0, err
-	}
-	return T.buf[0], nil
-}
-
-func (T *Buf) Read(reader io.Reader, typed bool) (In, error) {
-	T.rev++
-	T.pos = 0
-
-	// read header
-	T.setBufLen(5)
-	var err error
-	if typed {
-		_, err = io.ReadFull(reader, T.buf)
-	} else {
-		_, err = io.ReadFull(reader, T.buf[1:])
-	}
-	if err != nil {
-		return In{}, err
-	}
-
-	// extract length
-	length := binary.BigEndian.Uint32(T.buf[1:])
-
-	// read payload
-	T.setBufLen(int(length) + 1)
-	_, err = io.ReadFull(reader, T.buf[5:])
-	if err != nil {
-		return In{}, err
-	}
-
-	return T.In(), nil
-}
-
-func (T *Buf) WriteByte(writer io.Writer, b byte) error {
-	T.rev++
-	T.pos = 0
-
-	T.setBufLen(1)
-	T.buf[0] = b
-	_, err := writer.Write(T.buf)
-	return err
-}
-
-func (T *Buf) Write() Out {
-	T.rev++
-	T.pos = 0
-
-	T.setBufLen(5)
-	T.buf[0] = 0
-
-	return T.Out()
-}
-
-func (T *Buf) Swap(buf []byte) []byte {
-	T.pos = 0
-	T.rev++
-
-	v := T.buf
-	T.buf = buf
-	return v
-}
-
-func (T *Buf) Done() {
-	T.rev++
-	T.pos = 0
-	global.PutBytes(T.buf)
-	T.buf = nil
-}
-
-func (T *Buf) full() []byte {
-	// put length
-	binary.BigEndian.PutUint32(T.buf[1:], uint32(len(T.buf)-1))
-
-	if T.readType() == 0 {
-		// untyped
-		return T.buf[1:]
-	} else {
-		// typed
-		return T.buf
-	}
-}
-
-// read methods
-
-func (T *Buf) resetRead() {
-	T.pos = 0
-}
-
-func (T *Buf) readType() Type {
-	return Type(T.buf[0])
-}
-
-func (T *Buf) remaining() []byte {
-	return T.buf[T.pos+5:]
-}
-
-func (T *Buf) readUint8() (uint8, bool) {
-	rem := T.remaining()
-	if len(rem) < 1 {
-		return 0, false
-	}
-	T.pos += 1
-	return rem[0], true
-}
-
-func (T *Buf) readUint16() (uint16, bool) {
-	rem := T.remaining()
-	if len(rem) < 2 {
-		return 0, false
-	}
-	T.pos += 2
-	return binary.BigEndian.Uint16(rem), true
-}
-
-func (T *Buf) readUint32() (uint32, bool) {
-	rem := T.remaining()
-	if len(rem) < 4 {
-		return 0, false
-	}
-	T.pos += 4
-	return binary.BigEndian.Uint32(rem), true
-}
-
-func (T *Buf) readUint64() (uint64, bool) {
-	rem := T.remaining()
-	if len(rem) < 8 {
-		return 0, false
-	}
-	T.pos += 8
-	return binary.BigEndian.Uint64(rem), true
-}
-
-func (T *Buf) readInt8() (int8, bool) {
-	v, ok := T.readUint8()
-	if !ok {
-		return 0, false
-	}
-	return int8(v), true
-}
-
-func (T *Buf) readInt16() (int16, bool) {
-	v, ok := T.readUint16()
-	if !ok {
-		return 0, false
-	}
-	return int16(v), true
-}
-
-func (T *Buf) readInt32() (int32, bool) {
-	v, ok := T.readUint32()
-	if !ok {
-		return 0, false
-	}
-	return int32(v), true
-}
-
-func (T *Buf) readInt64() (int64, bool) {
-	v, ok := T.readUint64()
-	if !ok {
-		return 0, false
-	}
-	return int64(v), true
-}
-
-func (T *Buf) readFloat32() (float32, bool) {
-	v, ok := T.readUint32()
-	if !ok {
-		return 0, false
-	}
-	return math.Float32frombits(v), true
-}
-
-func (T *Buf) readFloat64() (float64, bool) {
-	v, ok := T.readUint64()
-	if !ok {
-		return 0, false
-	}
-	return math.Float64frombits(v), true
-}
-
-func (T *Buf) readUnsafeString() ([]byte, bool) {
-	rem := T.remaining()
-	for i, c := range rem {
-		if c == 0 {
-			T.pos += i + 1
-			return rem[:i], true
-		}
-	}
-	return nil, false
-}
-
-func (T *Buf) readStringBytes(v []byte) ([]byte, bool) {
-	str, ok := T.readUnsafeString()
-	v = slices.Resize(v, len(str))
-	copy(v, str)
-	return v, ok
-}
-
-func (T *Buf) readString() (string, bool) {
-	str, ok := T.readUnsafeString()
-	return string(str), ok
-}
-
-func (T *Buf) readBytes(b []byte) bool {
-	rem := T.remaining()
-	if len(rem) < len(b) {
-		return false
-	}
-	T.pos += len(b)
-	copy(b, rem)
-	return true
-}
-
-func (T *Buf) readUnsafeBytes(count int) ([]byte, bool) {
-	rem := T.remaining()
-	if len(rem) < count {
-		return nil, false
-	}
-	T.pos += count
-	return rem[:count], true
-}
-
-// write methods
-
-func (T *Buf) resetWrite() {
-	T.setBufLen(5)
-	T.buf[0] = 0
-}
-
-func (T *Buf) writeType(typ Type) {
-	T.buf[0] = byte(typ)
-}
-
-func (T *Buf) writeUint8(v uint8) {
-	T.ensureBufExtra(1)
-	T.buf = append(T.buf, v)
-}
-
-func (T *Buf) writeUint16(v uint16) {
-	T.ensureBufExtra(2)
-	T.buf = binary.BigEndian.AppendUint16(T.buf, v)
-}
-
-func (T *Buf) writeUint32(v uint32) {
-	T.ensureBufExtra(4)
-	T.buf = binary.BigEndian.AppendUint32(T.buf, v)
-}
-
-func (T *Buf) writeUint64(v uint64) {
-	T.ensureBufExtra(8)
-	T.buf = binary.BigEndian.AppendUint64(T.buf, v)
-}
-
-func (T *Buf) writeInt8(v int8) {
-	T.writeUint8(uint8(v))
-}
-
-func (T *Buf) writeInt16(v int16) {
-	T.writeUint16(uint16(v))
-}
-
-func (T *Buf) writeInt32(v int32) {
-	T.writeUint32(uint32(v))
-}
-
-func (T *Buf) writeInt64(v int64) {
-	T.writeUint64(uint64(v))
-}
-
-func (T *Buf) writeFloat32(v float32) {
-	T.writeUint32(math.Float32bits(v))
-}
-
-func (T *Buf) writeFloat64(v float64) {
-	T.writeUint64(math.Float64bits(v))
-}
-
-func (T *Buf) writeStringBytes(v []byte) {
-	T.ensureBufExtra(len(v) + 1)
-	T.buf = append(T.buf, v...)
-	T.buf = append(T.buf, 0)
-}
-
-func (T *Buf) writeString(v string) {
-	T.ensureBufExtra(len(v) + 1)
-	T.buf = append(T.buf, v...)
-	T.buf = append(T.buf, 0)
-}
-
-func (T *Buf) writeBytes(v []byte) {
-	T.ensureBufExtra(len(v))
-	T.buf = append(T.buf, v...)
-}
diff --git a/lib/zap/buffer.go b/lib/zap/buffer.go
new file mode 100644
index 0000000000000000000000000000000000000000..f39580f03155e2036be3c845d65b447bb67499a8
--- /dev/null
+++ b/lib/zap/buffer.go
@@ -0,0 +1,100 @@
+package zap
+
+import (
+	"encoding/binary"
+	"io"
+
+	"pggat2/lib/util/slices"
+)
+
+type buffered struct {
+	offset int
+	typed  bool
+}
+
+type Buffer struct {
+	primary []byte
+	items   []buffered
+}
+
+func (T *Buffer) ReadFrom(reader io.Reader, typed bool) error {
+	offset := len(T.primary)
+	if typed {
+		T.primary = append(T.primary, 0, 0, 0, 0, 0)
+	} else {
+		T.primary = append(T.primary, 0, 0, 0, 0)
+	}
+
+	_, err := io.ReadFull(reader, T.primary[offset:])
+	if err != nil {
+		T.primary = T.primary[:offset]
+		return err
+	}
+
+	var length uint32
+	if typed {
+		length = binary.BigEndian.Uint32(T.primary[offset+1:])
+	} else {
+		length = binary.BigEndian.Uint32(T.primary[offset:])
+	}
+
+	T.primary = slices.Resize(T.primary, len(T.primary)+int(length)-4)
+
+	var payload []byte
+	if typed {
+		payload = T.primary[offset+5:]
+	} else {
+		payload = T.primary[offset+4:]
+	}
+
+	_, err = io.ReadFull(reader, payload)
+	return err
+}
+
+func (T *Buffer) WriteInto(writer io.Writer) error {
+	_, err := writer.Write(T.primary)
+	return err
+}
+
+func (T *Buffer) Full() []byte {
+	return T.primary
+}
+
+func (T *Buffer) Reset() {
+	T.primary = T.primary[:0]
+	T.items = T.items[:0]
+}
+
+// Count returns the number of packets in the buffer
+func (T *Buffer) Count() int {
+	return len(T.items)
+}
+
+func (T *Buffer) Inspect(i int) Inspector {
+	item := T.items[i]
+	inspector := Inspector{
+		buffer: T,
+		offset: item.offset,
+		typed:  item.typed,
+	}
+	inspector.Reset()
+	return inspector
+}
+
+func (T *Buffer) Build(typed bool) Builder {
+	offset := len(T.primary)
+	T.items = append(T.items, buffered{
+		offset: offset,
+		typed:  typed,
+	})
+	if typed {
+		T.primary = append(T.primary, 0, 0, 0, 0, 4)
+	} else {
+		T.primary = append(T.primary, 0, 0, 0, 4)
+	}
+	return Builder{
+		buffer: T,
+		offset: offset,
+		typed:  typed,
+	}
+}
diff --git a/lib/zap/builder.go b/lib/zap/builder.go
new file mode 100644
index 0000000000000000000000000000000000000000..70421b0c44f7e25673c6b444f2d13143e097cfd3
--- /dev/null
+++ b/lib/zap/builder.go
@@ -0,0 +1,124 @@
+package zap
+
+import (
+	"encoding/binary"
+	"math"
+
+	"pggat2/lib/util/slices"
+)
+
+type Builder struct {
+	buffer *Buffer
+	offset int
+	typed  bool
+}
+
+func (T *Builder) Header() []byte {
+	if T.typed {
+		return T.buffer.primary[T.offset : T.offset+5]
+	}
+	return T.buffer.primary[T.offset : T.offset+4]
+}
+
+func (T *Builder) Payload() []byte {
+	length := T.GetLength()
+	if T.typed {
+		return T.buffer.primary[T.offset+5 : T.offset+5+length]
+	}
+	return T.buffer.primary[T.offset+4 : T.offset+4+length]
+}
+
+func (T *Builder) next(n int) []byte {
+	// add n to length
+	oldLength := T.GetLength()
+	T.Length(oldLength + n)
+
+	if T.typed {
+		return T.buffer.primary[T.offset+oldLength+1 : T.offset+oldLength+n+1]
+	}
+	return T.buffer.primary[T.offset+oldLength : T.offset+oldLength+n]
+}
+
+func (T *Builder) Reset() {
+	T.Length(4)
+	if T.typed {
+		T.Type(0)
+	}
+}
+
+func (T *Builder) Length(n int) {
+	header := T.Header()
+	length := header[len(header)-4:]
+
+	binary.BigEndian.PutUint32(length, uint32(n))
+
+	if T.typed {
+		T.buffer.primary = slices.Resize(T.buffer.primary, T.offset+n+1)
+	} else {
+		T.buffer.primary = slices.Resize(T.buffer.primary, T.offset+n)
+	}
+}
+
+func (T *Builder) GetLength() int {
+	header := T.Header()
+	length := header[len(header)-4:]
+
+	return int(binary.BigEndian.Uint32(length))
+}
+
+func (T *Builder) Type(typ Type) {
+	if !T.typed {
+		panic("Type() called on untyped builder")
+	}
+
+	T.buffer.primary[T.offset] = typ
+}
+
+func (T *Builder) Int8(v int8) {
+	T.Uint8(uint8(v))
+}
+
+func (T *Builder) Int16(v int16) {
+	T.Uint16(uint16(v))
+}
+
+func (T *Builder) Int32(v int32) {
+	T.Uint32(uint32(v))
+}
+
+func (T *Builder) Int64(v int64) {
+	T.Uint64(uint64(v))
+}
+
+func (T *Builder) Uint8(v uint8) {
+	T.next(1)[0] = v
+}
+
+func (T *Builder) Uint16(v uint16) {
+	binary.BigEndian.PutUint16(T.next(2), v)
+}
+
+func (T *Builder) Uint32(v uint32) {
+	binary.BigEndian.PutUint32(T.next(4), v)
+}
+
+func (T *Builder) Uint64(v uint64) {
+	binary.BigEndian.PutUint64(T.next(8), v)
+}
+
+func (T *Builder) Float32(v float32) {
+	T.Uint32(math.Float32bits(v))
+}
+
+func (T *Builder) Float64(v float64) {
+	T.Uint64(math.Float64bits(v))
+}
+
+func (T *Builder) String(v string) {
+	copy(T.next(len(v)), v)
+	T.Uint8(0)
+}
+
+func (T *Builder) Bytes(v []byte) {
+	copy(T.next(len(v)), v)
+}
diff --git a/lib/zap/in.go b/lib/zap/in.go
deleted file mode 100644
index 5eecf6258d924ab3f7af27ad9c0ca09b75f64470..0000000000000000000000000000000000000000
--- a/lib/zap/in.go
+++ /dev/null
@@ -1,91 +0,0 @@
-package zap
-
-type In struct {
-	buf *Buf
-	rev int
-}
-
-func (T In) Reset() {
-	T.buf.assertRev(T.rev)
-	T.buf.resetRead()
-}
-
-func (T In) Remaining() []byte {
-	T.buf.assertRev(T.rev)
-	return T.buf.remaining()
-}
-
-func (T In) Type() Type {
-	T.buf.assertRev(T.rev)
-	return T.buf.readType()
-}
-
-func (T In) Int8() (int8, bool) {
-	T.buf.assertRev(T.rev)
-	return T.buf.readInt8()
-}
-
-func (T In) Int16() (int16, bool) {
-	T.buf.assertRev(T.rev)
-	return T.buf.readInt16()
-}
-
-func (T In) Int32() (int32, bool) {
-	T.buf.assertRev(T.rev)
-	return T.buf.readInt32()
-}
-
-func (T In) Int64() (int64, bool) {
-	T.buf.assertRev(T.rev)
-	return T.buf.readInt64()
-}
-
-func (T In) Uint8() (uint8, bool) {
-	T.buf.assertRev(T.rev)
-	return T.buf.readUint8()
-}
-
-func (T In) Uint16() (uint16, bool) {
-	T.buf.assertRev(T.rev)
-	return T.buf.readUint16()
-}
-
-func (T In) Uint32() (uint32, bool) {
-	T.buf.assertRev(T.rev)
-	return T.buf.readUint32()
-}
-
-func (T In) Uint64() (uint64, bool) {
-	T.buf.assertRev(T.rev)
-	return T.buf.readUint64()
-}
-
-func (T In) Float32() (float32, bool) {
-	T.buf.assertRev(T.rev)
-	return T.buf.readFloat32()
-}
-
-func (T In) Float64() (float64, bool) {
-	T.buf.assertRev(T.rev)
-	return T.buf.readFloat64()
-}
-
-func (T In) StringBytes(b []byte) ([]byte, bool) {
-	T.buf.assertRev(T.rev)
-	return T.buf.readStringBytes(b)
-}
-
-func (T In) String() (string, bool) {
-	T.buf.assertRev(T.rev)
-	return T.buf.readString()
-}
-
-func (T In) Bytes(b []byte) bool {
-	T.buf.assertRev(T.rev)
-	return T.buf.readBytes(b)
-}
-
-func (T In) UnsafeBytes(count int) ([]byte, bool) {
-	T.buf.assertRev(T.rev)
-	return T.buf.readUnsafeBytes(count)
-}
diff --git a/lib/zap/inspector.go b/lib/zap/inspector.go
new file mode 100644
index 0000000000000000000000000000000000000000..408861b7ad77f17b2311a0d65251063f9782ce7d
--- /dev/null
+++ b/lib/zap/inspector.go
@@ -0,0 +1,164 @@
+package zap
+
+import (
+	"encoding/binary"
+	"math"
+)
+
+type Inspector struct {
+	buffer *Buffer
+	offset int
+	typed  bool
+
+	position int
+}
+
+func (T *Inspector) Reset() {
+	if T.typed {
+		T.position = 5
+	} else {
+		T.position = 4
+	}
+}
+
+func (T *Inspector) Length() int {
+	var length []byte
+	if T.typed {
+		length = T.buffer.primary[T.offset+1 : T.offset+5]
+	} else {
+		length = T.buffer.primary[T.offset : T.offset+4]
+	}
+
+	return int(binary.BigEndian.Uint32(length))
+}
+
+func (T *Inspector) Payload() []byte {
+	length := T.Length()
+	if T.typed {
+		return T.buffer.primary[T.offset+5 : T.offset+5+length]
+	}
+	return T.buffer.primary[T.offset+4 : T.offset+4+length]
+}
+
+func (T *Inspector) Remaining() []byte {
+	if T.typed {
+		return T.buffer.primary[T.offset+T.position : T.offset+T.Length()+1]
+	} else {
+		return T.buffer.primary[T.offset+T.position : T.offset+T.Length()]
+	}
+}
+
+func (T *Inspector) Type() Type {
+	if !T.typed {
+		panic("call of Type() on untyped packet")
+	}
+
+	return T.buffer.primary[T.offset]
+}
+
+func (T *Inspector) Int8() (int8, bool) {
+	if v, ok := T.Uint8(); ok {
+		return int8(v), true
+	}
+	return 0, false
+}
+
+func (T *Inspector) Int16() (int16, bool) {
+	if v, ok := T.Uint16(); ok {
+		return int16(v), true
+	}
+	return 0, false
+}
+
+func (T *Inspector) Int32() (int32, bool) {
+	if v, ok := T.Uint32(); ok {
+		return int32(v), true
+	}
+	return 0, false
+}
+
+func (T *Inspector) Int64() (int64, bool) {
+	if v, ok := T.Uint64(); ok {
+		return int64(v), true
+	}
+	return 0, false
+}
+
+func (T *Inspector) Uint8() (uint8, bool) {
+	rem := T.Remaining()
+	if len(rem) < 1 {
+		return 0, false
+	}
+	T.position += 1
+	return rem[0], true
+}
+
+func (T *Inspector) Uint16() (uint16, bool) {
+	rem := T.Remaining()
+	if len(rem) < 2 {
+		return 0, false
+	}
+	T.position += 2
+	return binary.BigEndian.Uint16(rem), true
+}
+
+func (T *Inspector) Uint32() (uint32, bool) {
+	rem := T.Remaining()
+	if len(rem) < 4 {
+		return 0, false
+	}
+	T.position += 4
+	return binary.BigEndian.Uint32(rem), true
+}
+
+func (T *Inspector) Uint64() (uint64, bool) {
+	rem := T.Remaining()
+	if len(rem) < 8 {
+		return 0, false
+	}
+	T.position += 8
+	return binary.BigEndian.Uint64(rem), true
+}
+
+func (T *Inspector) Float32() (float32, bool) {
+	if v, ok := T.Uint32(); ok {
+		return math.Float32frombits(v), true
+	}
+	return 0, false
+}
+
+func (T *Inspector) Float64() (float64, bool) {
+	if v, ok := T.Uint64(); ok {
+		return math.Float64frombits(v), true
+	}
+	return 0, false
+}
+
+func (T *Inspector) String() (string, bool) {
+	rem := T.Remaining()
+	for i, c := range rem {
+		if c == 0 {
+			T.position += i + 1
+			return string(rem[:i]), true
+		}
+	}
+	return "", false
+}
+
+func (T *Inspector) Bytes(b []byte) bool {
+	rem := T.Remaining()
+	if len(rem) < len(b) {
+		return false
+	}
+	T.position += copy(b, rem)
+	return true
+}
+
+func (T *Inspector) UnsafeBytes(count int) ([]byte, bool) {
+	rem := T.Remaining()
+	if len(rem) < count {
+		return nil, false
+	}
+	T.position += count
+	return rem[:count], true
+}
diff --git a/lib/zap/onebuffer/onebuffer.go b/lib/zap/onebuffer/onebuffer.go
deleted file mode 100644
index 3ecca273fe48d68b44f96ee178c4a7d71d04efa0..0000000000000000000000000000000000000000
--- a/lib/zap/onebuffer/onebuffer.go
+++ /dev/null
@@ -1,57 +0,0 @@
-package onebuffer
-
-import (
-	"pggat2/lib/util/decorator"
-	"pggat2/lib/zap"
-)
-
-type Onebuffer struct {
-	noCopy decorator.NoCopy
-
-	in   zap.In
-	read bool
-	zap.ReadWriter
-}
-
-func MakeOnebuffer(inner zap.ReadWriter) Onebuffer {
-	return Onebuffer{
-		read:       true,
-		ReadWriter: inner,
-	}
-}
-
-func (T *Onebuffer) Buffer() error {
-	if !T.read {
-		panic("a packet is already buffered in the Onebuffer!")
-	}
-	var err error
-	T.in, err = T.ReadWriter.Read()
-	T.read = false
-	return err
-}
-
-func (T *Onebuffer) BufferUntyped() error {
-	if !T.read {
-		panic("a packet is already buffered in the Onebuffer!")
-	}
-	var err error
-	T.in, err = T.ReadWriter.ReadUntyped()
-	T.read = false
-	return err
-}
-
-func (T *Onebuffer) Read() (zap.In, error) {
-	if !T.read {
-		T.read = true
-		return T.in, nil
-	}
-	return T.ReadWriter.Read()
-}
-
-func (T *Onebuffer) ReadUntyped() (zap.In, error) {
-	if !T.read {
-		T.read = true
-		return T.in, nil
-	}
-	return T.ReadWriter.ReadUntyped()
-}
diff --git a/lib/zap/out.go b/lib/zap/out.go
deleted file mode 100644
index 551f9d8c1405c9a9c9282bad9244b9af9066943c..0000000000000000000000000000000000000000
--- a/lib/zap/out.go
+++ /dev/null
@@ -1,86 +0,0 @@
-package zap
-
-type Out struct {
-	buf *Buf
-	rev int
-}
-
-func (T Out) Reset() {
-	T.buf.assertRev(T.rev)
-	T.buf.resetWrite()
-}
-
-func (T Out) Full() []byte {
-	T.buf.assertRev(T.rev)
-	return T.buf.full()
-}
-
-func (T Out) Type(typ Type) {
-	T.buf.assertRev(T.rev)
-	T.buf.writeType(typ)
-}
-
-func (T Out) Int8(v int8) {
-	T.buf.assertRev(T.rev)
-	T.buf.writeInt8(v)
-}
-
-func (T Out) Int16(v int16) {
-	T.buf.assertRev(T.rev)
-	T.buf.writeInt16(v)
-}
-
-func (T Out) Int32(v int32) {
-	T.buf.assertRev(T.rev)
-	T.buf.writeInt32(v)
-}
-
-func (T Out) Int64(v int64) {
-	T.buf.assertRev(T.rev)
-	T.buf.writeInt64(v)
-}
-
-func (T Out) Uint8(v uint8) {
-	T.buf.assertRev(T.rev)
-	T.buf.writeUint8(v)
-}
-
-func (T Out) Uint16(v uint16) {
-	T.buf.assertRev(T.rev)
-	T.buf.writeUint16(v)
-}
-
-func (T Out) Uint32(v uint32) {
-	T.buf.assertRev(T.rev)
-	T.buf.writeUint32(v)
-}
-
-func (T Out) Uint64(v uint64) {
-	T.buf.assertRev(T.rev)
-	T.buf.writeUint64(v)
-}
-
-func (T Out) Float32(v float32) {
-	T.buf.assertRev(T.rev)
-	T.buf.writeFloat32(v)
-}
-
-func (T Out) Float64(v float64) {
-	T.buf.assertRev(T.rev)
-	T.buf.writeFloat64(v)
-}
-
-func (T Out) StringBytes(v []byte) {
-	T.buf.assertRev(T.rev)
-	T.buf.writeStringBytes(v)
-}
-
-func (T Out) String(v string) {
-	T.buf.assertRev(T.rev)
-	T.buf.writeString(v)
-}
-
-func (T Out) Bytes(v []byte) {
-	T.buf.assertRev(T.rev)
-	T.buf.writeBytes(v)
-}
diff --git a/lib/zap/packets/v3.0/authenticationcleartext.go b/lib/zap/packets/v3.0/authenticationcleartext.go
index 9b3ebdbc407014b18ae819bc278d301f60f0b79d..bf415543dce965e64ca58092f2695116e622d0cf 100644
--- a/lib/zap/packets/v3.0/authenticationcleartext.go
+++ b/lib/zap/packets/v3.0/authenticationcleartext.go
@@ -1,10 +1,8 @@
 package packets
 
-import (
-	"pggat2/lib/zap"
-)
+import "pggat2/lib/zap"
 
-func ReadAuthenticationCleartext(in zap.In) bool {
+func ReadAuthenticationCleartext(in zap.Inspector) bool {
 	in.Reset()
 	if in.Type() != Authentication {
 		return false
@@ -19,7 +17,7 @@ func ReadAuthenticationCleartext(in zap.In) bool {
 	return true
 }
 
-func WriteAuthenticationCleartext(out zap.Out) {
+func WriteAuthenticationCleartext(out zap.Builder) {
 	out.Reset()
 	out.Type(Authentication)
 	out.Int32(3)
diff --git a/lib/zap/packets/v3.0/authenticationmd5.go b/lib/zap/packets/v3.0/authenticationmd5.go
index 2bcef712c0335e3774aabb430ff0662fd1c83c13..773066a0a1d386ed6a8ac0088507a8f147ebaa51 100644
--- a/lib/zap/packets/v3.0/authenticationmd5.go
+++ b/lib/zap/packets/v3.0/authenticationmd5.go
@@ -1,10 +1,8 @@
 package packets
 
-import (
-	"pggat2/lib/zap"
-)
+import "pggat2/lib/zap"
 
-func ReadAuthenticationMD5(in zap.In) ([4]byte, bool) {
+func ReadAuthenticationMD5(in zap.Inspector) ([4]byte, bool) {
 	in.Reset()
 	if in.Type() != Authentication {
 		return [4]byte{}, false
@@ -24,7 +22,7 @@ func ReadAuthenticationMD5(in zap.In) ([4]byte, bool) {
 	return salt, true
 }
 
-func WriteAuthenticationMD5(out zap.Out, salt [4]byte) {
+func WriteAuthenticationMD5(out zap.Builder, salt [4]byte) {
 	out.Reset()
 	out.Type(Authentication)
 	out.Uint32(5)
diff --git a/lib/zap/packets/v3.0/authenticationok.go b/lib/zap/packets/v3.0/authenticationok.go
index cd682ec5a31f4bb49cb0fa3d6c82b275ee46ec16..29271a7fb27e676a764c80be2f1cc5ccd995ba2f 100644
--- a/lib/zap/packets/v3.0/authenticationok.go
+++ b/lib/zap/packets/v3.0/authenticationok.go
@@ -4,7 +4,7 @@ import (
 	"pggat2/lib/zap"
 )
 
-func ReadAuthenticationOk(in zap.In) bool {
+func ReadAuthenticationOk(in zap.Inspector) bool {
 	in.Reset()
 	if in.Type() != Authentication {
 		return false
@@ -19,7 +19,7 @@ func ReadAuthenticationOk(in zap.In) bool {
 	return true
 }
 
-func WriteAuthenticationOk(out zap.Out) {
+func WriteAuthenticationOk(out zap.Builder) {
 	out.Reset()
 	out.Type(Authentication)
 	out.Int32(0)
diff --git a/lib/zap/packets/v3.0/authenticationresponse.go b/lib/zap/packets/v3.0/authenticationresponse.go
index 1dd93e0247ee1d66426f1c56bf356ae2742f3f88..eec9dc69d5e9ab2990dbafd78aadba07afb98d52 100644
--- a/lib/zap/packets/v3.0/authenticationresponse.go
+++ b/lib/zap/packets/v3.0/authenticationresponse.go
@@ -1,10 +1,8 @@
 package packets
 
-import (
-	"pggat2/lib/zap"
-)
+import "pggat2/lib/zap"
 
-func ReadAuthenticationResponse(in zap.In) ([]byte, bool) {
+func ReadAuthenticationResponse(in zap.Inspector) ([]byte, bool) {
 	in.Reset()
 	if in.Type() != AuthenticationResponse {
 		return nil, false
@@ -12,7 +10,7 @@ func ReadAuthenticationResponse(in zap.In) ([]byte, bool) {
 	return in.Remaining(), true
 }
 
-func WriteAuthenticationResponse(out zap.Out, resp []byte) {
+func WriteAuthenticationResponse(out zap.Builder, resp []byte) {
 	out.Reset()
 	out.Type(AuthenticationResponse)
 	out.Bytes(resp)
diff --git a/lib/zap/packets/v3.0/authenticationsasl.go b/lib/zap/packets/v3.0/authenticationsasl.go
index 5d6ba59fab4be8c8402f394ee3ba2117fb83ebef..dd9bc38e6b37b4b33a98978bdabe45d75a9b7dbd 100644
--- a/lib/zap/packets/v3.0/authenticationsasl.go
+++ b/lib/zap/packets/v3.0/authenticationsasl.go
@@ -1,10 +1,8 @@
 package packets
 
-import (
-	"pggat2/lib/zap"
-)
+import "pggat2/lib/zap"
 
-func ReadAuthenticationSASL(in zap.In) ([]string, bool) {
+func ReadAuthenticationSASL(in zap.Inspector) ([]string, bool) {
 	in.Reset()
 	if in.Type() != Authentication {
 		return nil, false
@@ -46,7 +44,7 @@ func ReadAuthenticationSASL(in zap.In) ([]string, bool) {
 	return mechanisms, true
 }
 
-func WriteAuthenticationSASL(out zap.Out, mechanisms []string) {
+func WriteAuthenticationSASL(out zap.Builder, mechanisms []string) {
 	out.Reset()
 	out.Type(Authentication)
 	out.Int32(10)
diff --git a/lib/zap/packets/v3.0/authenticationsaslcontinue.go b/lib/zap/packets/v3.0/authenticationsaslcontinue.go
index 269a373feb431f9050e088fbc45f7fcf1574ba42..cf7f18ff42f1125f9d4e3a7d92137fa506370276 100644
--- a/lib/zap/packets/v3.0/authenticationsaslcontinue.go
+++ b/lib/zap/packets/v3.0/authenticationsaslcontinue.go
@@ -4,7 +4,7 @@ import (
 	"pggat2/lib/zap"
 )
 
-func ReadAuthenticationSASLContinue(in zap.In) ([]byte, bool) {
+func ReadAuthenticationSASLContinue(in zap.Inspector) ([]byte, bool) {
 	in.Reset()
 	if in.Type() != Authentication {
 		return nil, false
@@ -19,7 +19,7 @@ func ReadAuthenticationSASLContinue(in zap.In) ([]byte, bool) {
 	return in.Remaining(), true
 }
 
-func WriteAuthenticationSASLContinue(out zap.Out, resp []byte) {
+func WriteAuthenticationSASLContinue(out zap.Builder, resp []byte) {
 	out.Reset()
 	out.Type(Authentication)
 	out.Int32(11)
diff --git a/lib/zap/packets/v3.0/authenticationsaslfinal.go b/lib/zap/packets/v3.0/authenticationsaslfinal.go
index 747a95091d0e0d87d67f679dad1a0785dd51642f..b29ae94efd13ff8b0e3d01ce54ee487009e34ebb 100644
--- a/lib/zap/packets/v3.0/authenticationsaslfinal.go
+++ b/lib/zap/packets/v3.0/authenticationsaslfinal.go
@@ -1,10 +1,8 @@
 package packets
 
-import (
-	"pggat2/lib/zap"
-)
+import "pggat2/lib/zap"
 
-func ReadAuthenticationSASLFinal(in zap.In) ([]byte, bool) {
+func ReadAuthenticationSASLFinal(in zap.Inspector) ([]byte, bool) {
 	in.Reset()
 	if in.Type() != Authentication {
 		return nil, false
@@ -19,7 +17,7 @@ func ReadAuthenticationSASLFinal(in zap.In) ([]byte, bool) {
 	return in.Remaining(), true
 }
 
-func WriteAuthenticationSASLFinal(out zap.Out, resp []byte) {
+func WriteAuthenticationSASLFinal(out zap.Builder, resp []byte) {
 	out.Reset()
 	out.Type(Authentication)
 	out.Int32(12)
diff --git a/lib/zap/packets/v3.0/backendkeydata.go b/lib/zap/packets/v3.0/backendkeydata.go
index feb05bac9571bfc2c4df9cc10dbf49d6653d70f4..74040a54ce33a3eceb4331ba839cb81da2d144b5 100644
--- a/lib/zap/packets/v3.0/backendkeydata.go
+++ b/lib/zap/packets/v3.0/backendkeydata.go
@@ -1,10 +1,8 @@
 package packets
 
-import (
-	"pggat2/lib/zap"
-)
+import "pggat2/lib/zap"
 
-func ReadBackendKeyData(in zap.In) ([8]byte, bool) {
+func ReadBackendKeyData(in zap.Inspector) ([8]byte, bool) {
 	in.Reset()
 	if in.Type() != BackendKeyData {
 		return [8]byte{}, false
@@ -17,7 +15,7 @@ func ReadBackendKeyData(in zap.In) ([8]byte, bool) {
 	return cancellationKey, true
 }
 
-func WriteBackendKeyData(out zap.Out, cancellationKey [8]byte) {
+func WriteBackendKeyData(out zap.Builder, cancellationKey [8]byte) {
 	out.Reset()
 	out.Type(BackendKeyData)
 	out.Bytes(cancellationKey[:])
diff --git a/lib/zap/packets/v3.0/bind.go b/lib/zap/packets/v3.0/bind.go
index b6effa444ee915d88d1166b61d7866298c43e653..9691883930d7f2da0d67986cdae80bc471a5e43d 100644
--- a/lib/zap/packets/v3.0/bind.go
+++ b/lib/zap/packets/v3.0/bind.go
@@ -4,7 +4,7 @@ import (
 	"pggat2/lib/zap"
 )
 
-func ReadBind(in zap.In) (destination string, source string, parameterFormatCodes []int16, parameterValues [][]byte, resultFormatCodes []int16, ok bool) {
+func ReadBind(in zap.Inspector) (destination string, source string, parameterFormatCodes []int16, parameterValues [][]byte, resultFormatCodes []int16, ok bool) {
 	in.Reset()
 	if in.Type() != Bind {
 		return
@@ -70,7 +70,7 @@ func ReadBind(in zap.In) (destination string, source string, parameterFormatCode
 	return
 }
 
-func WriteBind(out zap.Out, destination, source string, parameterFormatCodes []int16, parameterValues [][]byte, resultFormatCodes []int16) {
+func WriteBind(out zap.Builder, destination, source string, parameterFormatCodes []int16, parameterValues [][]byte, resultFormatCodes []int16) {
 	out.Reset()
 	out.Type(Bind)
 	out.String(destination)
diff --git a/lib/zap/packets/v3.0/close.go b/lib/zap/packets/v3.0/close.go
index 05e11bf9beb948e5ba639f7dbee8b3d5f9bcd6c6..e382f3d3b65f8713910671e3b3eb0cbe2481d5ee 100644
--- a/lib/zap/packets/v3.0/close.go
+++ b/lib/zap/packets/v3.0/close.go
@@ -1,10 +1,8 @@
 package packets
 
-import (
-	"pggat2/lib/zap"
-)
+import "pggat2/lib/zap"
 
-func ReadClose(in zap.In) (which uint8, target string, ok bool) {
+func ReadClose(in zap.Inspector) (which uint8, target string, ok bool) {
 	in.Reset()
 	if in.Type() != Close {
 		return
@@ -20,7 +18,7 @@ func ReadClose(in zap.In) (which uint8, target string, ok bool) {
 	return
 }
 
-func WriteClose(out zap.Out, which uint8, target string) {
+func WriteClose(out zap.Builder, which uint8, target string) {
 	out.Reset()
 	out.Type(Close)
 	out.Uint8(which)
diff --git a/lib/zap/packets/v3.0/describe.go b/lib/zap/packets/v3.0/describe.go
index 906abfbce91f265e1b1a729d8d8ece43a7300ccb..a5b52fff301e9ab392a61d7c94ed8957defd79df 100644
--- a/lib/zap/packets/v3.0/describe.go
+++ b/lib/zap/packets/v3.0/describe.go
@@ -4,7 +4,7 @@ import (
 	"pggat2/lib/zap"
 )
 
-func ReadDescribe(in zap.In) (which uint8, target string, ok bool) {
+func ReadDescribe(in zap.Inspector) (which uint8, target string, ok bool) {
 	in.Reset()
 	if in.Type() != Describe {
 		return
@@ -20,7 +20,7 @@ func ReadDescribe(in zap.In) (which uint8, target string, ok bool) {
 	return
 }
 
-func WriteDescribe(out zap.Out, which uint8, target string) {
+func WriteDescribe(out zap.Builder, which uint8, target string) {
 	out.Reset()
 	out.Type(Describe)
 	out.Uint8(which)
diff --git a/lib/zap/packets/v3.0/errorresponse.go b/lib/zap/packets/v3.0/errorresponse.go
index 2fae634108448d360bebf29b3c1de3fdcf514d83..d6f36cd59e88479df8888188f9e8d353591c65e3 100644
--- a/lib/zap/packets/v3.0/errorresponse.go
+++ b/lib/zap/packets/v3.0/errorresponse.go
@@ -5,7 +5,7 @@ import (
 	"pggat2/lib/zap"
 )
 
-func ReadErrorResponse(in zap.In) (perror.Error, bool) {
+func ReadErrorResponse(in zap.Inspector) (perror.Error, bool) {
 	in.Reset()
 	if in.Type() != ErrorResponse {
 		return nil, false
@@ -54,7 +54,7 @@ func ReadErrorResponse(in zap.In) (perror.Error, bool) {
 	), true
 }
 
-func WriteErrorResponse(out zap.Out, err perror.Error) {
+func WriteErrorResponse(out zap.Builder, err perror.Error) {
 	out.Reset()
 	out.Type(ErrorResponse)
 
diff --git a/lib/zap/packets/v3.0/execute.go b/lib/zap/packets/v3.0/execute.go
index 84fa064d11d75af53bc9b7c556fdbf481c4d57ef..7c32249a94cea7809e89b8e7223e3cbeb9e2a479 100644
--- a/lib/zap/packets/v3.0/execute.go
+++ b/lib/zap/packets/v3.0/execute.go
@@ -4,7 +4,7 @@ import (
 	"pggat2/lib/zap"
 )
 
-func ReadExecute(in zap.In) (target string, maxRows int32, ok bool) {
+func ReadExecute(in zap.Inspector) (target string, maxRows int32, ok bool) {
 	in.Reset()
 	if in.Type() != Execute {
 		return
@@ -20,7 +20,7 @@ func ReadExecute(in zap.In) (target string, maxRows int32, ok bool) {
 	return
 }
 
-func WriteExecute(out zap.Out, target string, maxRows int32) {
+func WriteExecute(out zap.Builder, target string, maxRows int32) {
 	out.Reset()
 	out.Type(Execute)
 	out.String(target)
diff --git a/lib/zap/packets/v3.0/negotiateprotocolversion.go b/lib/zap/packets/v3.0/negotiateprotocolversion.go
index db2df2b807345d331eb041bc8a976c3ae5f5c93d..73595713bb14c2490ccbc3559bc5245f70ca37a6 100644
--- a/lib/zap/packets/v3.0/negotiateprotocolversion.go
+++ b/lib/zap/packets/v3.0/negotiateprotocolversion.go
@@ -4,7 +4,7 @@ import (
 	"pggat2/lib/zap"
 )
 
-func ReadNegotiateProtocolVersion(in zap.In) (minorProtocolVersion int32, unrecognizedOptions []string, ok bool) {
+func ReadNegotiateProtocolVersion(in zap.Inspector) (minorProtocolVersion int32, unrecognizedOptions []string, ok bool) {
 	in.Reset()
 	if in.Type() != NegotiateProtocolVersion {
 		return
@@ -31,7 +31,7 @@ func ReadNegotiateProtocolVersion(in zap.In) (minorProtocolVersion int32, unreco
 	return
 }
 
-func WriteNegotiateProtocolVersion(out zap.Out, minorProtocolVersion int32, unrecognizedOptions []string) {
+func WriteNegotiateProtocolVersion(out zap.Builder, minorProtocolVersion int32, unrecognizedOptions []string) {
 	out.Reset()
 	out.Type(NegotiateProtocolVersion)
 	out.Int32(minorProtocolVersion)
diff --git a/lib/zap/packets/v3.0/parameterstatus.go b/lib/zap/packets/v3.0/parameterstatus.go
index 09b304cf4700148761935b123d1077f2b72074aa..cff7246aa0c17a2a82ce6a401e12276285e246ef 100644
--- a/lib/zap/packets/v3.0/parameterstatus.go
+++ b/lib/zap/packets/v3.0/parameterstatus.go
@@ -1,10 +1,8 @@
 package packets
 
-import (
-	"pggat2/lib/zap"
-)
+import "pggat2/lib/zap"
 
-func ReadParameterStatus(in zap.In) (key, value string, ok bool) {
+func ReadParameterStatus(in zap.Inspector) (key, value string, ok bool) {
 	in.Reset()
 	if in.Type() != ParameterStatus {
 		return
@@ -20,7 +18,7 @@ func ReadParameterStatus(in zap.In) (key, value string, ok bool) {
 	return
 }
 
-func WriteParameterStatus(out zap.Out, key, value string) {
+func WriteParameterStatus(out zap.Builder, key, value string) {
 	out.Reset()
 	out.Type(ParameterStatus)
 	out.String(key)
diff --git a/lib/zap/packets/v3.0/parse.go b/lib/zap/packets/v3.0/parse.go
index 087fe350b2a1bda4044575527f5aa5e1ca71d6cc..3d7c3f31be570c76bd26482a20cc7305014ccfd3 100644
--- a/lib/zap/packets/v3.0/parse.go
+++ b/lib/zap/packets/v3.0/parse.go
@@ -4,7 +4,7 @@ import (
 	"pggat2/lib/zap"
 )
 
-func ReadParse(in zap.In) (destination string, query string, parameterDataTypes []int32, ok bool) {
+func ReadParse(in zap.Inspector) (destination string, query string, parameterDataTypes []int32, ok bool) {
 	in.Reset()
 	if in.Type() != Parse {
 		return
@@ -34,7 +34,7 @@ func ReadParse(in zap.In) (destination string, query string, parameterDataTypes
 	return
 }
 
-func WriteParse(out zap.Out, destination string, query string, parameterDataTypes []int32) {
+func WriteParse(out zap.Builder, destination string, query string, parameterDataTypes []int32) {
 	out.Reset()
 	out.Type(Parse)
 	out.String(destination)
diff --git a/lib/zap/packets/v3.0/passwordmessage.go b/lib/zap/packets/v3.0/passwordmessage.go
index 89d16ad41ebf1915f4699c0a8d80bc814bb64fa1..f777e94c95118f457b1e70ec426f00e8673ba746 100644
--- a/lib/zap/packets/v3.0/passwordmessage.go
+++ b/lib/zap/packets/v3.0/passwordmessage.go
@@ -4,7 +4,7 @@ import (
 	"pggat2/lib/zap"
 )
 
-func ReadPasswordMessage(in zap.In) (string, bool) {
+func ReadPasswordMessage(in zap.Inspector) (string, bool) {
 	in.Reset()
 	if in.Type() != AuthenticationResponse {
 		return "", false
@@ -16,7 +16,7 @@ func ReadPasswordMessage(in zap.In) (string, bool) {
 	return password, true
 }
 
-func WritePasswordMessage(out zap.Out, password string) {
+func WritePasswordMessage(out zap.Builder, password string) {
 	out.Reset()
 	out.Type(AuthenticationResponse)
 	out.String(password)
diff --git a/lib/zap/packets/v3.0/readyforquery.go b/lib/zap/packets/v3.0/readyforquery.go
index b6d5ea82b71a5f2fd7d8df989e3b75f62a58b98b..f023ceb06cc5de23a20eee25300573e0a6d299b5 100644
--- a/lib/zap/packets/v3.0/readyforquery.go
+++ b/lib/zap/packets/v3.0/readyforquery.go
@@ -4,7 +4,7 @@ import (
 	"pggat2/lib/zap"
 )
 
-func ReadReadyForQuery(in zap.In) (byte, bool) {
+func ReadReadyForQuery(in zap.Inspector) (byte, bool) {
 	in.Reset()
 	if in.Type() != ReadyForQuery {
 		return 0, false
@@ -16,7 +16,7 @@ func ReadReadyForQuery(in zap.In) (byte, bool) {
 	return state, true
 }
 
-func WriteReadyForQuery(out zap.Out, state uint8) {
+func WriteReadyForQuery(out zap.Builder, state uint8) {
 	out.Reset()
 	out.Type(ReadyForQuery)
 	out.Uint8(state)
diff --git a/lib/zap/packets/v3.0/saslinitialresponse.go b/lib/zap/packets/v3.0/saslinitialresponse.go
index 4946f9bebd8b963501ae8d36b93069b9ac5bba35..6cbcd94b694e7fcc5a74c19c931b8be81629a823 100644
--- a/lib/zap/packets/v3.0/saslinitialresponse.go
+++ b/lib/zap/packets/v3.0/saslinitialresponse.go
@@ -4,7 +4,7 @@ import (
 	"pggat2/lib/zap"
 )
 
-func ReadSASLInitialResponse(in zap.In) (mechanism string, initialResponse []byte, ok bool) {
+func ReadSASLInitialResponse(in zap.Inspector) (mechanism string, initialResponse []byte, ok bool) {
 	in.Reset()
 	if in.Type() != AuthenticationResponse {
 		return
@@ -28,7 +28,7 @@ func ReadSASLInitialResponse(in zap.In) (mechanism string, initialResponse []byt
 	return
 }
 
-func WriteSASLInitialResponse(out zap.Out, mechanism string, initialResponse []byte) {
+func WriteSASLInitialResponse(out zap.Builder, mechanism string, initialResponse []byte) {
 	out.Reset()
 	out.Type(AuthenticationResponse)
 	out.String(mechanism)
diff --git a/lib/zap/reader.go b/lib/zap/reader.go
index 465f70ebb77d0a969398463fe5a13f7d8d1c5071..f16c4a554baf47b53231cd0eb8d022419549464e 100644
--- a/lib/zap/reader.go
+++ b/lib/zap/reader.go
@@ -1,14 +1,9 @@
 package zap
 
-import (
-	"io"
-	"time"
-)
+import "time"
 
 type Reader interface {
-	io.ByteReader
+	ReadInto(buffer *Buffer, typed bool) error
 
-	SetReadDeadline(deadline time.Time) error
-	Read() (In, error)
-	ReadUntyped() (In, error)
+	SetReadDeadline(time time.Time) error
 }
diff --git a/lib/zap/readwriter.go b/lib/zap/readwriter.go
index cc1093f22ec39dbd86210719ef3fa17744244d1f..22b2a309250d2e694b5a5c9ef842a57780499e85 100644
--- a/lib/zap/readwriter.go
+++ b/lib/zap/readwriter.go
@@ -1,9 +1,6 @@
 package zap
 
-import "time"
-
 type ReadWriter interface {
-	SetDeadline(deadline time.Time) error
 	Reader
 	Writer
 }
diff --git a/lib/zap/regender.go b/lib/zap/regender.go
deleted file mode 100644
index 9adb2ee7a3471c1b00320be04f6d750b93c28e7c..0000000000000000000000000000000000000000
--- a/lib/zap/regender.go
+++ /dev/null
@@ -1,15 +0,0 @@
-package zap
-
-func InToOut(in In) Out {
-	return Out{
-		buf: in.buf,
-		rev: in.rev,
-	}
-}
-
-func OutToIn(out Out) In {
-	return In{
-		buf: out.buf,
-		rev: out.rev,
-	}
-}
diff --git a/lib/zap/writer.go b/lib/zap/writer.go
index b58cbf7f6127f81cae9e5a209670e765dae9328e..aff1a982107897d4f5761d5a9945384a970a1bb9 100644
--- a/lib/zap/writer.go
+++ b/lib/zap/writer.go
@@ -1,14 +1,9 @@
 package zap
 
-import (
-	"io"
-	"time"
-)
+import "time"
 
 type Writer interface {
-	io.ByteWriter
+	WriteFrom(buffer *Buffer) error
 
-	SetWriteDeadline(deadline time.Time) error
-	Write() Out
-	Send(Out) error
+	SetWriteDeadline(time time.Time) error
 }
diff --git a/lib/zap/zio/reader.go b/lib/zap/zio/reader.go
deleted file mode 100644
index c405d25e0bab71f67485fd6a17036a206e9edeaf..0000000000000000000000000000000000000000
--- a/lib/zap/zio/reader.go
+++ /dev/null
@@ -1,44 +0,0 @@
-package zio
-
-import (
-	"io"
-	"time"
-
-	"pggat2/lib/util/dio"
-	"pggat2/lib/zap"
-)
-
-type Reader struct {
-	reader dio.Reader
-	r      io.Reader
-	buf    zap.Buf
-}
-
-func MakeReader(reader dio.Reader) Reader {
-	return Reader{
-		reader: reader,
-		r:      reader,
-	}
-}
-
-func (T *Reader) SetReadDeadline(deadline time.Time) error {
-	return T.reader.SetReadDeadline(deadline)
-}
-
-func (T *Reader) ReadByte() (byte, error) {
-	return T.buf.ReadByte(T.r)
-}
-
-func (T *Reader) Read() (zap.In, error) {
-	return T.buf.Read(T.r, true)
-}
-
-func (T *Reader) ReadUntyped() (zap.In, error) {
-	return T.buf.Read(T.r, false)
-}
-
-func (T *Reader) Done() {
-	T.buf.Done()
-}
-
-var _ zap.Reader = (*Reader)(nil)
diff --git a/lib/zap/zio/readwriter.go b/lib/zap/zio/readwriter.go
index d4fedd451cc90240752e29a07fd0711e798adee7..f1fe3ba3d1b8b54564c47eed4b6e26cff5f62b79 100644
--- a/lib/zap/zio/readwriter.go
+++ b/lib/zap/zio/readwriter.go
@@ -9,60 +9,39 @@ import (
 )
 
 type ReadWriter struct {
-	rw dio.ReadWriter
-	// they are seperated out to prevent an expensive runtime.convI2I (which causes runtime.getitab)
-	r   io.Reader
-	w   io.Writer
-	buf zap.Buf
+	io dio.ReadWriter
 }
 
-func MakeReadWriter(rw dio.ReadWriter) ReadWriter {
+func MakeReadWriter(io dio.ReadWriter) ReadWriter {
 	return ReadWriter{
-		rw: rw,
-		r:  rw,
-		w:  rw,
+		io: io,
 	}
 }
 
-func (T *ReadWriter) SetDeadline(deadline time.Time) error {
-	return T.rw.SetDeadline(deadline)
-}
-
-func (T *ReadWriter) SetReadDeadline(deadline time.Time) error {
-	return T.rw.SetReadDeadline(deadline)
-}
-
-func (T *ReadWriter) SetWriteDeadline(deadline time.Time) error {
-	return T.rw.SetWriteDeadline(deadline)
-}
-
-func (T *ReadWriter) ReadByte() (byte, error) {
-	return T.buf.ReadByte(T.r)
-}
-
-func (T *ReadWriter) Read() (zap.In, error) {
-	return T.buf.Read(T.r, true)
-}
+func (T ReadWriter) ReadInto(buffer *zap.Buffer, typed bool) error {
+	builder := buffer.Build(typed)
+	_, err := io.ReadFull(T.io, builder.Header())
+	if err != nil {
+		return err
+	}
 
-func (T *ReadWriter) ReadUntyped() (zap.In, error) {
-	return T.buf.Read(T.r, false)
-}
+	builder.Length(builder.GetLength())
 
-func (T *ReadWriter) WriteByte(b byte) error {
-	return T.buf.WriteByte(T.w, b)
+	_, err = io.ReadFull(T.io, builder.Payload())
+	return err
 }
 
-func (T *ReadWriter) Write() zap.Out {
-	return T.buf.Write()
+func (T ReadWriter) WriteFrom(buffer *zap.Buffer) error {
+	_, err := T.io.Write(buffer.Full())
+	return err
 }
 
-func (T *ReadWriter) Send(out zap.Out) error {
-	_, err := T.rw.Write(out.Full())
-	return err
+func (T ReadWriter) SetReadDeadline(time time.Time) error {
+	return T.io.SetReadDeadline(time)
 }
 
-func (T *ReadWriter) Done() {
-	T.buf.Done()
+func (T ReadWriter) SetWriteDeadline(time time.Time) error {
+	return T.io.SetWriteDeadline(time)
 }
 
-var _ zap.ReadWriter = (*ReadWriter)(nil)
+var _ zap.ReadWriter = ReadWriter{}
diff --git a/lib/zap/zio/writer.go b/lib/zap/zio/writer.go
deleted file mode 100644
index 8d5b6c104cebe8885bd89a5ab37671ad7a0f599f..0000000000000000000000000000000000000000
--- a/lib/zap/zio/writer.go
+++ /dev/null
@@ -1,45 +0,0 @@
-package zio
-
-import (
-	"io"
-	"time"
-
-	"pggat2/lib/util/dio"
-	"pggat2/lib/zap"
-)
-
-type Writer struct {
-	writer dio.Writer
-	w      io.Writer
-	buf    zap.Buf
-}
-
-func MakeWriter(writer dio.Writer) Writer {
-	return Writer{
-		writer: writer,
-		w:      writer,
-	}
-}
-
-func (T *Writer) SetWriteDeadline(deadline time.Time) error {
-	return T.writer.SetWriteDeadline(deadline)
-}
-
-func (T *Writer) WriteByte(b byte) error {
-	return T.buf.WriteByte(T.w, b)
-}
-
-func (T *Writer) Write() zap.Out {
-	return T.buf.Write()
-}
-
-func (T *Writer) Send(out zap.Out) error {
-	_, err := T.writer.Write(out.Full())
-	return err
-}
-
-func (T *Writer) Done() {
-	T.buf.Done()
-}
-
-var _ zap.Writer = (*Writer)(nil)
diff --git a/lib/zap3/packet.go b/lib/zap3/packet.go
new file mode 100644
index 0000000000000000000000000000000000000000..d80df9d70ce017faedce11af5d7c4a9bbecec908
--- /dev/null
+++ b/lib/zap3/packet.go
@@ -0,0 +1,273 @@
+package zap3
+
+import (
+	"encoding/binary"
+	"io"
+	"math"
+	"net"
+
+	"pggat2/lib/util/slices"
+)
+
+type Packets struct {
+	packets net.Buffers
+}
+
+func (T *Packets) WriteTo(w io.Writer) (int64, error) {
+	return T.packets.WriteTo(w)
+}
+
+func (T *Packets) Append(packet []byte) {
+	T.packets = append(T.packets, packet)
+}
+
+func (T *Packets) Clear() {
+	T.packets = T.packets[:0]
+}
+
+type PacketReader []byte
+
+func (T *PacketReader) ReadInt8() (int8, bool) {
+	if v, ok := T.ReadUint8(); ok {
+		return int8(v), true
+	}
+	return 0, false
+}
+
+func (T *PacketReader) ReadInt16() (int16, bool) {
+	if v, ok := T.ReadUint16(); ok {
+		return int16(v), true
+	}
+	return 0, false
+}
+
+func (T *PacketReader) ReadInt32() (int32, bool) {
+	if v, ok := T.ReadUint32(); ok {
+		return int32(v), true
+	}
+	return 0, false
+}
+
+func (T *PacketReader) ReadInt64() (int64, bool) {
+	if v, ok := T.ReadUint64(); ok {
+		return int64(v), true
+	}
+	return 0, false
+}
+
+func (T *PacketReader) ReadUint8() (uint8, bool) {
+	if len(*T) < 1 {
+		return 0, false
+	}
+
+	v := (*T)[0]
+	*T = (*T)[1:]
+	return v, true
+}
+
+func (T *PacketReader) ReadUint16() (uint16, bool) {
+	if len(*T) < 2 {
+		return 0, false
+	}
+
+	v := binary.BigEndian.Uint16(*T)
+	*T = (*T)[2:]
+	return v, true
+}
+
+func (T *PacketReader) ReadUint32() (uint32, bool) {
+	if len(*T) < 4 {
+		return 0, false
+	}
+
+	v := binary.BigEndian.Uint32(*T)
+	*T = (*T)[4:]
+	return v, true
+}
+
+func (T *PacketReader) ReadUint64() (uint64, bool) {
+	if len(*T) < 8 {
+		return 0, false
+	}
+
+	v := binary.BigEndian.Uint64(*T)
+	*T = (*T)[8:]
+	return v, true
+}
+
+func (T *PacketReader) ReadFloat32() (float32, bool) {
+	if v, ok := T.ReadUint32(); ok {
+		return math.Float32frombits(v), true
+	}
+
+	return 0, false
+}
+
+func (T *PacketReader) ReadFloat64() (float64, bool) {
+	if v, ok := T.ReadUint64(); ok {
+		return math.Float64frombits(v), true
+	}
+
+	return 0, false
+}
+
+func (T *PacketReader) ReadString() (string, bool) {
+	for i, b := range *T {
+		if b == 0 {
+			v := (*T)[:i]
+			*T = (*T)[i+1:]
+			return string(v), true
+		}
+	}
+
+	return "", false
+}
+
+func (T *PacketReader) ReadBytes(b []byte) bool {
+	if len(*T) < len(b) {
+		return false
+	}
+
+	copy(b, *T)
+	*T = (*T)[len(b):]
+	return true
+}
+
+type PacketWriter []byte
+
+func (T *PacketWriter) WriteInt8(v int8) {
+	T.WriteUint8(uint8(v))
+}
+
+func (T *PacketWriter) WriteInt16(v int16) {
+	T.WriteUint16(uint16(v))
+}
+
+func (T *PacketWriter) WriteInt32(v int32) {
+	T.WriteUint32(uint32(v))
+}
+
+func (T *PacketWriter) WriteInt64(v int64) {
+	T.WriteUint64(uint64(v))
+}
+
+func (T *PacketWriter) WriteUint8(v uint8) {
+	*T = append(*T, v)
+}
+
+func (T *PacketWriter) WriteUint16(v uint16) {
+	*T = binary.BigEndian.AppendUint16(*T, v)
+}
+
+func (T *PacketWriter) WriteUint32(v uint32) {
+	*T = binary.BigEndian.AppendUint32(*T, v)
+}
+
+func (T *PacketWriter) WriteUint64(v uint64) {
+	*T = binary.BigEndian.AppendUint64(*T, v)
+}
+
+func (T *PacketWriter) WriteFloat32(v float32) {
+	T.WriteUint32(math.Float32bits(v))
+}
+
+func (T *PacketWriter) WriteFloat64(v float64) {
+	T.WriteUint64(math.Float64bits(v))
+}
+
+func (T *PacketWriter) WriteString(v string) {
+	*T = append(*T, v...)
+	T.WriteUint8(0)
+}
+
+func (T *PacketWriter) WriteBytes(v []byte) {
+	*T = append(*T, v...)
+}
+
+type ReadablePacket struct {
+	PacketReader
+	typ Type
+}
+
+func (T *ReadablePacket) ReadType() Type {
+	return T.typ
+}
+
+type Packet struct {
+	PacketWriter
+}
+
+func (T *Packet) ReadFrom(r io.Reader) (int64, error) {
+	T.PacketWriter = slices.Resize(T.PacketWriter, 5)
+	n, err := io.ReadFull(r, T.PacketWriter)
+	if err != nil {
+		return int64(n), err
+	}
+	length := T.Length()
+	T.PacketWriter = slices.Resize(T.PacketWriter, int(length)+1)
+	m, err := io.ReadFull(r, T.Payload())
+	return int64(n + m), err
+}
+
+func (T *Packet) WriteTo(w io.Writer) (int64, error) {
+	n, err := w.Write(T.PacketWriter)
+	return int64(n), err
+}
+
+func (T *Packet) Length() uint32 {
+	return binary.BigEndian.Uint32(T.PacketWriter[1:])
+}
+
+func (T *Packet) Payload() []byte {
+	return T.PacketWriter[5:]
+}
+
+func (T *Packet) WriteType(v Type) {
+	T.PacketWriter[0] = v
+}
+
+func (T *Packet) Read() ReadablePacket {
+	return ReadablePacket{
+		typ:          T.PacketWriter[0],
+		PacketReader: T.Payload(),
+	}
+}
+
+type UntypedReadablePacket struct {
+	PacketReader
+}
+
+type UntypedPacket struct {
+	PacketWriter
+}
+
+func (T *UntypedPacket) ReadFrom(r io.Reader) (int64, error) {
+	T.PacketWriter = slices.Resize(T.PacketWriter, 4)
+	n, err := io.ReadFull(r, T.PacketWriter)
+	if err != nil {
+		return int64(n), err
+	}
+	length := T.Length()
+	T.PacketWriter = slices.Resize(T.PacketWriter, int(length))
+	m, err := io.ReadFull(r, T.Payload())
+	return int64(n + m), err
+}
+
+func (T *UntypedPacket) WriteTo(w io.Writer) (int64, error) {
+	n, err := w.Write(T.PacketWriter)
+	return int64(n), err
+}
+
+func (T *UntypedPacket) Length() uint32 {
+	return binary.BigEndian.Uint32(T.PacketWriter)
+}
+
+func (T *UntypedPacket) Payload() []byte {
+	return T.PacketWriter[4:]
+}
+
+func (T *UntypedPacket) Read() UntypedReadablePacket {
+	return UntypedReadablePacket{
+		PacketReader: PacketReader(T.Payload()),
+	}
+}
diff --git a/lib/zap3/packets/v3.0/authenticationcleartext.go b/lib/zap3/packets/v3.0/authenticationcleartext.go
new file mode 100644
index 0000000000000000000000000000000000000000..594ca6eb4fde79bb389923037a16bb3ce294fa56
--- /dev/null
+++ b/lib/zap3/packets/v3.0/authenticationcleartext.go
@@ -0,0 +1,24 @@
+package packets
+
+import (
+	"pggat2/lib/zap3"
+)
+
+func ReadAuthenticationCleartext(in *zap3.ReadablePacket) bool {
+	if in.ReadType() != Authentication {
+		return false
+	}
+	method, ok := in.ReadInt32()
+	if !ok {
+		return false
+	}
+	if method != 3 {
+		return false
+	}
+	return true
+}
+
+func WriteAuthenticationCleartext(out *zap3.Packet) {
+	out.WriteType(Authentication)
+	out.WriteInt32(3)
+}
diff --git a/lib/zap3/packets/v3.0/authenticationmd5.go b/lib/zap3/packets/v3.0/authenticationmd5.go
new file mode 100644
index 0000000000000000000000000000000000000000..4837b36a49ee988e3a4c9dd5fd87be2f3b82172e
--- /dev/null
+++ b/lib/zap3/packets/v3.0/authenticationmd5.go
@@ -0,0 +1,30 @@
+package packets
+
+import (
+	"pggat2/lib/zap3"
+)
+
+func ReadAuthenticationMD5(in *zap3.ReadablePacket) ([4]byte, bool) {
+	if in.ReadType() != Authentication {
+		return [4]byte{}, false
+	}
+	method, ok := in.ReadInt32()
+	if !ok {
+		return [4]byte{}, false
+	}
+	if method != 5 {
+		return [4]byte{}, false
+	}
+	var salt [4]byte
+	ok = in.ReadBytes(salt[:])
+	if !ok {
+		return salt, false
+	}
+	return salt, true
+}
+
+func WriteAuthenticationMD5(out *zap3.Packet, salt [4]byte) {
+	out.WriteType(Authentication)
+	out.WriteUint32(5)
+	out.WriteBytes(salt[:])
+}
diff --git a/lib/zap3/packets/v3.0/authenticationok.go b/lib/zap3/packets/v3.0/authenticationok.go
new file mode 100644
index 0000000000000000000000000000000000000000..ddd35f9f46939bbf86aabea32cabcbfb1d1339a5
--- /dev/null
+++ b/lib/zap3/packets/v3.0/authenticationok.go
@@ -0,0 +1,24 @@
+package packets
+
+import (
+	"pggat2/lib/zap3"
+)
+
+func ReadAuthenticationOk(in *zap3.ReadablePacket) bool {
+	if in.ReadType() != Authentication {
+		return false
+	}
+	method, ok := in.ReadInt32()
+	if !ok {
+		return false
+	}
+	if method != 0 {
+		return false
+	}
+	return true
+}
+
+func WriteAuthenticationOk(out *zap3.Packet) {
+	out.WriteType(Authentication)
+	out.WriteInt32(0)
+}
diff --git a/lib/zap3/packets/v3.0/authenticationresponse.go b/lib/zap3/packets/v3.0/authenticationresponse.go
new file mode 100644
index 0000000000000000000000000000000000000000..eec9dc69d5e9ab2990dbafd78aadba07afb98d52
--- /dev/null
+++ b/lib/zap3/packets/v3.0/authenticationresponse.go
@@ -0,0 +1,17 @@
+package packets
+
+import "pggat2/lib/zap"
+
+func ReadAuthenticationResponse(in zap.Inspector) ([]byte, bool) {
+	in.Reset()
+	if in.Type() != AuthenticationResponse {
+		return nil, false
+	}
+	return in.Remaining(), true
+}
+
+func WriteAuthenticationResponse(out zap.Builder, resp []byte) {
+	out.Reset()
+	out.Type(AuthenticationResponse)
+	out.Bytes(resp)
+}
diff --git a/lib/zap3/packets/v3.0/authenticationsasl.go b/lib/zap3/packets/v3.0/authenticationsasl.go
new file mode 100644
index 0000000000000000000000000000000000000000..dd9bc38e6b37b4b33a98978bdabe45d75a9b7dbd
--- /dev/null
+++ b/lib/zap3/packets/v3.0/authenticationsasl.go
@@ -0,0 +1,55 @@
+package packets
+
+import "pggat2/lib/zap"
+
+func ReadAuthenticationSASL(in zap.Inspector) ([]string, bool) {
+	in.Reset()
+	if in.Type() != Authentication {
+		return nil, false
+	}
+
+	method, ok := in.Int32()
+	if !ok {
+		return nil, false
+	}
+
+	if method != 10 {
+		return nil, false
+	}
+
+	// get count first to prevent reallocating the slice a bunch
+	var mechanismCount int
+	for {
+		mechanism, ok := in.String()
+		if !ok {
+			return nil, false
+		}
+		if mechanism == "" {
+			break
+		}
+		mechanismCount++
+	}
+
+	mechanisms := make([]string, 0, mechanismCount)
+	in.Reset()
+	in.Int32()
+	for i := 0; i < mechanismCount; i++ {
+		mechanism, ok := in.String()
+		if !ok {
+			return nil, false
+		}
+		mechanisms = append(mechanisms, mechanism)
+	}
+
+	return mechanisms, true
+}
+
+func WriteAuthenticationSASL(out zap.Builder, mechanisms []string) {
+	out.Reset()
+	out.Type(Authentication)
+	out.Int32(10)
+	for _, mechanism := range mechanisms {
+		out.String(mechanism)
+	}
+	out.Uint8(0)
+}
diff --git a/lib/zap3/packets/v3.0/authenticationsaslcontinue.go b/lib/zap3/packets/v3.0/authenticationsaslcontinue.go
new file mode 100644
index 0000000000000000000000000000000000000000..cf7f18ff42f1125f9d4e3a7d92137fa506370276
--- /dev/null
+++ b/lib/zap3/packets/v3.0/authenticationsaslcontinue.go
@@ -0,0 +1,27 @@
+package packets
+
+import (
+	"pggat2/lib/zap"
+)
+
+func ReadAuthenticationSASLContinue(in zap.Inspector) ([]byte, bool) {
+	in.Reset()
+	if in.Type() != Authentication {
+		return nil, false
+	}
+	method, ok := in.Int32()
+	if !ok {
+		return nil, false
+	}
+	if method != 11 {
+		return nil, false
+	}
+	return in.Remaining(), true
+}
+
+func WriteAuthenticationSASLContinue(out zap.Builder, resp []byte) {
+	out.Reset()
+	out.Type(Authentication)
+	out.Int32(11)
+	out.Bytes(resp)
+}
diff --git a/lib/zap3/packets/v3.0/authenticationsaslfinal.go b/lib/zap3/packets/v3.0/authenticationsaslfinal.go
new file mode 100644
index 0000000000000000000000000000000000000000..b29ae94efd13ff8b0e3d01ce54ee487009e34ebb
--- /dev/null
+++ b/lib/zap3/packets/v3.0/authenticationsaslfinal.go
@@ -0,0 +1,25 @@
+package packets
+
+import "pggat2/lib/zap"
+
+func ReadAuthenticationSASLFinal(in zap.Inspector) ([]byte, bool) {
+	in.Reset()
+	if in.Type() != Authentication {
+		return nil, false
+	}
+	method, ok := in.Int32()
+	if !ok {
+		return nil, false
+	}
+	if method != 12 {
+		return nil, false
+	}
+	return in.Remaining(), true
+}
+
+func WriteAuthenticationSASLFinal(out zap.Builder, resp []byte) {
+	out.Reset()
+	out.Type(Authentication)
+	out.Int32(12)
+	out.Bytes(resp)
+}
diff --git a/lib/zap3/packets/v3.0/backendkeydata.go b/lib/zap3/packets/v3.0/backendkeydata.go
new file mode 100644
index 0000000000000000000000000000000000000000..74040a54ce33a3eceb4331ba839cb81da2d144b5
--- /dev/null
+++ b/lib/zap3/packets/v3.0/backendkeydata.go
@@ -0,0 +1,22 @@
+package packets
+
+import "pggat2/lib/zap"
+
+func ReadBackendKeyData(in zap.Inspector) ([8]byte, bool) {
+	in.Reset()
+	if in.Type() != BackendKeyData {
+		return [8]byte{}, false
+	}
+	var cancellationKey [8]byte
+	ok := in.Bytes(cancellationKey[:])
+	if !ok {
+		return cancellationKey, false
+	}
+	return cancellationKey, true
+}
+
+func WriteBackendKeyData(out zap.Builder, cancellationKey [8]byte) {
+	out.Reset()
+	out.Type(BackendKeyData)
+	out.Bytes(cancellationKey[:])
+}
diff --git a/lib/zap3/packets/v3.0/bind.go b/lib/zap3/packets/v3.0/bind.go
new file mode 100644
index 0000000000000000000000000000000000000000..9691883930d7f2da0d67986cdae80bc471a5e43d
--- /dev/null
+++ b/lib/zap3/packets/v3.0/bind.go
@@ -0,0 +1,95 @@
+package packets
+
+import (
+	"pggat2/lib/zap"
+)
+
+func ReadBind(in zap.Inspector) (destination string, source string, parameterFormatCodes []int16, parameterValues [][]byte, resultFormatCodes []int16, ok bool) {
+	in.Reset()
+	if in.Type() != Bind {
+		return
+	}
+	destination, ok = in.String()
+	if !ok {
+		return
+	}
+	source, ok = in.String()
+	if !ok {
+		return
+	}
+	var parameterFormatCodesLength uint16
+	parameterFormatCodesLength, ok = in.Uint16()
+	if !ok {
+		return
+	}
+	parameterFormatCodes = make([]int16, 0, int(parameterFormatCodesLength))
+	for i := 0; i < int(parameterFormatCodesLength); i++ {
+		var parameterFormatCode int16
+		parameterFormatCode, ok = in.Int16()
+		if !ok {
+			return
+		}
+		parameterFormatCodes = append(parameterFormatCodes, parameterFormatCode)
+	}
+	var parameterValuesLength uint16
+	parameterValuesLength, ok = in.Uint16()
+	if !ok {
+		return
+	}
+	parameterValues = make([][]byte, 0, int(parameterValuesLength))
+	for i := 0; i < int(parameterValuesLength); i++ {
+		var parameterValueLength int32
+		parameterValueLength, ok = in.Int32()
+		if !ok {
+			return
+		}
+		var parameterValue []byte
+		if parameterValueLength >= 0 {
+			parameterValue = make([]byte, int(parameterValueLength))
+			ok = in.Bytes(parameterValue)
+			if !ok {
+				return
+			}
+		}
+		parameterValues = append(parameterValues, parameterValue)
+	}
+	var resultFormatCodesLength uint16
+	resultFormatCodesLength, ok = in.Uint16()
+	if !ok {
+		return
+	}
+	resultFormatCodes = make([]int16, 0, int(resultFormatCodesLength))
+	for i := 0; i < int(resultFormatCodesLength); i++ {
+		var resultFormatCode int16
+		resultFormatCode, ok = in.Int16()
+		if !ok {
+			return
+		}
+		resultFormatCodes = append(resultFormatCodes, resultFormatCode)
+	}
+	return
+}
+
+func WriteBind(out zap.Builder, destination, source string, parameterFormatCodes []int16, parameterValues [][]byte, resultFormatCodes []int16) {
+	out.Reset()
+	out.Type(Bind)
+	out.String(destination)
+	out.String(source)
+	out.Uint16(uint16(len(parameterFormatCodes)))
+	for _, v := range parameterFormatCodes {
+		out.Int16(v)
+	}
+	out.Uint16(uint16(len(parameterValues)))
+	for _, v := range parameterValues {
+		if v == nil {
+			out.Int32(-1)
+			continue
+		}
+		out.Int32(int32(len(v)))
+		out.Bytes(v)
+	}
+	out.Uint16(uint16(len(resultFormatCodes)))
+	for _, v := range resultFormatCodes {
+		out.Int16(v)
+	}
+}
diff --git a/lib/zap3/packets/v3.0/close.go b/lib/zap3/packets/v3.0/close.go
new file mode 100644
index 0000000000000000000000000000000000000000..e382f3d3b65f8713910671e3b3eb0cbe2481d5ee
--- /dev/null
+++ b/lib/zap3/packets/v3.0/close.go
@@ -0,0 +1,26 @@
+package packets
+
+import "pggat2/lib/zap"
+
+func ReadClose(in zap.Inspector) (which uint8, target string, ok bool) {
+	in.Reset()
+	if in.Type() != Close {
+		return
+	}
+	which, ok = in.Uint8()
+	if !ok {
+		return
+	}
+	target, ok = in.String()
+	if !ok {
+		return
+	}
+	return
+}
+
+func WriteClose(out zap.Builder, which uint8, target string) {
+	out.Reset()
+	out.Type(Close)
+	out.Uint8(which)
+	out.String(target)
+}
diff --git a/lib/zap3/packets/v3.0/describe.go b/lib/zap3/packets/v3.0/describe.go
new file mode 100644
index 0000000000000000000000000000000000000000..a5b52fff301e9ab392a61d7c94ed8957defd79df
--- /dev/null
+++ b/lib/zap3/packets/v3.0/describe.go
@@ -0,0 +1,28 @@
+package packets
+
+import (
+	"pggat2/lib/zap"
+)
+
+func ReadDescribe(in zap.Inspector) (which uint8, target string, ok bool) {
+	in.Reset()
+	if in.Type() != Describe {
+		return
+	}
+	which, ok = in.Uint8()
+	if !ok {
+		return
+	}
+	target, ok = in.String()
+	if !ok {
+		return
+	}
+	return
+}
+
+func WriteDescribe(out zap.Builder, which uint8, target string) {
+	out.Reset()
+	out.Type(Describe)
+	out.Uint8(which)
+	out.String(target)
+}
diff --git a/lib/zap3/packets/v3.0/errorresponse.go b/lib/zap3/packets/v3.0/errorresponse.go
new file mode 100644
index 0000000000000000000000000000000000000000..d6f36cd59e88479df8888188f9e8d353591c65e3
--- /dev/null
+++ b/lib/zap3/packets/v3.0/errorresponse.go
@@ -0,0 +1,76 @@
+package packets
+
+import (
+	"pggat2/lib/perror"
+	"pggat2/lib/zap"
+)
+
+func ReadErrorResponse(in zap.Inspector) (perror.Error, bool) {
+	in.Reset()
+	if in.Type() != ErrorResponse {
+		return nil, false
+	}
+
+	var severity perror.Severity
+	var code perror.Code
+	var message string
+	var extra []perror.ExtraField
+
+	for {
+		typ, ok := in.Uint8()
+		if !ok {
+			return nil, false
+		}
+
+		if typ == 0 {
+			break
+		}
+
+		value, ok := in.String()
+		if !ok {
+			return nil, false
+		}
+
+		switch typ {
+		case 'S':
+			severity = perror.Severity(value)
+		case 'C':
+			code = perror.Code(value)
+		case 'M':
+			message = value
+		default:
+			extra = append(extra, perror.ExtraField{
+				Type:  perror.Extra(typ),
+				Value: value,
+			})
+		}
+	}
+
+	return perror.New(
+		severity,
+		code,
+		message,
+		extra...,
+	), true
+}
+
+func WriteErrorResponse(out zap.Builder, err perror.Error) {
+	out.Reset()
+	out.Type(ErrorResponse)
+
+	out.Uint8('S')
+	out.String(string(err.Severity()))
+
+	out.Uint8('C')
+	out.String(string(err.Code()))
+
+	out.Uint8('M')
+	out.String(err.Message())
+
+	for _, field := range err.Extra() {
+		out.Uint8(uint8(field.Type))
+		out.String(field.Value)
+	}
+
+	out.Uint8(0)
+}
diff --git a/lib/zap3/packets/v3.0/errors.go b/lib/zap3/packets/v3.0/errors.go
new file mode 100644
index 0000000000000000000000000000000000000000..7fe488210c45ea31a7423b59c7de9da07c77515e
--- /dev/null
+++ b/lib/zap3/packets/v3.0/errors.go
@@ -0,0 +1,16 @@
+package packets
+
+import "pggat2/lib/perror"
+
+var (
+	ErrBadFormat = perror.New(
+		perror.FATAL,
+		perror.ProtocolViolation,
+		"Bad packet format",
+	)
+	ErrUnexpectedPacket = perror.New(
+		perror.FATAL,
+		perror.ProtocolViolation,
+		"unexpected packet",
+	)
+)
diff --git a/lib/zap3/packets/v3.0/execute.go b/lib/zap3/packets/v3.0/execute.go
new file mode 100644
index 0000000000000000000000000000000000000000..7c32249a94cea7809e89b8e7223e3cbeb9e2a479
--- /dev/null
+++ b/lib/zap3/packets/v3.0/execute.go
@@ -0,0 +1,28 @@
+package packets
+
+import (
+	"pggat2/lib/zap"
+)
+
+func ReadExecute(in zap.Inspector) (target string, maxRows int32, ok bool) {
+	in.Reset()
+	if in.Type() != Execute {
+		return
+	}
+	target, ok = in.String()
+	if !ok {
+		return
+	}
+	maxRows, ok = in.Int32()
+	if !ok {
+		return
+	}
+	return
+}
+
+func WriteExecute(out zap.Builder, target string, maxRows int32) {
+	out.Reset()
+	out.Type(Execute)
+	out.String(target)
+	out.Int32(maxRows)
+}
diff --git a/lib/zap3/packets/v3.0/negotiateprotocolversion.go b/lib/zap3/packets/v3.0/negotiateprotocolversion.go
new file mode 100644
index 0000000000000000000000000000000000000000..73595713bb14c2490ccbc3559bc5245f70ca37a6
--- /dev/null
+++ b/lib/zap3/packets/v3.0/negotiateprotocolversion.go
@@ -0,0 +1,42 @@
+package packets
+
+import (
+	"pggat2/lib/zap"
+)
+
+func ReadNegotiateProtocolVersion(in zap.Inspector) (minorProtocolVersion int32, unrecognizedOptions []string, ok bool) {
+	in.Reset()
+	if in.Type() != NegotiateProtocolVersion {
+		return
+	}
+	minorProtocolVersion, ok = in.Int32()
+	if !ok {
+		return
+	}
+	var numUnrecognizedOptions int32
+	numUnrecognizedOptions, ok = in.Int32()
+	if !ok {
+		return
+	}
+	unrecognizedOptions = make([]string, 0, numUnrecognizedOptions)
+	for i := 0; i < int(numUnrecognizedOptions); i++ {
+		var unrecognizedOption string
+		unrecognizedOption, ok = in.String()
+		if !ok {
+			return
+		}
+		unrecognizedOptions = append(unrecognizedOptions, unrecognizedOption)
+	}
+	ok = true
+	return
+}
+
+func WriteNegotiateProtocolVersion(out zap.Builder, minorProtocolVersion int32, unrecognizedOptions []string) {
+	out.Reset()
+	out.Type(NegotiateProtocolVersion)
+	out.Int32(minorProtocolVersion)
+	out.Int32(int32(len(unrecognizedOptions)))
+	for _, option := range unrecognizedOptions {
+		out.String(option)
+	}
+}
diff --git a/lib/zap3/packets/v3.0/parameterstatus.go b/lib/zap3/packets/v3.0/parameterstatus.go
new file mode 100644
index 0000000000000000000000000000000000000000..cff7246aa0c17a2a82ce6a401e12276285e246ef
--- /dev/null
+++ b/lib/zap3/packets/v3.0/parameterstatus.go
@@ -0,0 +1,26 @@
+package packets
+
+import "pggat2/lib/zap"
+
+func ReadParameterStatus(in zap.Inspector) (key, value string, ok bool) {
+	in.Reset()
+	if in.Type() != ParameterStatus {
+		return
+	}
+	key, ok = in.String()
+	if !ok {
+		return
+	}
+	value, ok = in.String()
+	if !ok {
+		return
+	}
+	return
+}
+
+func WriteParameterStatus(out zap.Builder, key, value string) {
+	out.Reset()
+	out.Type(ParameterStatus)
+	out.String(key)
+	out.String(value)
+}
diff --git a/lib/zap3/packets/v3.0/parse.go b/lib/zap3/packets/v3.0/parse.go
new file mode 100644
index 0000000000000000000000000000000000000000..3d7c3f31be570c76bd26482a20cc7305014ccfd3
--- /dev/null
+++ b/lib/zap3/packets/v3.0/parse.go
@@ -0,0 +1,46 @@
+package packets
+
+import (
+	"pggat2/lib/zap"
+)
+
+func ReadParse(in zap.Inspector) (destination string, query string, parameterDataTypes []int32, ok bool) {
+	in.Reset()
+	if in.Type() != Parse {
+		return
+	}
+	destination, ok = in.String()
+	if !ok {
+		return
+	}
+	query, ok = in.String()
+	if !ok {
+		return
+	}
+	var parameterDataTypesCount int16
+	parameterDataTypesCount, ok = in.Int16()
+	if !ok {
+		return
+	}
+	parameterDataTypes = make([]int32, 0, int(parameterDataTypesCount))
+	for i := 0; i < int(parameterDataTypesCount); i++ {
+		var parameterDataType int32
+		parameterDataType, ok = in.Int32()
+		if !ok {
+			return
+		}
+		parameterDataTypes = append(parameterDataTypes, parameterDataType)
+	}
+	return
+}
+
+func WriteParse(out zap.Builder, destination string, query string, parameterDataTypes []int32) {
+	out.Reset()
+	out.Type(Parse)
+	out.String(destination)
+	out.String(query)
+	out.Int16(int16(len(parameterDataTypes)))
+	for _, v := range parameterDataTypes {
+		out.Int32(v)
+	}
+}
diff --git a/lib/zap3/packets/v3.0/passwordmessage.go b/lib/zap3/packets/v3.0/passwordmessage.go
new file mode 100644
index 0000000000000000000000000000000000000000..f777e94c95118f457b1e70ec426f00e8673ba746
--- /dev/null
+++ b/lib/zap3/packets/v3.0/passwordmessage.go
@@ -0,0 +1,23 @@
+package packets
+
+import (
+	"pggat2/lib/zap"
+)
+
+func ReadPasswordMessage(in zap.Inspector) (string, bool) {
+	in.Reset()
+	if in.Type() != AuthenticationResponse {
+		return "", false
+	}
+	password, ok := in.String()
+	if !ok {
+		return "", false
+	}
+	return password, true
+}
+
+func WritePasswordMessage(out zap.Builder, password string) {
+	out.Reset()
+	out.Type(AuthenticationResponse)
+	out.String(password)
+}
diff --git a/lib/zap3/packets/v3.0/readyforquery.go b/lib/zap3/packets/v3.0/readyforquery.go
new file mode 100644
index 0000000000000000000000000000000000000000..f023ceb06cc5de23a20eee25300573e0a6d299b5
--- /dev/null
+++ b/lib/zap3/packets/v3.0/readyforquery.go
@@ -0,0 +1,23 @@
+package packets
+
+import (
+	"pggat2/lib/zap"
+)
+
+func ReadReadyForQuery(in zap.Inspector) (byte, bool) {
+	in.Reset()
+	if in.Type() != ReadyForQuery {
+		return 0, false
+	}
+	state, ok := in.Uint8()
+	if !ok {
+		return 0, false
+	}
+	return state, true
+}
+
+func WriteReadyForQuery(out zap.Builder, state uint8) {
+	out.Reset()
+	out.Type(ReadyForQuery)
+	out.Uint8(state)
+}
diff --git a/lib/zap3/packets/v3.0/saslinitialresponse.go b/lib/zap3/packets/v3.0/saslinitialresponse.go
new file mode 100644
index 0000000000000000000000000000000000000000..6cbcd94b694e7fcc5a74c19c931b8be81629a823
--- /dev/null
+++ b/lib/zap3/packets/v3.0/saslinitialresponse.go
@@ -0,0 +1,41 @@
+package packets
+
+import (
+	"pggat2/lib/zap"
+)
+
+func ReadSASLInitialResponse(in zap.Inspector) (mechanism string, initialResponse []byte, ok bool) {
+	in.Reset()
+	if in.Type() != AuthenticationResponse {
+		return
+	}
+
+	mechanism, ok = in.String()
+	if !ok {
+		return
+	}
+
+	var initialResponseSize int32
+	initialResponseSize, ok = in.Int32()
+	if !ok {
+		return
+	}
+	if initialResponseSize == -1 {
+		return
+	}
+
+	initialResponse, ok = in.UnsafeBytes(int(initialResponseSize))
+	return
+}
+
+func WriteSASLInitialResponse(out zap.Builder, mechanism string, initialResponse []byte) {
+	out.Reset()
+	out.Type(AuthenticationResponse)
+	out.String(mechanism)
+	if initialResponse == nil {
+		out.Int32(-1)
+	} else {
+		out.Int32(int32(len(initialResponse)))
+		out.Bytes(initialResponse)
+	}
+}
diff --git a/lib/zap3/packets/v3.0/types.go b/lib/zap3/packets/v3.0/types.go
new file mode 100644
index 0000000000000000000000000000000000000000..68b3740658189194077803a62ce5e3d9e9d545a5
--- /dev/null
+++ b/lib/zap3/packets/v3.0/types.go
@@ -0,0 +1,43 @@
+package packets
+
+import "pggat2/lib/zap"
+
+const (
+	None                     zap.Type = 0
+	Authentication           zap.Type = 'R'
+	BackendKeyData           zap.Type = 'K'
+	Bind                     zap.Type = 'B'
+	BindComplete             zap.Type = '2'
+	Close                    zap.Type = 'C'
+	CloseComplete            zap.Type = '3'
+	CommandComplete          zap.Type = 'C'
+	CopyData                 zap.Type = 'd'
+	CopyDone                 zap.Type = 'c'
+	CopyFail                 zap.Type = 'f'
+	CopyInResponse           zap.Type = 'G'
+	CopyOutResponse          zap.Type = 'H'
+	CopyBothResponse         zap.Type = 'W'
+	DataRow                  zap.Type = 'D'
+	Describe                 zap.Type = 'D'
+	EmptyQueryResponse       zap.Type = 'I'
+	ErrorResponse            zap.Type = 'E'
+	Execute                  zap.Type = 'E'
+	Flush                    zap.Type = 'H'
+	FunctionCall             zap.Type = 'F'
+	FunctionCallResponse     zap.Type = 'V'
+	AuthenticationResponse   zap.Type = 'p'
+	NegotiateProtocolVersion zap.Type = 'v'
+	NoData                   zap.Type = 'n'
+	NoticeResponse           zap.Type = 'N'
+	NotificationResponse     zap.Type = 'A'
+	ParameterDescription     zap.Type = 't'
+	ParameterStatus          zap.Type = 'S'
+	Parse                    zap.Type = 'P'
+	ParseComplete            zap.Type = '1'
+	PortalSuspended          zap.Type = 's'
+	Query                    zap.Type = 'Q'
+	ReadyForQuery            zap.Type = 'Z'
+	RowDescription           zap.Type = 'T'
+	Sync                     zap.Type = 'S'
+	Terminate                zap.Type = 'X'
+)
diff --git a/lib/zap3/reader.go b/lib/zap3/reader.go
new file mode 100644
index 0000000000000000000000000000000000000000..3ea1005b737d6994c39eb48ca87368fe62a4df12
--- /dev/null
+++ b/lib/zap3/reader.go
@@ -0,0 +1,24 @@
+package zap3
+
+import "io"
+
+type Reader interface {
+	Read(*Packet) error
+	ReadUntyped(*UntypedPacket) error
+}
+
+type IOReader struct {
+	Reader io.Reader
+}
+
+func (T IOReader) Read(packet *Packet) error {
+	_, err := packet.ReadFrom(T.Reader)
+	return err
+}
+
+func (T IOReader) ReadUntyped(packet *UntypedPacket) error {
+	_, err := packet.ReadFrom(T.Reader)
+	return err
+}
+
+var _ Reader = IOReader{}
diff --git a/lib/zap3/type.go b/lib/zap3/type.go
new file mode 100644
index 0000000000000000000000000000000000000000..b1abf1fbf98917212e0fdf6f95ecb84c93d5e03a
--- /dev/null
+++ b/lib/zap3/type.go
@@ -0,0 +1,3 @@
+package zap3
+
+type Type int
diff --git a/lib/zap3/writer.go b/lib/zap3/writer.go
new file mode 100644
index 0000000000000000000000000000000000000000..40fc38bfab22a391c1cecc0390e384ccf0b0b013
--- /dev/null
+++ b/lib/zap3/writer.go
@@ -0,0 +1,30 @@
+package zap3
+
+import "io"
+
+type Writer interface {
+	Write(*Packet) error
+	WriteUntyped(*UntypedPacket) error
+	WriteV(*Packets) error
+}
+
+type IOWriter struct {
+	Writer io.Writer
+}
+
+func (T IOWriter) Write(packet *Packet) error {
+	_, err := packet.WriteTo(T.Writer)
+	return err
+}
+
+func (T IOWriter) WriteUntyped(packet *UntypedPacket) error {
+	_, err := packet.WriteTo(T.Writer)
+	return err
+}
+
+func (T IOWriter) WriteV(packets *Packets) error {
+	_, err := packets.WriteTo(T.Writer)
+	return err
+}
+
+var _ Writer = IOWriter{}