diff --git a/cmd/cgat/main.go b/cmd/cgat/main.go
index f0cdd8c9fdfae987b27a6ce0840bb84a293debcb..76671d6e7c6b5ad9ac536127b78becd8382b1043 100644
--- a/cmd/cgat/main.go
+++ b/cmd/cgat/main.go
@@ -16,7 +16,6 @@ import (
 	"pggat2/lib/rob"
 	"pggat2/lib/rob/schedulers/v1"
 	"pggat2/lib/zap"
-	"pggat2/lib/zap/zio"
 )
 
 type work struct {
@@ -45,7 +44,10 @@ func testServer(r rob.Scheduler) {
 	if err != nil {
 		panic(err)
 	}
-	rw := zio.MakeReadWriter(conn)
+	rw := zap.CombinedReadWriter{
+		Reader: zap.IOReader{Reader: conn},
+		Writer: zap.IOWriter{Writer: conn},
+	}
 	eqps := eqp.NewServer()
 	pss := ps.NewServer()
 	mw := interceptor.NewInterceptor(
@@ -104,7 +106,10 @@ func main() {
 		}
 		go func() {
 			source := r.NewSource()
-			client := zio.MakeReadWriter(conn)
+			client := zap.CombinedReadWriter{
+				Reader: zap.IOReader{Reader: conn},
+				Writer: zap.IOWriter{Writer: conn},
+			}
 			eqpc := eqp.NewClient()
 			defer eqpc.Done()
 			psc := ps.NewClient()
@@ -116,7 +121,10 @@ func main() {
 			)
 			frontends.Accept(mw, DefaultParameterStatus)
 			for {
-				// TODO(garet) sleep until more work is available
+				_, err := conn.Read([]byte{})
+				if err != nil {
+					break
+				}
 				source.Do(0, work{
 					rw:   mw,
 					eqpc: eqpc,
diff --git a/lib/bouncer/backends/v0/accept.go b/lib/bouncer/backends/v0/accept.go
index a6cd9e7683efd8d06d560a679f0389ea4a026905..ed6cf8aeca2157705fabc583e4a6b562ecca7e3a 100644
--- a/lib/bouncer/backends/v0/accept.go
+++ b/lib/bouncer/backends/v0/accept.go
@@ -31,18 +31,21 @@ func failpg(server zap.ReadWriter, err perror.Error) {
 }
 
 func authenticationSASLChallenge(server zap.ReadWriter, mechanism sasl.Client) (done bool, status Status) {
-	in, err := server.Read()
+	packet := zap.NewPacket()
+	defer packet.Done()
+	err := server.Read(packet)
 	if err != nil {
 		fail(server, err)
 		return false, Fail
 	}
+	read := packet.Read()
 
-	if in.Type() != packets.Authentication {
+	if read.ReadType() != packets.Authentication {
 		fail(server, ErrProtocolError)
 		return false, Fail
 	}
 
-	method, ok := in.Int32()
+	method, ok := read.ReadInt32()
 	if !ok {
 		fail(server, ErrBadPacket)
 		return false, Fail
@@ -51,16 +54,15 @@ func authenticationSASLChallenge(server zap.ReadWriter, mechanism sasl.Client) (
 	switch method {
 	case 11:
 		// challenge
-		response, err := mechanism.Continue(in.Remaining())
+		response, err := mechanism.Continue(read.ReadUnsafeRemaining())
 		if err != nil {
 			fail(server, err)
 			return false, Fail
 		}
 
-		out := server.Write()
-		packets.WriteAuthenticationResponse(out, response)
+		packets.WriteAuthenticationResponse(packet, response)
 
-		err = server.Send(out)
+		err = server.Write(packet)
 		if err != nil {
 			fail(server, err)
 			return false, Fail
@@ -68,7 +70,7 @@ func authenticationSASLChallenge(server zap.ReadWriter, mechanism sasl.Client) (
 		return false, Ok
 	case 12:
 		// finish
-		err = mechanism.Final(in.Remaining())
+		err = mechanism.Final(read.ReadUnsafeRemaining())
 		if err != nil {
 			fail(server, err)
 			return false, Fail
@@ -89,9 +91,10 @@ func authenticationSASL(server zap.ReadWriter, mechanisms []string, username, pa
 	}
 	initialResponse := mechanism.InitialResponse()
 
-	out := server.Write()
-	packets.WriteSASLInitialResponse(out, mechanism.Name(), initialResponse)
-	err = server.Send(out)
+	packet := zap.NewPacket()
+	defer packet.Done()
+	packets.WriteSASLInitialResponse(packet, mechanism.Name(), initialResponse)
+	err = server.Write(packet)
 	if err != nil {
 		fail(server, err)
 		return Fail
@@ -112,9 +115,10 @@ func authenticationSASL(server zap.ReadWriter, mechanisms []string, username, pa
 }
 
 func authenticationMD5(server zap.ReadWriter, salt [4]byte, username, password string) Status {
-	out := server.Write()
-	packets.WritePasswordMessage(out, md5.Encode(username, password, salt))
-	err := server.Send(out)
+	packet := zap.NewPacket()
+	defer packet.Done()
+	packets.WritePasswordMessage(packet, md5.Encode(username, password, salt))
+	err := server.Write(packet)
 	if err != nil {
 		fail(server, err)
 		return Fail
@@ -123,9 +127,10 @@ func authenticationMD5(server zap.ReadWriter, salt [4]byte, username, password s
 }
 
 func authenticationCleartext(server zap.ReadWriter, password string) Status {
-	out := server.Write()
-	packets.WritePasswordMessage(out, password)
-	err := server.Send(out)
+	packet := zap.NewPacket()
+	defer packet.Done()
+	packets.WritePasswordMessage(packet, password)
+	err := server.Write(packet)
 	if err != nil {
 		fail(server, err)
 		return Fail
@@ -134,15 +139,18 @@ func authenticationCleartext(server zap.ReadWriter, password string) Status {
 }
 
 func startup0(server zap.ReadWriter, username, password string) (done bool, status Status) {
-	in, err := server.Read()
+	packet := zap.NewPacket()
+	defer packet.Done()
+	err := server.Read(packet)
 	if err != nil {
 		fail(server, err)
 		return false, Fail
 	}
+	read := packet.Read()
 
-	switch in.Type() {
+	switch read.ReadType() {
 	case packets.ErrorResponse:
-		perr, ok := packets.ReadErrorResponse(in)
+		perr, ok := packets.ReadErrorResponse(&read)
 		if !ok {
 			fail(server, ErrBadPacket)
 			return false, Fail
@@ -150,7 +158,8 @@ func startup0(server zap.ReadWriter, username, password string) (done bool, stat
 		failpg(server, perr)
 		return false, Fail
 	case packets.Authentication:
-		method, ok := in.Int32()
+		read2 := read
+		method, ok := read2.ReadInt32()
 		if !ok {
 			fail(server, ErrBadPacket)
 			return false, Fail
@@ -166,7 +175,7 @@ func startup0(server zap.ReadWriter, username, password string) (done bool, stat
 		case 3:
 			return false, authenticationCleartext(server, password)
 		case 5:
-			salt, ok := packets.ReadAuthenticationMD5(in)
+			salt, ok := packets.ReadAuthenticationMD5(&read)
 			if !ok {
 				fail(server, ErrBadPacket)
 				return false, Fail
@@ -183,7 +192,7 @@ func startup0(server zap.ReadWriter, username, password string) (done bool, stat
 			return false, Fail
 		case 10:
 			// read list of mechanisms
-			mechanisms, ok := packets.ReadAuthenticationSASL(in)
+			mechanisms, ok := packets.ReadAuthenticationSASL(&read)
 			if !ok {
 				fail(server, ErrBadPacket)
 				return false, Fail
@@ -205,16 +214,19 @@ func startup0(server zap.ReadWriter, username, password string) (done bool, stat
 }
 
 func startup1(server zap.ReadWriter) (done bool, status Status) {
-	in, err := server.Read()
+	packet := zap.NewPacket()
+	defer packet.Done()
+	err := server.Read(packet)
 	if err != nil {
 		fail(server, err)
 		return false, Fail
 	}
+	read := packet.Read()
 
-	switch in.Type() {
+	switch read.ReadType() {
 	case packets.BackendKeyData:
 		var cancellationKey [8]byte
-		ok := in.Bytes(cancellationKey[:])
+		ok := read.ReadBytes(cancellationKey[:])
 		if !ok {
 			fail(server, ErrBadPacket)
 			return false, Fail
@@ -226,7 +238,7 @@ func startup1(server zap.ReadWriter) (done bool, status Status) {
 	case packets.ReadyForQuery:
 		return true, Ok
 	case packets.ErrorResponse:
-		perr, ok := packets.ReadErrorResponse(in)
+		perr, ok := packets.ReadErrorResponse(&read)
 		if !ok {
 			fail(server, ErrBadPacket)
 			return false, Fail
@@ -247,16 +259,16 @@ func Accept(server zap.ReadWriter, username, password, database string) {
 		database = username
 	}
 	// we can re-use the memory for this pkt most of the way down because we don't pass this anywhere
-	out := server.Write()
-	out.Int16(3)
-	out.Int16(0)
-	out.String("user")
-	out.String(username)
-	out.String("database")
-	out.String(database)
-	out.String("")
+	packet := zap.NewUntypedPacket()
+	packet.WriteInt16(3)
+	packet.WriteInt16(0)
+	packet.WriteString("user")
+	packet.WriteString(username)
+	packet.WriteString("database")
+	packet.WriteString(database)
+	packet.WriteString("")
 
-	err := server.Send(out)
+	err := server.WriteUntyped(packet)
 	if err != nil {
 		fail(server, err)
 		return
diff --git a/lib/bouncer/bouncers/v2/bctx/context.go b/lib/bouncer/bouncers/v2/bctx/context.go
index 63d3e2439ebe69b39f312a809a6d88cceb0a299e..94bfecad10222145baf2a167ab9904c50130a8f2 100644
--- a/lib/bouncer/bouncers/v2/bctx/context.go
+++ b/lib/bouncer/bouncers/v2/bctx/context.go
@@ -26,50 +26,34 @@ func MakeContext(client, server zap.ReadWriter) Context {
 	}
 }
 
-func (T *Context) ClientRead() (zap.In, berr.Error) {
-	in, err := T.client.Read()
+func (T *Context) ClientRead(packet *zap.Packet) berr.Error {
+	err := T.client.Read(packet)
 	if err != nil {
-		return zap.In{}, berr.MakeClient(err)
+		return berr.MakeClient(err)
 	}
-	return in, nil
+	return nil
 }
 
-func (T *Context) ServerRead() (zap.In, berr.Error) {
-	in, err := T.server.Read()
+func (T *Context) ServerRead(packet *zap.Packet) berr.Error {
+	err := T.server.Read(packet)
 	if err != nil {
-		return zap.In{}, berr.MakeServer(err)
+		return berr.MakeServer(err)
 	}
-	return in, nil
+	return nil
 }
 
-func (T *Context) ClientSend(out zap.Out) berr.Error {
-	err := T.client.Send(out)
+func (T *Context) ClientWrite(packet *zap.Packet) berr.Error {
+	err := T.client.Write(packet)
 	if err != nil {
 		return berr.MakeClient(err)
 	}
 	return nil
 }
 
-func (T *Context) ServerSend(out zap.Out) berr.Error {
-	err := T.server.Send(out)
+func (T *Context) ServerWrite(packet *zap.Packet) berr.Error {
+	err := T.server.Write(packet)
 	if err != nil {
 		return berr.MakeServer(err)
 	}
 	return nil
 }
-
-func (T *Context) ClientProxy(in zap.In) berr.Error {
-	return T.ClientSend(zap.InToOut(in))
-}
-
-func (T *Context) ServerProxy(in zap.In) berr.Error {
-	return T.ServerSend(zap.InToOut(in))
-}
-
-func (T *Context) ClientWrite() zap.Out {
-	return T.client.Write()
-}
-
-func (T *Context) ServerWrite() zap.Out {
-	return T.server.Write()
-}
diff --git a/lib/bouncer/bouncers/v2/bouncer.go b/lib/bouncer/bouncers/v2/bouncer.go
index 1ab7f3e5df4b342c7fb24b4fcb4f2a944db5a6d0..6524238ea31368e26f5ed8f1f52a9e15957b83e0 100644
--- a/lib/bouncer/bouncers/v2/bouncer.go
+++ b/lib/bouncer/bouncers/v2/bouncer.go
@@ -9,39 +9,43 @@ import (
 	packets "pggat2/lib/zap/packets/v3.0"
 )
 
-func serverRead(ctx *bctx.Context) (zap.In, berr.Error) {
+func serverRead(ctx *bctx.Context, packet *zap.Packet) berr.Error {
 	for {
-		in, err := ctx.ServerRead()
+		err := ctx.ServerRead(packet)
 		if err != nil {
-			return zap.In{}, err
+			packet.Done()
+			return err
 		}
-		switch in.Type() {
+
+		switch packet.ReadType() {
 		case packets.NoticeResponse,
 			packets.ParameterStatus,
 			packets.NotificationResponse:
-			if err = ctx.ClientProxy(in); err != nil {
-				return zap.In{}, err
+			if err = ctx.ClientWrite(packet); err != nil {
+				return err
 			}
 		default:
-			return in, nil
+			return nil
 		}
 	}
 }
 
 func copyIn(ctx *bctx.Context) berr.Error {
+	packet := zap.NewPacket()
+	defer packet.Done()
 	for {
-		in, err := ctx.ClientRead()
+		err := ctx.ClientRead(packet)
 		if err != nil {
 			return err
 		}
 
-		switch in.Type() {
+		switch packet.ReadType() {
 		case packets.CopyData:
-			if err = ctx.ServerProxy(in); err != nil {
+			if err = ctx.ServerWrite(packet); err != nil {
 				return err
 			}
 		case packets.CopyDone, packets.CopyFail:
-			if err = ctx.ServerProxy(in); err != nil {
+			if err = ctx.ServerWrite(packet); err != nil {
 				return err
 			}
 			ctx.CopyIn = false
@@ -53,20 +57,22 @@ func copyIn(ctx *bctx.Context) berr.Error {
 }
 
 func copyOut(ctx *bctx.Context) berr.Error {
+	packet := zap.NewPacket()
+	defer packet.Done()
 	for {
-		in, err := serverRead(ctx)
+		err := serverRead(ctx, packet)
 		if err != nil {
 			return err
 		}
 
-		switch in.Type() {
+		switch packet.ReadType() {
 		case packets.CopyData:
-			if err = ctx.ClientProxy(in); err != nil {
+			if err = ctx.ClientWrite(packet); err != nil {
 				return err
 			}
 		case packets.CopyDone, packets.ErrorResponse:
 			ctx.CopyOut = false
-			return ctx.ClientProxy(in)
+			return ctx.ClientWrite(packet)
 		default:
 			return berr.ServerUnexpectedPacket
 		}
@@ -74,24 +80,28 @@ func copyOut(ctx *bctx.Context) berr.Error {
 }
 
 func query(ctx *bctx.Context) berr.Error {
+	packet := zap.NewPacket()
+	defer packet.Done()
 	for {
-		in, err := serverRead(ctx)
+		err := serverRead(ctx, packet)
 		if err != nil {
 			return err
 		}
 
-		switch in.Type() {
+		read := packet.Read()
+
+		switch read.ReadType() {
 		case packets.CommandComplete,
 			packets.RowDescription,
 			packets.DataRow,
 			packets.EmptyQueryResponse,
 			packets.ErrorResponse:
-			if err = ctx.ClientProxy(in); err != nil {
+			if err = ctx.ClientWrite(packet); err != nil {
 				return err
 			}
 		case packets.CopyInResponse:
 			ctx.CopyIn = true
-			if err = ctx.ClientProxy(in); err != nil {
+			if err = ctx.ClientWrite(packet); err != nil {
 				return err
 			}
 			if err = copyIn(ctx); err != nil {
@@ -99,7 +109,7 @@ func query(ctx *bctx.Context) berr.Error {
 			}
 		case packets.CopyOutResponse:
 			ctx.CopyOut = true
-			if err = ctx.ClientProxy(in); err != nil {
+			if err = ctx.ClientWrite(packet); err != nil {
 				return err
 			}
 			if err = copyOut(ctx); err != nil {
@@ -108,10 +118,10 @@ func query(ctx *bctx.Context) berr.Error {
 		case packets.ReadyForQuery:
 			ctx.Query = false
 			var ok bool
-			if ctx.TxState, ok = packets.ReadReadyForQuery(in); !ok {
+			if ctx.TxState, ok = packets.ReadReadyForQuery(&read); !ok {
 				return berr.ServerBadPacket
 			}
-			return ctx.ClientProxy(in)
+			return ctx.ClientWrite(packet)
 		default:
 			return berr.ServerUnexpectedPacket
 		}
@@ -119,36 +129,44 @@ func query(ctx *bctx.Context) berr.Error {
 }
 
 func functionCall(ctx *bctx.Context) berr.Error {
+	packet := zap.NewPacket()
+	defer packet.Done()
 	for {
-		in, err := serverRead(ctx)
+		err := serverRead(ctx, packet)
 		if err != nil {
 			return err
 		}
 
-		switch in.Type() {
+		read := packet.Read()
+
+		switch read.ReadType() {
 		case packets.ErrorResponse, packets.FunctionCallResponse:
-			if err = ctx.ClientProxy(in); err != nil {
+			if err = ctx.ClientWrite(packet); err != nil {
 				return err
 			}
 		case packets.ReadyForQuery:
 			ctx.FunctionCall = false
 			var ok bool
-			if ctx.TxState, ok = packets.ReadReadyForQuery(in); !ok {
+			if ctx.TxState, ok = packets.ReadReadyForQuery(&read); !ok {
 				return berr.ServerBadPacket
 			}
-			return ctx.ClientProxy(in)
+			return ctx.ClientWrite(packet)
 		}
 	}
 }
 
 func sync(ctx *bctx.Context) berr.Error {
+	packet := zap.NewPacket()
+	defer packet.Done()
 	for {
-		in, err := serverRead(ctx)
+		err := serverRead(ctx, packet)
 		if err != nil {
 			return err
 		}
 
-		switch in.Type() {
+		read := packet.Read()
+
+		switch read.ReadType() {
 		case packets.ParseComplete,
 			packets.BindComplete,
 			packets.ErrorResponse,
@@ -160,13 +178,13 @@ func sync(ctx *bctx.Context) berr.Error {
 			packets.DataRow,
 			packets.EmptyQueryResponse,
 			packets.PortalSuspended:
-			err = ctx.ClientProxy(in)
+			err = ctx.ClientWrite(packet)
 			if err != nil {
 				return err
 			}
 		case packets.CopyInResponse:
 			ctx.CopyIn = true
-			if err = ctx.ClientProxy(in); err != nil {
+			if err = ctx.ClientWrite(packet); err != nil {
 				return err
 			}
 			if err = copyIn(ctx); err != nil {
@@ -174,7 +192,7 @@ func sync(ctx *bctx.Context) berr.Error {
 			}
 		case packets.CopyOutResponse:
 			ctx.CopyOut = true
-			if err = ctx.ClientProxy(in); err != nil {
+			if err = ctx.ClientWrite(packet); err != nil {
 				return err
 			}
 			if err = copyOut(ctx); err != nil {
@@ -184,10 +202,10 @@ func sync(ctx *bctx.Context) berr.Error {
 			ctx.Sync = false
 			ctx.EQP = false
 			var ok bool
-			if ctx.TxState, ok = packets.ReadReadyForQuery(in); !ok {
+			if ctx.TxState, ok = packets.ReadReadyForQuery(&read); !ok {
 				return berr.ServerBadPacket
 			}
-			return ctx.ClientProxy(in)
+			return ctx.ClientWrite(packet)
 		default:
 			return berr.ServerUnexpectedPacket
 		}
@@ -195,21 +213,23 @@ func sync(ctx *bctx.Context) berr.Error {
 }
 
 func eqp(ctx *bctx.Context) berr.Error {
+	packet := zap.NewPacket()
+	defer packet.Done()
 	for {
-		in, err := ctx.ClientRead()
+		err := ctx.ClientRead(packet)
 		if err != nil {
 			return err
 		}
 
-		switch in.Type() {
+		switch packet.ReadType() {
 		case packets.Sync:
-			if err = ctx.ServerProxy(in); err != nil {
+			if err = ctx.ServerWrite(packet); err != nil {
 				return err
 			}
 			ctx.Sync = true
 			return sync(ctx)
 		case packets.Parse, packets.Bind, packets.Close, packets.Describe, packets.Execute, packets.Flush:
-			if err = ctx.ServerProxy(in); err != nil {
+			if err = ctx.ServerWrite(packet); err != nil {
 				return err
 			}
 		default:
@@ -219,15 +239,17 @@ func eqp(ctx *bctx.Context) berr.Error {
 }
 
 func transaction(ctx *bctx.Context) berr.Error {
+	packet := zap.NewPacket()
+	defer packet.Done()
 	for {
-		in, err := ctx.ClientRead()
+		err := ctx.ClientRead(packet)
 		if err != nil {
 			return err
 		}
 
-		switch in.Type() {
+		switch packet.ReadType() {
 		case packets.Query:
-			if err = ctx.ServerProxy(in); err != nil {
+			if err = ctx.ServerWrite(packet); err != nil {
 				return err
 			}
 			ctx.Query = true
@@ -235,7 +257,7 @@ func transaction(ctx *bctx.Context) berr.Error {
 				return err
 			}
 		case packets.FunctionCall:
-			if err = ctx.ServerProxy(in); err != nil {
+			if err = ctx.ServerWrite(packet); err != nil {
 				return err
 			}
 			ctx.FunctionCall = true
@@ -244,13 +266,12 @@ func transaction(ctx *bctx.Context) berr.Error {
 			}
 		case packets.Sync:
 			// phony sync call, we can just reply with a fake ReadyForQuery(TxState)
-			out := zap.InToOut(in)
-			packets.WriteReadyForQuery(out, ctx.TxState)
-			if err = ctx.ClientSend(out); err != nil {
+			packets.WriteReadyForQuery(packet, ctx.TxState)
+			if err = ctx.ClientWrite(packet); err != nil {
 				return err
 			}
 		case packets.Parse, packets.Bind, packets.Close, packets.Describe, packets.Execute, packets.Flush:
-			if err = ctx.ServerProxy(in); err != nil {
+			if err = ctx.ServerWrite(packet); err != nil {
 				return err
 			}
 			ctx.EQP = true
@@ -269,13 +290,13 @@ func transaction(ctx *bctx.Context) berr.Error {
 
 func clientError(ctx *bctx.Context, err error) {
 	// send fatal error to client
-	out := ctx.ClientWrite()
-	packets.WriteErrorResponse(out, perror.New(
+	packet := zap.NewPacket()
+	packets.WriteErrorResponse(packet, perror.New(
 		perror.FATAL,
 		perror.ProtocolViolation,
 		err.Error(),
 	))
-	_ = ctx.ClientSend(out)
+	_ = ctx.ClientWrite(packet)
 }
 
 func serverError(ctx *bctx.Context, err error) {
diff --git a/lib/bouncer/bouncers/v2/rserver/recoverer.go b/lib/bouncer/bouncers/v2/rserver/recoverer.go
index dc5ab09fac432c7029b2818aa7718a27d0184f1b..8eedc7de3d1213a9b54b3e06eac923c5c7a10827 100644
--- a/lib/bouncer/bouncers/v2/rserver/recoverer.go
+++ b/lib/bouncer/bouncers/v2/rserver/recoverer.go
@@ -7,29 +7,31 @@ import (
 	packets "pggat2/lib/zap/packets/v3.0"
 )
 
-func serverRead(ctx *bctx.Context) (zap.In, error) {
+func serverRead(ctx *bctx.Context, packet *zap.Packet) error {
 	for {
-		in, err := ctx.ServerRead()
+		err := ctx.ServerRead(packet)
 		if err != nil {
-			return zap.In{}, err
+			return err
 		}
-		switch in.Type() {
+
+		switch packet.ReadType() {
 		case packets.NoticeResponse,
 			packets.ParameterStatus,
 			packets.NotificationResponse:
 			continue
 		default:
-			return in, nil
+			return nil
 		}
 	}
 }
 
 func copyIn(ctx *bctx.Context) error {
 	// send copy fail
-	out := ctx.ServerWrite()
-	out.Type(packets.CopyFail)
-	out.String("client failed")
-	if err := ctx.ServerSend(out); err != nil {
+	packet := zap.NewPacket()
+	defer packet.Done()
+	packet.WriteType(packets.CopyFail)
+	packet.WriteString("client failed")
+	if err := ctx.ServerWrite(packet); err != nil {
 		return err
 	}
 	ctx.CopyIn = false
@@ -37,13 +39,15 @@ func copyIn(ctx *bctx.Context) error {
 }
 
 func copyOut(ctx *bctx.Context) error {
+	packet := zap.NewPacket()
+	defer packet.Done()
 	for {
-		in, err := serverRead(ctx)
+		err := serverRead(ctx, packet)
 		if err != nil {
 			return err
 		}
 
-		switch in.Type() {
+		switch packet.ReadType() {
 		case packets.CopyData:
 			continue
 		case packets.CopyDone, packets.ErrorResponse:
@@ -56,13 +60,17 @@ func copyOut(ctx *bctx.Context) error {
 }
 
 func query(ctx *bctx.Context) error {
+	packet := zap.NewPacket()
+	defer packet.Done()
 	for {
-		in, err := serverRead(ctx)
+		err := serverRead(ctx, packet)
 		if err != nil {
 			return err
 		}
 
-		switch in.Type() {
+		read := packet.Read()
+
+		switch read.ReadType() {
 		case packets.CommandComplete,
 			packets.RowDescription,
 			packets.DataRow,
@@ -82,7 +90,7 @@ func query(ctx *bctx.Context) error {
 		case packets.ReadyForQuery:
 			ctx.Query = false
 			var ok bool
-			if ctx.TxState, ok = packets.ReadReadyForQuery(in); !ok {
+			if ctx.TxState, ok = packets.ReadReadyForQuery(&read); !ok {
 				return berr.ServerBadPacket
 			}
 			return nil
@@ -93,19 +101,23 @@ func query(ctx *bctx.Context) error {
 }
 
 func functionCall(ctx *bctx.Context) error {
+	packet := zap.NewPacket()
+	defer packet.Done()
 	for {
-		in, err := serverRead(ctx)
+		err := serverRead(ctx, packet)
 		if err != nil {
 			return err
 		}
 
-		switch in.Type() {
+		read := packet.Read()
+
+		switch read.ReadType() {
 		case packets.ErrorResponse, packets.FunctionCallResponse:
 			continue
 		case packets.ReadyForQuery:
 			ctx.FunctionCall = false
 			var ok bool
-			if ctx.TxState, ok = packets.ReadReadyForQuery(in); !ok {
+			if ctx.TxState, ok = packets.ReadReadyForQuery(&read); !ok {
 				return berr.ServerBadPacket
 			}
 			return nil
@@ -116,13 +128,17 @@ func functionCall(ctx *bctx.Context) error {
 }
 
 func sync(ctx *bctx.Context) error {
+	packet := zap.NewPacket()
+	defer packet.Done()
 	for {
-		in, err := serverRead(ctx)
+		err := serverRead(ctx, packet)
 		if err != nil {
 			return err
 		}
 
-		switch in.Type() {
+		read := packet.Read()
+
+		switch read.ReadType() {
 		case packets.ParseComplete,
 			packets.BindComplete,
 			packets.ErrorResponse,
@@ -149,7 +165,7 @@ func sync(ctx *bctx.Context) error {
 			ctx.Sync = false
 			ctx.EQP = false
 			var ok bool
-			if ctx.TxState, ok = packets.ReadReadyForQuery(in); !ok {
+			if ctx.TxState, ok = packets.ReadReadyForQuery(&read); !ok {
 				return berr.ServerBadPacket
 			}
 			return nil
@@ -161,9 +177,10 @@ func sync(ctx *bctx.Context) error {
 
 func eqp(ctx *bctx.Context) error {
 	// send sync
-	out := ctx.ServerWrite()
-	out.Type(packets.Sync)
-	if err := ctx.ServerSend(out); err != nil {
+	packet := zap.NewPacket()
+	defer packet.Done()
+	packet.WriteType(packets.Sync)
+	if err := ctx.ServerWrite(packet); err != nil {
 		return err
 	}
 	ctx.Sync = true
@@ -174,10 +191,11 @@ func eqp(ctx *bctx.Context) error {
 
 func transaction(ctx *bctx.Context) error {
 	// write Query('ABORT;')
-	out := ctx.ServerWrite()
-	out.Type(packets.Query)
-	out.String("ABORT;")
-	if err := ctx.ServerSend(out); err != nil {
+	packet := zap.NewPacket()
+	defer packet.Done()
+	packet.WriteType(packets.Query)
+	packet.WriteString("ABORT;")
+	if err := ctx.ServerWrite(packet); err != nil {
 		return err
 	}
 	ctx.Query = true
diff --git a/lib/bouncer/frontends/v0/accept.go b/lib/bouncer/frontends/v0/accept.go
index f759d60590a6a35f34af1083ae9cbfcd4fbd429c..8fdd51b803c47f69dfa437de755cc22d204d43f7 100644
--- a/lib/bouncer/frontends/v0/accept.go
+++ b/lib/bouncer/frontends/v0/accept.go
@@ -18,24 +18,28 @@ const (
 )
 
 func fail(client zap.ReadWriter, err perror.Error) {
-	out := client.Write()
-	packets.WriteErrorResponse(out, err)
-	_ = client.Send(out)
+	packet := zap.NewPacket()
+	defer packet.Done()
+	packets.WriteErrorResponse(packet, err)
+	_ = client.Write(packet)
 }
 
 func startup0(client zap.ReadWriter) (done bool, status Status) {
-	in, err := client.ReadUntyped()
+	packet := zap.NewUntypedPacket()
+	defer packet.Done()
+	err := client.ReadUntyped(packet)
 	if err != nil {
 		fail(client, perror.Wrap(err))
 		return false, Fail
 	}
+	read := packet.Read()
 
-	majorVersion, ok := in.Uint16()
+	majorVersion, ok := read.ReadUint16()
 	if !ok {
 		fail(client, packets.ErrBadFormat)
 		return false, Fail
 	}
-	minorVersion, ok := in.Uint16()
+	minorVersion, ok := read.ReadUint16()
 	if !ok {
 		fail(client, packets.ErrBadFormat)
 		return false, Fail
@@ -92,7 +96,7 @@ func startup0(client zap.ReadWriter) (done bool, status Status) {
 	var database string
 
 	for {
-		key, ok := in.String()
+		key, ok := read.ReadString()
 		if !ok {
 			fail(client, packets.ErrBadFormat)
 			return false, Fail
@@ -101,7 +105,7 @@ func startup0(client zap.ReadWriter) (done bool, status Status) {
 			break
 		}
 
-		value, ok := in.String()
+		value, ok := read.ReadString()
 		if !ok {
 			fail(client, packets.ErrBadFormat)
 			return false, Fail
@@ -138,10 +142,11 @@ func startup0(client zap.ReadWriter) (done bool, status Status) {
 
 	if minorVersion != 0 || len(unsupportedOptions) > 0 {
 		// negotiate protocol
-		out := client.Write()
-		packets.WriteNegotiateProtocolVersion(out, 0, unsupportedOptions)
+		packet := zap.NewPacket()
+		defer packet.Done()
+		packets.WriteNegotiateProtocolVersion(packet, 0, unsupportedOptions)
 
-		err = client.Send(out)
+		err = client.Write(packet)
 		if err != nil {
 			fail(client, perror.Wrap(err))
 			return false, Fail
@@ -165,12 +170,15 @@ func startup0(client zap.ReadWriter) (done bool, status Status) {
 
 func authenticationSASLInitial(client zap.ReadWriter, username, password string) (server sasl.Server, resp []byte, done bool, status Status) {
 	// check which authentication method the client wants
-	in, err := client.Read()
+	packet := zap.NewPacket()
+	defer packet.Done()
+	err := client.Read(packet)
 	if err != nil {
 		fail(client, perror.Wrap(err))
 		return nil, nil, false, Fail
 	}
-	mechanism, initialResponse, ok := packets.ReadSASLInitialResponse(in)
+	read := packet.Read()
+	mechanism, initialResponse, ok := packets.ReadSASLInitialResponse(&read)
 	if !ok {
 		fail(client, packets.ErrBadFormat)
 		return nil, nil, false, Fail
@@ -191,12 +199,15 @@ func authenticationSASLInitial(client zap.ReadWriter, username, password string)
 }
 
 func authenticationSASLContinue(client zap.ReadWriter, tool sasl.Server) (resp []byte, done bool, status Status) {
-	in, err := client.Read()
+	packet := zap.NewPacket()
+	defer packet.Done()
+	err := client.Read(packet)
 	if err != nil {
 		fail(client, perror.Wrap(err))
 		return nil, false, Fail
 	}
-	clientResp, ok := packets.ReadAuthenticationResponse(in)
+	read := packet.Read()
+	clientResp, ok := packets.ReadAuthenticationResponse(&read)
 	if !ok {
 		fail(client, packets.ErrBadFormat)
 		return nil, false, Fail
@@ -211,9 +222,10 @@ func authenticationSASLContinue(client zap.ReadWriter, tool sasl.Server) (resp [
 }
 
 func authenticationSASL(client zap.ReadWriter, username, password string) Status {
-	out := client.Write()
-	packets.WriteAuthenticationSASL(out, sasl.Mechanisms)
-	err := client.Send(out)
+	packet := zap.NewPacket()
+	defer packet.Done()
+	packets.WriteAuthenticationSASL(packet, sasl.Mechanisms)
+	err := client.Write(packet)
 	if err != nil {
 		fail(client, perror.Wrap(err))
 		return Fail
@@ -226,18 +238,16 @@ func authenticationSASL(client zap.ReadWriter, username, password string) Status
 			return status
 		}
 		if done {
-			out = client.Write()
-			packets.WriteAuthenticationSASLFinal(out, resp)
-			err = client.Send(out)
+			packets.WriteAuthenticationSASLFinal(packet, resp)
+			err = client.Write(packet)
 			if err != nil {
 				fail(client, perror.Wrap(err))
 				return Fail
 			}
 			break
 		} else {
-			out = client.Write()
-			packets.WriteAuthenticationSASLContinue(out, resp)
-			err = client.Send(out)
+			packets.WriteAuthenticationSASLContinue(packet, resp)
+			err = client.Write(packet)
 			if err != nil {
 				fail(client, perror.Wrap(err))
 				return Fail
@@ -251,9 +261,10 @@ func authenticationSASL(client zap.ReadWriter, username, password string) Status
 }
 
 func updateParameter(client zap.ReadWriter, name, value string) Status {
-	out := client.Write()
-	packets.WriteParameterStatus(out, name, value)
-	err := client.Send(out)
+	packet := zap.NewPacket()
+	defer packet.Done()
+	packets.WriteParameterStatus(packet, name, value)
+	err := client.Write(packet)
 	if err != nil {
 		fail(client, perror.Wrap(err))
 		return Fail
@@ -278,9 +289,10 @@ func Accept(client zap.ReadWriter, initialParameterStatus map[string]string) {
 	}
 
 	// send auth Ok
-	out := client.Write()
-	packets.WriteAuthenticationOk(out)
-	err := client.Send(out)
+	packet := zap.NewPacket()
+	defer packet.Done()
+	packets.WriteAuthenticationOk(packet)
+	err := client.Write(packet)
 	if err != nil {
 		fail(client, perror.Wrap(err))
 		return
@@ -300,18 +312,16 @@ func Accept(client zap.ReadWriter, initialParameterStatus map[string]string) {
 		fail(client, perror.Wrap(err))
 		return
 	}
-	out = client.Write()
-	packets.WriteBackendKeyData(out, cancellationKey)
-	err = client.Send(out)
+	packets.WriteBackendKeyData(packet, cancellationKey)
+	err = client.Write(packet)
 	if err != nil {
 		fail(client, perror.Wrap(err))
 		return
 	}
 
 	// send ready for query
-	out = client.Write()
-	packets.WriteReadyForQuery(out, 'I')
-	err = client.Send(out)
+	packets.WriteReadyForQuery(packet, 'I')
+	err = client.Write(packet)
 	if err != nil {
 		fail(client, perror.Wrap(err))
 		return
diff --git a/lib/global/pools.go b/lib/global/pools.go
deleted file mode 100644
index 2f7f228d08c73164361df607d39aedec847601ce..0000000000000000000000000000000000000000
--- a/lib/global/pools.go
+++ /dev/null
@@ -1,25 +0,0 @@
-package global
-
-import (
-	"sync"
-
-	"pggat2/lib/util/pools"
-)
-
-// i really don't know how I feel about these global pools
-var (
-	bytesPool pools.Log2[byte]
-	bytesMu   sync.Mutex
-)
-
-func GetBytes(length int32) []byte {
-	bytesMu.Lock()
-	defer bytesMu.Unlock()
-	return bytesPool.Get(length)
-}
-
-func PutBytes(v []byte) {
-	bytesMu.Lock()
-	defer bytesMu.Unlock()
-	bytesPool.Put(v)
-}
diff --git a/lib/middleware/context.go b/lib/middleware/context.go
index 6df9341ed51526be3b63c7dfa4695894422b2039..54178bb883268db652cee670462c444f91869ee7 100644
--- a/lib/middleware/context.go
+++ b/lib/middleware/context.go
@@ -6,6 +6,8 @@ type Context interface {
 	// Cancel the current packet
 	Cancel()
 
-	BuildBefore(typed bool) zap.Builder
-	BuildAfter(typed bool) zap.Builder
+	// Write packet to underlying connection
+	Write(packet *zap.Packet) error
+	// WriteUntyped is the same as Write but with an UntypedPacket
+	WriteUntyped(packet *zap.UntypedPacket) error
 }
diff --git a/lib/middleware/interceptor/context.go b/lib/middleware/interceptor/context.go
index 4c975b95d0f6fbb8c80a53b4cae3ec2ff18255fb..0f2dcd73613f400c913bf737af356a8fcbb0bb2e 100644
--- a/lib/middleware/interceptor/context.go
+++ b/lib/middleware/interceptor/context.go
@@ -3,16 +3,21 @@ package interceptor
 import (
 	"pggat2/lib/middleware"
 	"pggat2/lib/util/decorator"
+	"pggat2/lib/zap"
 )
 
 type Context struct {
 	noCopy decorator.NoCopy
 
 	cancelled bool
+
+	rw zap.ReadWriter
 }
 
-func makeContext() Context {
-	return Context{}
+func makeContext(rw zap.ReadWriter) Context {
+	return Context{
+		rw: rw,
+	}
 }
 
 func (T *Context) reset() {
@@ -23,4 +28,12 @@ func (T *Context) Cancel() {
 	T.cancelled = true
 }
 
+func (T *Context) Write(packet *zap.Packet) error {
+	return T.rw.Write(packet)
+}
+
+func (T *Context) WriteUntyped(packet *zap.UntypedPacket) error {
+	return T.rw.WriteUntyped(packet)
+}
+
 var _ middleware.Context = (*Context)(nil)
diff --git a/lib/middleware/interceptor/interceptor.go b/lib/middleware/interceptor/interceptor.go
index 1183bd9c8f6756e4abd70e63ca1e0f14f73bff55..0fb5b56b1e6828cb9830d654eb5c21b41e09255a 100644
--- a/lib/middleware/interceptor/interceptor.go
+++ b/lib/middleware/interceptor/interceptor.go
@@ -1,8 +1,6 @@
 package interceptor
 
 import (
-	"time"
-
 	"pggat2/lib/middleware"
 	"pggat2/lib/zap"
 )
@@ -16,60 +14,98 @@ type Interceptor struct {
 func NewInterceptor(rw zap.ReadWriter, middlewares ...middleware.Middleware) *Interceptor {
 	return &Interceptor{
 		middlewares: middlewares,
-		context:     makeContext(),
+		context:     makeContext(rw),
+		rw:          rw,
 	}
 }
 
-func (T *Interceptor) ReadInto(buffer *zap.Buffer, typed bool) error {
-	pre := buffer.Count()
-
-	if err := T.rw.ReadInto(buffer, typed); err != nil {
-		return err
-	}
+func (T *Interceptor) ReadByte() (byte, error) {
+	return T.rw.ReadByte()
+}
 
-	post := buffer.Count()
+func (T *Interceptor) Read(packet *zap.Packet) error {
+outer:
+	for {
+		err := T.rw.Read(packet)
+		if err != nil {
+			return err
+		}
 
-	for i := pre; i < post; i++ {
 		for _, mw := range T.middlewares {
 			T.context.reset()
-			if err := mw.Read(&T.context, buffer.Inspect(i)); err != nil {
+			err := mw.Read(&T.context, packet)
+			if err != nil {
 				return err
 			}
-
 			if T.context.cancelled {
-				// TODO(garet) cancel packet
-				panic("TODO")
+				continue outer
 			}
 		}
-	}
 
-	return nil
+		return nil
+	}
 }
 
-func (T *Interceptor) SetReadDeadline(time time.Time) error {
-	return T.rw.SetReadDeadline(time)
-}
+func (T *Interceptor) ReadUntyped(packet *zap.UntypedPacket) error {
+outer:
+	for {
+		err := T.rw.ReadUntyped(packet)
+		if err != nil {
+			return err
+		}
 
-func (T *Interceptor) WriteFrom(buffer *zap.Buffer) error {
-	for i := 0; i < buffer.Count(); i++ {
 		for _, mw := range T.middlewares {
 			T.context.reset()
-			if err := mw.Write(&T.context, buffer.Inspect(i)); err != nil {
+			err := mw.ReadUntyped(&T.context, packet)
+			if err != nil {
 				return err
 			}
-
 			if T.context.cancelled {
-				// TODO(garet) cancel packet
-				panic("TODO")
+				continue outer
 			}
 		}
+
+		return nil
+	}
+}
+
+func (T *Interceptor) WriteByte(b byte) error {
+	return T.rw.WriteByte(b)
+}
+
+func (T *Interceptor) Write(packet *zap.Packet) error {
+	for _, mw := range T.middlewares {
+		T.context.reset()
+		err := mw.Write(&T.context, packet)
+		if err != nil {
+			return err
+		}
+		if T.context.cancelled {
+			return nil
+		}
+	}
+
+	return T.rw.Write(packet)
+}
+
+func (T *Interceptor) WriteUntyped(packet *zap.UntypedPacket) error {
+	for _, mw := range T.middlewares {
+		T.context.reset()
+		err := mw.WriteUntyped(&T.context, packet)
+		if err != nil {
+			return err
+		}
+		if T.context.cancelled {
+			return nil
+		}
 	}
 
-	return T.rw.WriteFrom(buffer)
+	return T.rw.WriteUntyped(packet)
 }
 
-func (T *Interceptor) SetWriteDeadline(time time.Time) error {
-	return T.rw.SetWriteDeadline(time)
+func (T *Interceptor) WriteV(packets *zap.Packets) error {
+	panic("implement me")
+	// TODO(garet)
 }
 
 var _ zap.ReadWriter = (*Interceptor)(nil)
diff --git a/lib/middleware/middleware.go b/lib/middleware/middleware.go
index c0623c9d04f191a33b0b2d48e3e9752538c75604..a4114a6fa375b74b2b20b13495c4d8a25c7c10bb 100644
--- a/lib/middleware/middleware.go
+++ b/lib/middleware/middleware.go
@@ -3,6 +3,8 @@ package middleware
 import "pggat2/lib/zap"
 
 type Middleware interface {
-	Write(ctx Context, packet zap.Inspector) error
-	Read(ctx Context, packet zap.Inspector) error
+	Read(ctx Context, packet *zap.Packet) error
+	ReadUntyped(ctx Context, packet *zap.UntypedPacket) error
+	Write(ctx Context, packet *zap.Packet) error
+	WriteUntyped(ctx Context, packet *zap.UntypedPacket) error
 }
diff --git a/lib/middleware/middlewares/eqp/client.go b/lib/middleware/middlewares/eqp/client.go
index 46569f5045f6fa17e319862422e81be129de36e6..0144293aa4a70f4689ba22906f4eb092a7ccca2f 100644
--- a/lib/middleware/middlewares/eqp/client.go
+++ b/lib/middleware/middlewares/eqp/client.go
@@ -11,6 +11,8 @@ import (
 type Client struct {
 	preparedStatements map[string]PreparedStatement
 	portals            map[string]Portal
+
+	middleware.Nil
 }
 
 func NewClient() *Client {
@@ -47,10 +49,11 @@ func (T *Client) Done() {
 	}
 }
 
-func (T *Client) Write(_ middleware.Context, in zap.Inspector) error {
-	switch in.Type() {
+func (T *Client) Write(_ middleware.Context, packet *zap.Packet) error {
+	read := packet.Read()
+	switch read.ReadType() {
 	case packets.ReadyForQuery:
-		state, ok := packets.ReadReadyForQuery(in)
+		state, ok := packets.ReadReadyForQuery(&read)
 		if !ok {
 			return errors.New("bad packet format")
 		}
@@ -67,8 +70,9 @@ func (T *Client) Write(_ middleware.Context, in zap.Inspector) error {
 	return nil
 }
 
-func (T *Client) Read(ctx middleware.Context, in zap.Inspector) error {
-	switch in.Type() {
+func (T *Client) Read(ctx middleware.Context, packet *zap.Packet) error {
+	read := packet.Read()
+	switch read.ReadType() {
 	case packets.Query:
 		// clobber unnamed portal and unnamed prepared statement
 		T.deletePreparedStatement("")
@@ -76,7 +80,7 @@ func (T *Client) Read(ctx middleware.Context, in zap.Inspector) error {
 	case packets.Parse:
 		ctx.Cancel()
 
-		destination, preparedStatement, ok := ReadParse(in)
+		destination, preparedStatement, ok := ReadParse(&read)
 		if !ok {
 			return errors.New("bad packet format")
 		}
@@ -84,17 +88,15 @@ func (T *Client) Read(ctx middleware.Context, in zap.Inspector) error {
 		T.preparedStatements[destination] = preparedStatement
 
 		// send parse complete
-		out := zap.InToOut(in)
-		out.Reset()
-		out.Type(packets.ParseComplete)
-		err := ctx.Send(out)
+		packet.WriteType(packets.ParseComplete)
+		err := ctx.Write(packet)
 		if err != nil {
 			return err
 		}
 	case packets.Bind:
 		ctx.Cancel()
 
-		destination, portal, ok := ReadBind(in)
+		destination, portal, ok := ReadBind(&read)
 		if !ok {
 			return errors.New("bad packet format")
 		}
@@ -102,17 +104,15 @@ func (T *Client) Read(ctx middleware.Context, in zap.Inspector) error {
 		T.portals[destination] = portal
 
 		// send bind complete
-		out := zap.InToOut(in)
-		out.Reset()
-		out.Type(packets.BindComplete)
-		err := ctx.Send(out)
+		packet.WriteType(packets.BindComplete)
+		err := ctx.Write(packet)
 		if err != nil {
 			return err
 		}
 	case packets.Close:
 		ctx.Cancel()
 
-		which, target, ok := packets.ReadClose(in)
+		which, target, ok := packets.ReadClose(&read)
 		if !ok {
 			return errors.New("bad packet format")
 		}
@@ -126,16 +126,14 @@ func (T *Client) Read(ctx middleware.Context, in zap.Inspector) error {
 		}
 
 		// send close complete
-		out := zap.InToOut(in)
-		out.Reset()
-		out.Type(packets.CloseComplete)
-		err := ctx.Send(out)
+		packet.WriteType(packets.CloseComplete)
+		err := ctx.Write(packet)
 		if err != nil {
 			return err
 		}
 	case packets.Describe:
 		// ensure target exists
-		which, _, ok := packets.ReadDescribe(in)
+		which, _, ok := packets.ReadDescribe(&read)
 		if !ok {
 			return errors.New("bad packet format")
 		}
@@ -146,7 +144,7 @@ func (T *Client) Read(ctx middleware.Context, in zap.Inspector) error {
 			return errors.New("unknown describe target")
 		}
 	case packets.Execute:
-		_, _, ok := packets.ReadExecute(in)
+		_, _, ok := packets.ReadExecute(&read)
 		if !ok {
 			return errors.New("bad packet format")
 		}
diff --git a/lib/middleware/middlewares/eqp/portal.go b/lib/middleware/middlewares/eqp/portal.go
index ec3b8696de7e2f1f7c44a15225bc3f7a7421d175..0ece97b993f3b9599d9a4bdc874bdfbe3398ae0b 100644
--- a/lib/middleware/middlewares/eqp/portal.go
+++ b/lib/middleware/middlewares/eqp/portal.go
@@ -3,38 +3,38 @@ package eqp
 import (
 	"hash/maphash"
 
-	"pggat2/lib/global"
 	"pggat2/lib/zap"
 	packets "pggat2/lib/zap/packets/v3.0"
 )
 
 type Portal struct {
 	source string
-	raw    []byte
+	packet *zap.Packet
 	hash   uint64
 }
 
-func ReadBind(in zap.Inspector) (destination string, portal Portal, ok bool) {
-	in.Reset()
-	if in.Type() != packets.Bind {
+func ReadBind(in *zap.ReadablePacket) (destination string, portal Portal, ok bool) {
+	if in.ReadType() != packets.Bind {
 		return
 	}
-	destination, ok = in.String()
+	in2 := *in
+	destination, ok = in2.ReadString()
 	if !ok {
 		return
 	}
-	portal.source, ok = in.String()
+	portal.source, ok = in2.ReadString()
 	if !ok {
 		return
 	}
-	full := in.Payload()
-	portal.hash = maphash.Bytes(seed, full)
-	portal.raw = global.GetBytes(int32(len(full)))
-	copy(portal.raw, full)
+
+	portal.packet = zap.NewPacket()
+	portal.packet.WriteType(packets.Bind)
+	portal.packet.WriteBytes(in.ReadUnsafeRemaining())
+	portal.hash = maphash.Bytes(seed, portal.packet.Payload())
 	return
 }
 
 func (T *Portal) Done() {
-	global.PutBytes(T.raw)
-	T.raw = nil
+	T.packet.Done()
+	T.packet = nil
 }
diff --git a/lib/middleware/middlewares/eqp/preparedStatement.go b/lib/middleware/middlewares/eqp/preparedStatement.go
index c6e9f9359fb165679d81b7df4e4fc8b336a531fe..96f341334e15a6eac0db341acf0424ada128cbdd 100644
--- a/lib/middleware/middlewares/eqp/preparedStatement.go
+++ b/lib/middleware/middlewares/eqp/preparedStatement.go
@@ -3,33 +3,33 @@ package eqp
 import (
 	"hash/maphash"
 
-	"pggat2/lib/global"
 	"pggat2/lib/zap"
 	packets "pggat2/lib/zap/packets/v3.0"
 )
 
 type PreparedStatement struct {
-	raw  []byte
-	hash uint64
+	packet *zap.Packet
+	hash   uint64
 }
 
-func ReadParse(in zap.Inspector) (destination string, preparedStatement PreparedStatement, ok bool) {
-	in.Reset()
-	if in.Type() != packets.Parse {
+func ReadParse(in *zap.ReadablePacket) (destination string, preparedStatement PreparedStatement, ok bool) {
+	if in.ReadType() != packets.Parse {
 		return
 	}
-	destination, ok = in.String()
+	in2 := *in
+	destination, ok = in2.ReadString()
 	if !ok {
 		return
 	}
-	full := in.Payload()
-	preparedStatement.hash = maphash.Bytes(seed, full)
-	preparedStatement.raw = global.GetBytes(int32(len(full)))
-	copy(preparedStatement.raw, full)
+
+	preparedStatement.packet = zap.NewPacket()
+	preparedStatement.packet.WriteType(packets.Parse)
+	preparedStatement.packet.WriteBytes(in.ReadUnsafeRemaining())
+	preparedStatement.hash = maphash.Bytes(seed, preparedStatement.packet.Payload())
 	return
 }
 
 func (T *PreparedStatement) Done() {
-	global.PutBytes(T.raw)
-	T.raw = nil
+	T.packet.Done()
+	T.packet = nil
 }
diff --git a/lib/middleware/middlewares/eqp/server.go b/lib/middleware/middlewares/eqp/server.go
index 4cad60714beaf6ec9d507bc04f4d8cbf450f0193..9b391ba56b3740a15e3c726827fec9cebed3bf1d 100644
--- a/lib/middleware/middlewares/eqp/server.go
+++ b/lib/middleware/middlewares/eqp/server.go
@@ -23,6 +23,8 @@ type Server struct {
 	pendingCloses             ring.Ring[Close]
 
 	peer *Client
+
+	middleware.Nil
 }
 
 func NewServer() *Server {
@@ -57,9 +59,10 @@ func (T *Server) closePreparedStatement(ctx middleware.Context, target string) e
 	}
 
 	// send close packet
-	out := T.buf.Write()
-	packets.WriteClose(out, 'S', target)
-	err := ctx.Send(out)
+	packet := zap.NewPacket()
+	defer packet.Done()
+	packets.WriteClose(packet, 'S', target)
+	err := ctx.Write(packet)
 	if err != nil {
 		return err
 	}
@@ -91,9 +94,10 @@ func (T *Server) closePortal(ctx middleware.Context, target string) error {
 	}
 
 	// send close packet
-	out := T.buf.Write()
-	packets.WriteClose(out, 'P', target)
-	err := ctx.Send(out)
+	packet := zap.NewPacket()
+	defer packet.Done()
+	packets.WriteClose(packet, 'P', target)
+	err := ctx.Write(packet)
 	if err != nil {
 		return err
 	}
@@ -119,9 +123,7 @@ func (T *Server) bindPreparedStatement(
 		return err
 	}
 
-	old := T.buf.Swap(preparedStatement.raw)
-	err = ctx.Send(T.buf.Out())
-	T.buf.Swap(old)
+	err = ctx.Write(preparedStatement.packet)
 	if err != nil {
 		return err
 	}
@@ -149,9 +151,7 @@ func (T *Server) bindPortal(
 		return err
 	}
 
-	old := T.buf.Swap(portal.raw)
-	err = ctx.Send(T.buf.Out())
-	T.buf.Swap(old)
+	err = ctx.Write(portal.packet)
 	if err != nil {
 		return err
 	}
@@ -212,8 +212,9 @@ func (T *Server) syncPortal(ctx middleware.Context, target string) error {
 	return T.bindPortal(ctx, target, expected)
 }
 
-func (T *Server) Write(ctx middleware.Context, in zap.Inspector) error {
-	switch in.Type() {
+func (T *Server) Write(ctx middleware.Context, packet *zap.Packet) error {
+	read := packet.Read()
+	switch read.ReadType() {
 	case packets.Query:
 		// clobber unnamed portal and unnamed prepared statement
 		T.deletePreparedStatement("")
@@ -223,7 +224,7 @@ func (T *Server) Write(ctx middleware.Context, in zap.Inspector) error {
 		panic("unreachable")
 	case packets.Describe:
 		// ensure target exists
-		which, target, ok := packets.ReadDescribe(in)
+		which, target, ok := packets.ReadDescribe(&read)
 		if !ok {
 			// should've been caught by eqp.Client
 			panic("unreachable")
@@ -245,7 +246,7 @@ func (T *Server) Write(ctx middleware.Context, in zap.Inspector) error {
 			panic("unknown describe target")
 		}
 	case packets.Execute:
-		target, _, ok := packets.ReadExecute(in)
+		target, _, ok := packets.ReadExecute(&read)
 		if !ok {
 			// should've been caught by eqp.Client
 			panic("unreachable")
@@ -260,8 +261,9 @@ func (T *Server) Write(ctx middleware.Context, in zap.Inspector) error {
 	return nil
 }
 
-func (T *Server) Read(ctx middleware.Context, in zap.Inspector) error {
-	switch in.Type() {
+func (T *Server) Read(ctx middleware.Context, packet *zap.Packet) error {
+	read := packet.Read()
+	switch read.ReadType() {
 	case packets.ParseComplete:
 		ctx.Cancel()
 
@@ -275,7 +277,7 @@ func (T *Server) Read(ctx middleware.Context, in zap.Inspector) error {
 
 		T.pendingCloses.PopFront()
 	case packets.ReadyForQuery:
-		state, ok := packets.ReadReadyForQuery(in)
+		state, ok := packets.ReadReadyForQuery(&read)
 		if !ok {
 			return errors.New("bad packet format")
 		}
diff --git a/lib/middleware/middlewares/ps/client.go b/lib/middleware/middlewares/ps/client.go
index 86bf0003654d73a3c25984d1cec50b586e6d3b17..dd4e671655381df956e0a8618c483e2752d1251e 100644
--- a/lib/middleware/middlewares/ps/client.go
+++ b/lib/middleware/middlewares/ps/client.go
@@ -29,9 +29,10 @@ func (T *Client) SetServer(peer *Server) {
 }
 
 func (T *Client) updateParameter0(ctx middleware.Context, name, value string) error {
-	out := T.buf.Write()
-	packets.WriteParameterStatus(out, name, value)
-	err := ctx.Send(out)
+	packet := zap.NewPacket()
+	defer packet.Done()
+	packets.WriteParameterStatus(packet, name, value)
+	err := ctx.Write(packet)
 	if err != nil {
 		return err
 	}
@@ -76,10 +77,11 @@ func (T *Client) sync(ctx middleware.Context) error {
 	return nil
 }
 
-func (T *Client) Send(ctx middleware.Context, in zap.Inspector) error {
-	switch in.Type() {
+func (T *Client) Send(ctx middleware.Context, packet *zap.Packet) error {
+	read := packet.Read()
+	switch read.ReadType() {
 	case packets.ParameterStatus:
-		key, value, ok := packets.ReadParameterStatus(in)
+		key, value, ok := packets.ReadParameterStatus(&read)
 		if !ok {
 			return errors.New("bad packet format")
 		}
diff --git a/lib/middleware/middlewares/ps/server.go b/lib/middleware/middlewares/ps/server.go
index aa7d9cb109bcaea63d395c22ea9f05b66f4ac83b..802ea5b21212012d6a1c6384586ed5c7ece1b24b 100644
--- a/lib/middleware/middlewares/ps/server.go
+++ b/lib/middleware/middlewares/ps/server.go
@@ -20,10 +20,11 @@ func NewServer() *Server {
 	}
 }
 
-func (T *Server) Read(_ middleware.Context, in zap.Inspector) error {
-	switch in.Type() {
+func (T *Server) Read(_ middleware.Context, in *zap.Packet) error {
+	read := in.Read()
+	switch read.ReadType() {
 	case packets.ParameterStatus:
-		key, value, ok := packets.ReadParameterStatus(in)
+		key, value, ok := packets.ReadParameterStatus(&read)
 		if !ok {
 			return errors.New("bad packet format")
 		}
diff --git a/lib/middleware/middlewares/unterminate/unterminate.go b/lib/middleware/middlewares/unterminate/unterminate.go
index 2dc5b2aadd9fca4f6551ca522d45bfce5717a07f..69f77aeec55395b7e494a305003f0a8e6e7027e7 100644
--- a/lib/middleware/middlewares/unterminate/unterminate.go
+++ b/lib/middleware/middlewares/unterminate/unterminate.go
@@ -14,8 +14,8 @@ type unterm struct {
 	middleware.Nil
 }
 
-func (unterm) Read(_ middleware.Context, in zap.Inspector) error {
-	if in.Type() == packets.Terminate {
+func (unterm) Read(_ middleware.Context, packet *zap.Packet) error {
+	if packet.ReadType() == packets.Terminate {
 		return io.EOF
 	}
 	return nil
diff --git a/lib/middleware/nil.go b/lib/middleware/nil.go
index b8ea179ce1d77db77733e90c35e2b1c9d9ca5ea8..65132675d90b90a1be605f7fb12d76fda29c8f25 100644
--- a/lib/middleware/nil.go
+++ b/lib/middleware/nil.go
@@ -4,11 +4,19 @@ import "pggat2/lib/zap"
 
 type Nil struct{}
 
-func (Nil) Write(_ Context, _ zap.Inspector) error {
+func (Nil) Read(_ Context, _ *zap.Packet) error {
 	return nil
 }
 
-func (Nil) Read(_ Context, _ zap.Inspector) error {
+func (Nil) ReadUntyped(_ Context, _ *zap.UntypedPacket) error {
+	return nil
+}
+
+func (Nil) Write(_ Context, _ *zap.Packet) error {
+	return nil
+}
+
+func (Nil) WriteUntyped(_ Context, _ *zap.UntypedPacket) error {
 	return nil
 }
 
diff --git a/lib/zap/buffer.go b/lib/zap/buffer.go
deleted file mode 100644
index f39580f03155e2036be3c845d65b447bb67499a8..0000000000000000000000000000000000000000
--- a/lib/zap/buffer.go
+++ /dev/null
@@ -1,100 +0,0 @@
-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
deleted file mode 100644
index 70421b0c44f7e25673c6b444f2d13143e097cfd3..0000000000000000000000000000000000000000
--- a/lib/zap/builder.go
+++ /dev/null
@@ -1,124 +0,0 @@
-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/inspector.go b/lib/zap/inspector.go
deleted file mode 100644
index 408861b7ad77f17b2311a0d65251063f9782ce7d..0000000000000000000000000000000000000000
--- a/lib/zap/inspector.go
+++ /dev/null
@@ -1,164 +0,0 @@
-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/zap3/packet.go b/lib/zap/packet.go
similarity index 80%
rename from lib/zap3/packet.go
rename to lib/zap/packet.go
index d80df9d70ce017faedce11af5d7c4a9bbecec908..62a57cf47294da6ee2ad151ce5eab3db8b7d61e9 100644
--- a/lib/zap3/packet.go
+++ b/lib/zap/packet.go
@@ -1,4 +1,4 @@
-package zap3
+package zap
 
 import (
 	"encoding/binary"
@@ -133,6 +133,21 @@ func (T *PacketReader) ReadBytes(b []byte) bool {
 	return true
 }
 
+func (T *PacketReader) ReadUnsafeBytes(n int) ([]byte, bool) {
+	if len(*T) < n {
+		return nil, false
+	}
+	v := (*T)[:n]
+	*T = (*T)[n:]
+	return v, true
+}
+
+func (T *PacketReader) ReadUnsafeRemaining() []byte {
+	v := *T
+	*T = nil
+	return v
+}
+
 type PacketWriter []byte
 
 func (T *PacketWriter) WriteInt8(v int8) {
@@ -197,25 +212,38 @@ type Packet struct {
 	PacketWriter
 }
 
+func NewPacket() *Packet {
+	return &Packet{
+		PacketWriter{
+			0, 0, 0, 0, 4,
+		},
+	}
+}
+
 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()
+	length := binary.BigEndian.Uint32(T.PacketWriter[1:])
 	T.PacketWriter = slices.Resize(T.PacketWriter, int(length)+1)
 	m, err := io.ReadFull(r, T.Payload())
 	return int64(n + m), err
 }
 
+func (T *Packet) updateLength() {
+	binary.BigEndian.PutUint32(T.PacketWriter[1:], T.Length())
+}
+
 func (T *Packet) WriteTo(w io.Writer) (int64, error) {
+	T.updateLength()
 	n, err := w.Write(T.PacketWriter)
 	return int64(n), err
 }
 
 func (T *Packet) Length() uint32 {
-	return binary.BigEndian.Uint32(T.PacketWriter[1:])
+	return uint32(len(T.PacketWriter)) - 1
 }
 
 func (T *Packet) Payload() []byte {
@@ -223,16 +251,25 @@ func (T *Packet) Payload() []byte {
 }
 
 func (T *Packet) WriteType(v Type) {
-	T.PacketWriter[0] = v
+	T.PacketWriter[0] = byte(v)
+	T.PacketWriter = T.PacketWriter[:5]
+}
+
+func (T *Packet) ReadType() Type {
+	return Type(T.PacketWriter[0])
 }
 
 func (T *Packet) Read() ReadablePacket {
 	return ReadablePacket{
-		typ:          T.PacketWriter[0],
+		typ:          T.ReadType(),
 		PacketReader: T.Payload(),
 	}
 }
 
+func (T *Packet) Done() {
+	// TODO(garet)
+}
+
 type UntypedReadablePacket struct {
 	PacketReader
 }
@@ -241,25 +278,38 @@ type UntypedPacket struct {
 	PacketWriter
 }
 
+func NewUntypedPacket() *UntypedPacket {
+	return &UntypedPacket{
+		PacketWriter{
+			0, 0, 0, 4,
+		},
+	}
+}
+
 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()
+	length := binary.BigEndian.Uint32(T.PacketWriter)
 	T.PacketWriter = slices.Resize(T.PacketWriter, int(length))
 	m, err := io.ReadFull(r, T.Payload())
 	return int64(n + m), err
 }
 
+func (T *UntypedPacket) updateLength() {
+	binary.BigEndian.PutUint32(T.PacketWriter, T.Length())
+}
+
 func (T *UntypedPacket) WriteTo(w io.Writer) (int64, error) {
+	T.updateLength()
 	n, err := w.Write(T.PacketWriter)
 	return int64(n), err
 }
 
 func (T *UntypedPacket) Length() uint32 {
-	return binary.BigEndian.Uint32(T.PacketWriter)
+	return uint32(len(T.PacketWriter))
 }
 
 func (T *UntypedPacket) Payload() []byte {
@@ -271,3 +321,7 @@ func (T *UntypedPacket) Read() UntypedReadablePacket {
 		PacketReader: PacketReader(T.Payload()),
 	}
 }
+
+func (T *UntypedPacket) Done() {
+	// TODO(garet)
+}
diff --git a/lib/zap/packets/v3.0/authenticationcleartext.go b/lib/zap/packets/v3.0/authenticationcleartext.go
index bf415543dce965e64ca58092f2695116e622d0cf..095138654b7d63f7c58852bcc62dbba0e7670c0c 100644
--- a/lib/zap/packets/v3.0/authenticationcleartext.go
+++ b/lib/zap/packets/v3.0/authenticationcleartext.go
@@ -2,12 +2,11 @@ package packets
 
 import "pggat2/lib/zap"
 
-func ReadAuthenticationCleartext(in zap.Inspector) bool {
-	in.Reset()
-	if in.Type() != Authentication {
+func ReadAuthenticationCleartext(in *zap.ReadablePacket) bool {
+	if in.ReadType() != Authentication {
 		return false
 	}
-	method, ok := in.Int32()
+	method, ok := in.ReadInt32()
 	if !ok {
 		return false
 	}
@@ -17,8 +16,7 @@ func ReadAuthenticationCleartext(in zap.Inspector) bool {
 	return true
 }
 
-func WriteAuthenticationCleartext(out zap.Builder) {
-	out.Reset()
-	out.Type(Authentication)
-	out.Int32(3)
+func WriteAuthenticationCleartext(out *zap.Packet) {
+	out.WriteType(Authentication)
+	out.WriteInt32(3)
 }
diff --git a/lib/zap/packets/v3.0/authenticationmd5.go b/lib/zap/packets/v3.0/authenticationmd5.go
index 773066a0a1d386ed6a8ac0088507a8f147ebaa51..96bcbe0837a80e71364db435e9715f0bb24f0106 100644
--- a/lib/zap/packets/v3.0/authenticationmd5.go
+++ b/lib/zap/packets/v3.0/authenticationmd5.go
@@ -2,12 +2,11 @@ package packets
 
 import "pggat2/lib/zap"
 
-func ReadAuthenticationMD5(in zap.Inspector) ([4]byte, bool) {
-	in.Reset()
-	if in.Type() != Authentication {
+func ReadAuthenticationMD5(in *zap.ReadablePacket) ([4]byte, bool) {
+	if in.ReadType() != Authentication {
 		return [4]byte{}, false
 	}
-	method, ok := in.Int32()
+	method, ok := in.ReadInt32()
 	if !ok {
 		return [4]byte{}, false
 	}
@@ -15,16 +14,15 @@ func ReadAuthenticationMD5(in zap.Inspector) ([4]byte, bool) {
 		return [4]byte{}, false
 	}
 	var salt [4]byte
-	ok = in.Bytes(salt[:])
+	ok = in.ReadBytes(salt[:])
 	if !ok {
 		return salt, false
 	}
 	return salt, true
 }
 
-func WriteAuthenticationMD5(out zap.Builder, salt [4]byte) {
-	out.Reset()
-	out.Type(Authentication)
-	out.Uint32(5)
-	out.Bytes(salt[:])
+func WriteAuthenticationMD5(out *zap.Packet, salt [4]byte) {
+	out.WriteType(Authentication)
+	out.WriteUint32(5)
+	out.WriteBytes(salt[:])
 }
diff --git a/lib/zap/packets/v3.0/authenticationok.go b/lib/zap/packets/v3.0/authenticationok.go
index 29271a7fb27e676a764c80be2f1cc5ccd995ba2f..44ce0f7bc8a410729bb6cc8091ba6dd59a671d11 100644
--- a/lib/zap/packets/v3.0/authenticationok.go
+++ b/lib/zap/packets/v3.0/authenticationok.go
@@ -1,15 +1,12 @@
 package packets
 
-import (
-	"pggat2/lib/zap"
-)
+import "pggat2/lib/zap"
 
-func ReadAuthenticationOk(in zap.Inspector) bool {
-	in.Reset()
-	if in.Type() != Authentication {
+func ReadAuthenticationOk(in *zap.ReadablePacket) bool {
+	if in.ReadType() != Authentication {
 		return false
 	}
-	method, ok := in.Int32()
+	method, ok := in.ReadInt32()
 	if !ok {
 		return false
 	}
@@ -19,8 +16,7 @@ func ReadAuthenticationOk(in zap.Inspector) bool {
 	return true
 }
 
-func WriteAuthenticationOk(out zap.Builder) {
-	out.Reset()
-	out.Type(Authentication)
-	out.Int32(0)
+func WriteAuthenticationOk(out *zap.Packet) {
+	out.WriteType(Authentication)
+	out.WriteInt32(0)
 }
diff --git a/lib/zap/packets/v3.0/authenticationresponse.go b/lib/zap/packets/v3.0/authenticationresponse.go
index eec9dc69d5e9ab2990dbafd78aadba07afb98d52..38270480f3210f705dba2ea650f0705763a59c2d 100644
--- a/lib/zap/packets/v3.0/authenticationresponse.go
+++ b/lib/zap/packets/v3.0/authenticationresponse.go
@@ -2,16 +2,14 @@ package packets
 
 import "pggat2/lib/zap"
 
-func ReadAuthenticationResponse(in zap.Inspector) ([]byte, bool) {
-	in.Reset()
-	if in.Type() != AuthenticationResponse {
+func ReadAuthenticationResponse(in *zap.ReadablePacket) ([]byte, bool) {
+	if in.ReadType() != AuthenticationResponse {
 		return nil, false
 	}
-	return in.Remaining(), true
+	return in.ReadUnsafeRemaining(), true
 }
 
-func WriteAuthenticationResponse(out zap.Builder, resp []byte) {
-	out.Reset()
-	out.Type(AuthenticationResponse)
-	out.Bytes(resp)
+func WriteAuthenticationResponse(out *zap.Packet, resp []byte) {
+	out.WriteType(AuthenticationResponse)
+	out.WriteBytes(resp)
 }
diff --git a/lib/zap/packets/v3.0/authenticationsasl.go b/lib/zap/packets/v3.0/authenticationsasl.go
index dd9bc38e6b37b4b33a98978bdabe45d75a9b7dbd..2db1b390a174b51a4bb31441bc35784272c63d95 100644
--- a/lib/zap/packets/v3.0/authenticationsasl.go
+++ b/lib/zap/packets/v3.0/authenticationsasl.go
@@ -2,13 +2,12 @@ package packets
 
 import "pggat2/lib/zap"
 
-func ReadAuthenticationSASL(in zap.Inspector) ([]string, bool) {
-	in.Reset()
-	if in.Type() != Authentication {
+func ReadAuthenticationSASL(in *zap.ReadablePacket) ([]string, bool) {
+	if in.ReadType() != Authentication {
 		return nil, false
 	}
 
-	method, ok := in.Int32()
+	method, ok := in.ReadInt32()
 	if !ok {
 		return nil, false
 	}
@@ -17,10 +16,12 @@ func ReadAuthenticationSASL(in zap.Inspector) ([]string, bool) {
 		return nil, false
 	}
 
+	in2 := *in
+
 	// get count first to prevent reallocating the slice a bunch
 	var mechanismCount int
 	for {
-		mechanism, ok := in.String()
+		mechanism, ok := in2.ReadString()
 		if !ok {
 			return nil, false
 		}
@@ -31,10 +32,8 @@ func ReadAuthenticationSASL(in zap.Inspector) ([]string, bool) {
 	}
 
 	mechanisms := make([]string, 0, mechanismCount)
-	in.Reset()
-	in.Int32()
 	for i := 0; i < mechanismCount; i++ {
-		mechanism, ok := in.String()
+		mechanism, ok := in.ReadString()
 		if !ok {
 			return nil, false
 		}
@@ -44,12 +43,11 @@ func ReadAuthenticationSASL(in zap.Inspector) ([]string, bool) {
 	return mechanisms, true
 }
 
-func WriteAuthenticationSASL(out zap.Builder, mechanisms []string) {
-	out.Reset()
-	out.Type(Authentication)
-	out.Int32(10)
+func WriteAuthenticationSASL(out *zap.Packet, mechanisms []string) {
+	out.WriteType(Authentication)
+	out.WriteInt32(10)
 	for _, mechanism := range mechanisms {
-		out.String(mechanism)
+		out.WriteString(mechanism)
 	}
-	out.Uint8(0)
+	out.WriteUint8(0)
 }
diff --git a/lib/zap/packets/v3.0/authenticationsaslcontinue.go b/lib/zap/packets/v3.0/authenticationsaslcontinue.go
index cf7f18ff42f1125f9d4e3a7d92137fa506370276..25b49abbd75d9f0106bb1e24330340a030cd0219 100644
--- a/lib/zap/packets/v3.0/authenticationsaslcontinue.go
+++ b/lib/zap/packets/v3.0/authenticationsaslcontinue.go
@@ -1,27 +1,23 @@
 package packets
 
-import (
-	"pggat2/lib/zap"
-)
+import "pggat2/lib/zap"
 
-func ReadAuthenticationSASLContinue(in zap.Inspector) ([]byte, bool) {
-	in.Reset()
-	if in.Type() != Authentication {
+func ReadAuthenticationSASLContinue(in *zap.ReadablePacket) ([]byte, bool) {
+	if in.ReadType() != Authentication {
 		return nil, false
 	}
-	method, ok := in.Int32()
+	method, ok := in.ReadInt32()
 	if !ok {
 		return nil, false
 	}
 	if method != 11 {
 		return nil, false
 	}
-	return in.Remaining(), true
+	return in.ReadUnsafeRemaining(), true
 }
 
-func WriteAuthenticationSASLContinue(out zap.Builder, resp []byte) {
-	out.Reset()
-	out.Type(Authentication)
-	out.Int32(11)
-	out.Bytes(resp)
+func WriteAuthenticationSASLContinue(out *zap.Packet, resp []byte) {
+	out.WriteType(Authentication)
+	out.WriteInt32(11)
+	out.WriteBytes(resp)
 }
diff --git a/lib/zap/packets/v3.0/authenticationsaslfinal.go b/lib/zap/packets/v3.0/authenticationsaslfinal.go
index b29ae94efd13ff8b0e3d01ce54ee487009e34ebb..29ac80534159e14178f73c4e822daa4a106791fa 100644
--- a/lib/zap/packets/v3.0/authenticationsaslfinal.go
+++ b/lib/zap/packets/v3.0/authenticationsaslfinal.go
@@ -2,24 +2,22 @@ package packets
 
 import "pggat2/lib/zap"
 
-func ReadAuthenticationSASLFinal(in zap.Inspector) ([]byte, bool) {
-	in.Reset()
-	if in.Type() != Authentication {
+func ReadAuthenticationSASLFinal(in *zap.ReadablePacket) ([]byte, bool) {
+	if in.ReadType() != Authentication {
 		return nil, false
 	}
-	method, ok := in.Int32()
+	method, ok := in.ReadInt32()
 	if !ok {
 		return nil, false
 	}
 	if method != 12 {
 		return nil, false
 	}
-	return in.Remaining(), true
+	return in.ReadUnsafeRemaining(), true
 }
 
-func WriteAuthenticationSASLFinal(out zap.Builder, resp []byte) {
-	out.Reset()
-	out.Type(Authentication)
-	out.Int32(12)
-	out.Bytes(resp)
+func WriteAuthenticationSASLFinal(out *zap.Packet, resp []byte) {
+	out.WriteType(Authentication)
+	out.WriteInt32(12)
+	out.WriteBytes(resp)
 }
diff --git a/lib/zap/packets/v3.0/backendkeydata.go b/lib/zap/packets/v3.0/backendkeydata.go
index 74040a54ce33a3eceb4331ba839cb81da2d144b5..edc4effeccdf8feb568c5fdbd6ab0bac8db879b1 100644
--- a/lib/zap/packets/v3.0/backendkeydata.go
+++ b/lib/zap/packets/v3.0/backendkeydata.go
@@ -2,21 +2,19 @@ package packets
 
 import "pggat2/lib/zap"
 
-func ReadBackendKeyData(in zap.Inspector) ([8]byte, bool) {
-	in.Reset()
-	if in.Type() != BackendKeyData {
+func ReadBackendKeyData(in *zap.ReadablePacket) ([8]byte, bool) {
+	if in.ReadType() != BackendKeyData {
 		return [8]byte{}, false
 	}
 	var cancellationKey [8]byte
-	ok := in.Bytes(cancellationKey[:])
+	ok := in.ReadBytes(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[:])
+func WriteBackendKeyData(out *zap.Packet, cancellationKey [8]byte) {
+	out.WriteType(BackendKeyData)
+	out.WriteBytes(cancellationKey[:])
 }
diff --git a/lib/zap/packets/v3.0/bind.go b/lib/zap/packets/v3.0/bind.go
index 9691883930d7f2da0d67986cdae80bc471a5e43d..ed3669ddecb9b23f42027c4d1372515149fc8a3e 100644
--- a/lib/zap/packets/v3.0/bind.go
+++ b/lib/zap/packets/v3.0/bind.go
@@ -1,52 +1,49 @@
 package packets
 
-import (
-	"pggat2/lib/zap"
-)
+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 {
+func ReadBind(in *zap.ReadablePacket) (destination string, source string, parameterFormatCodes []int16, parameterValues [][]byte, resultFormatCodes []int16, ok bool) {
+	if in.ReadType() != Bind {
 		return
 	}
-	destination, ok = in.String()
+	destination, ok = in.ReadString()
 	if !ok {
 		return
 	}
-	source, ok = in.String()
+	source, ok = in.ReadString()
 	if !ok {
 		return
 	}
 	var parameterFormatCodesLength uint16
-	parameterFormatCodesLength, ok = in.Uint16()
+	parameterFormatCodesLength, ok = in.ReadUint16()
 	if !ok {
 		return
 	}
 	parameterFormatCodes = make([]int16, 0, int(parameterFormatCodesLength))
 	for i := 0; i < int(parameterFormatCodesLength); i++ {
 		var parameterFormatCode int16
-		parameterFormatCode, ok = in.Int16()
+		parameterFormatCode, ok = in.ReadInt16()
 		if !ok {
 			return
 		}
 		parameterFormatCodes = append(parameterFormatCodes, parameterFormatCode)
 	}
 	var parameterValuesLength uint16
-	parameterValuesLength, ok = in.Uint16()
+	parameterValuesLength, ok = in.ReadUint16()
 	if !ok {
 		return
 	}
 	parameterValues = make([][]byte, 0, int(parameterValuesLength))
 	for i := 0; i < int(parameterValuesLength); i++ {
 		var parameterValueLength int32
-		parameterValueLength, ok = in.Int32()
+		parameterValueLength, ok = in.ReadInt32()
 		if !ok {
 			return
 		}
 		var parameterValue []byte
 		if parameterValueLength >= 0 {
 			parameterValue = make([]byte, int(parameterValueLength))
-			ok = in.Bytes(parameterValue)
+			ok = in.ReadBytes(parameterValue)
 			if !ok {
 				return
 			}
@@ -54,14 +51,14 @@ func ReadBind(in zap.Inspector) (destination string, source string, parameterFor
 		parameterValues = append(parameterValues, parameterValue)
 	}
 	var resultFormatCodesLength uint16
-	resultFormatCodesLength, ok = in.Uint16()
+	resultFormatCodesLength, ok = in.ReadUint16()
 	if !ok {
 		return
 	}
 	resultFormatCodes = make([]int16, 0, int(resultFormatCodesLength))
 	for i := 0; i < int(resultFormatCodesLength); i++ {
 		var resultFormatCode int16
-		resultFormatCode, ok = in.Int16()
+		resultFormatCode, ok = in.ReadInt16()
 		if !ok {
 			return
 		}
@@ -70,26 +67,25 @@ func ReadBind(in zap.Inspector) (destination string, source string, parameterFor
 	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)))
+func WriteBind(out *zap.Packet, destination, source string, parameterFormatCodes []int16, parameterValues [][]byte, resultFormatCodes []int16) {
+	out.WriteType(Bind)
+	out.WriteString(destination)
+	out.WriteString(source)
+	out.WriteUint16(uint16(len(parameterFormatCodes)))
 	for _, v := range parameterFormatCodes {
-		out.Int16(v)
+		out.WriteInt16(v)
 	}
-	out.Uint16(uint16(len(parameterValues)))
+	out.WriteUint16(uint16(len(parameterValues)))
 	for _, v := range parameterValues {
 		if v == nil {
-			out.Int32(-1)
+			out.WriteInt32(-1)
 			continue
 		}
-		out.Int32(int32(len(v)))
-		out.Bytes(v)
+		out.WriteInt32(int32(len(v)))
+		out.WriteBytes(v)
 	}
-	out.Uint16(uint16(len(resultFormatCodes)))
+	out.WriteUint16(uint16(len(resultFormatCodes)))
 	for _, v := range resultFormatCodes {
-		out.Int16(v)
+		out.WriteInt16(v)
 	}
 }
diff --git a/lib/zap/packets/v3.0/close.go b/lib/zap/packets/v3.0/close.go
index e382f3d3b65f8713910671e3b3eb0cbe2481d5ee..b7b3ba8b09b77be0f1bb15167bf9c6044fdbf6d6 100644
--- a/lib/zap/packets/v3.0/close.go
+++ b/lib/zap/packets/v3.0/close.go
@@ -2,25 +2,23 @@ package packets
 
 import "pggat2/lib/zap"
 
-func ReadClose(in zap.Inspector) (which uint8, target string, ok bool) {
-	in.Reset()
-	if in.Type() != Close {
+func ReadClose(in *zap.ReadablePacket) (which uint8, target string, ok bool) {
+	if in.ReadType() != Close {
 		return
 	}
-	which, ok = in.Uint8()
+	which, ok = in.ReadUint8()
 	if !ok {
 		return
 	}
-	target, ok = in.String()
+	target, ok = in.ReadString()
 	if !ok {
 		return
 	}
 	return
 }
 
-func WriteClose(out zap.Builder, which uint8, target string) {
-	out.Reset()
-	out.Type(Close)
-	out.Uint8(which)
-	out.String(target)
+func WriteClose(out *zap.Packet, which uint8, target string) {
+	out.WriteType(Close)
+	out.WriteUint8(which)
+	out.WriteString(target)
 }
diff --git a/lib/zap/packets/v3.0/describe.go b/lib/zap/packets/v3.0/describe.go
index a5b52fff301e9ab392a61d7c94ed8957defd79df..9cfffde3151cc3437d38521ea8439ff252dcd5bc 100644
--- a/lib/zap/packets/v3.0/describe.go
+++ b/lib/zap/packets/v3.0/describe.go
@@ -1,28 +1,24 @@
 package packets
 
-import (
-	"pggat2/lib/zap"
-)
+import "pggat2/lib/zap"
 
-func ReadDescribe(in zap.Inspector) (which uint8, target string, ok bool) {
-	in.Reset()
-	if in.Type() != Describe {
+func ReadDescribe(in *zap.ReadablePacket) (which uint8, target string, ok bool) {
+	if in.ReadType() != Describe {
 		return
 	}
-	which, ok = in.Uint8()
+	which, ok = in.ReadUint8()
 	if !ok {
 		return
 	}
-	target, ok = in.String()
+	target, ok = in.ReadString()
 	if !ok {
 		return
 	}
 	return
 }
 
-func WriteDescribe(out zap.Builder, which uint8, target string) {
-	out.Reset()
-	out.Type(Describe)
-	out.Uint8(which)
-	out.String(target)
+func WriteDescribe(out *zap.Packet, which uint8, target string) {
+	out.WriteType(Describe)
+	out.WriteUint8(which)
+	out.WriteString(target)
 }
diff --git a/lib/zap/packets/v3.0/errorresponse.go b/lib/zap/packets/v3.0/errorresponse.go
index d6f36cd59e88479df8888188f9e8d353591c65e3..f7680c0cf7bc0cd835c858b89cbd5697f2ad296e 100644
--- a/lib/zap/packets/v3.0/errorresponse.go
+++ b/lib/zap/packets/v3.0/errorresponse.go
@@ -5,9 +5,8 @@ import (
 	"pggat2/lib/zap"
 )
 
-func ReadErrorResponse(in zap.Inspector) (perror.Error, bool) {
-	in.Reset()
-	if in.Type() != ErrorResponse {
+func ReadErrorResponse(in *zap.ReadablePacket) (perror.Error, bool) {
+	if in.ReadType() != ErrorResponse {
 		return nil, false
 	}
 
@@ -17,7 +16,7 @@ func ReadErrorResponse(in zap.Inspector) (perror.Error, bool) {
 	var extra []perror.ExtraField
 
 	for {
-		typ, ok := in.Uint8()
+		typ, ok := in.ReadUint8()
 		if !ok {
 			return nil, false
 		}
@@ -26,7 +25,7 @@ func ReadErrorResponse(in zap.Inspector) (perror.Error, bool) {
 			break
 		}
 
-		value, ok := in.String()
+		value, ok := in.ReadString()
 		if !ok {
 			return nil, false
 		}
@@ -54,23 +53,22 @@ func ReadErrorResponse(in zap.Inspector) (perror.Error, bool) {
 	), true
 }
 
-func WriteErrorResponse(out zap.Builder, err perror.Error) {
-	out.Reset()
-	out.Type(ErrorResponse)
+func WriteErrorResponse(out *zap.Packet, err perror.Error) {
+	out.WriteType(ErrorResponse)
 
-	out.Uint8('S')
-	out.String(string(err.Severity()))
+	out.WriteUint8('S')
+	out.WriteString(string(err.Severity()))
 
-	out.Uint8('C')
-	out.String(string(err.Code()))
+	out.WriteUint8('C')
+	out.WriteString(string(err.Code()))
 
-	out.Uint8('M')
-	out.String(err.Message())
+	out.WriteUint8('M')
+	out.WriteString(err.Message())
 
 	for _, field := range err.Extra() {
-		out.Uint8(uint8(field.Type))
-		out.String(field.Value)
+		out.WriteUint8(uint8(field.Type))
+		out.WriteString(field.Value)
 	}
 
-	out.Uint8(0)
+	out.WriteUint8(0)
 }
diff --git a/lib/zap/packets/v3.0/execute.go b/lib/zap/packets/v3.0/execute.go
index 7c32249a94cea7809e89b8e7223e3cbeb9e2a479..5d93031fae0cf3336cf05cd3c50998c75b75b230 100644
--- a/lib/zap/packets/v3.0/execute.go
+++ b/lib/zap/packets/v3.0/execute.go
@@ -1,28 +1,24 @@
 package packets
 
-import (
-	"pggat2/lib/zap"
-)
+import "pggat2/lib/zap"
 
-func ReadExecute(in zap.Inspector) (target string, maxRows int32, ok bool) {
-	in.Reset()
-	if in.Type() != Execute {
+func ReadExecute(in *zap.ReadablePacket) (target string, maxRows int32, ok bool) {
+	if in.ReadType() != Execute {
 		return
 	}
-	target, ok = in.String()
+	target, ok = in.ReadString()
 	if !ok {
 		return
 	}
-	maxRows, ok = in.Int32()
+	maxRows, ok = in.ReadInt32()
 	if !ok {
 		return
 	}
 	return
 }
 
-func WriteExecute(out zap.Builder, target string, maxRows int32) {
-	out.Reset()
-	out.Type(Execute)
-	out.String(target)
-	out.Int32(maxRows)
+func WriteExecute(out *zap.Packet, target string, maxRows int32) {
+	out.WriteType(Execute)
+	out.WriteString(target)
+	out.WriteInt32(maxRows)
 }
diff --git a/lib/zap/packets/v3.0/negotiateprotocolversion.go b/lib/zap/packets/v3.0/negotiateprotocolversion.go
index 73595713bb14c2490ccbc3559bc5245f70ca37a6..fc59c91b220a834bf1b2d9e0e10d897c89751dcd 100644
--- a/lib/zap/packets/v3.0/negotiateprotocolversion.go
+++ b/lib/zap/packets/v3.0/negotiateprotocolversion.go
@@ -1,27 +1,24 @@
 package packets
 
-import (
-	"pggat2/lib/zap"
-)
+import "pggat2/lib/zap"
 
-func ReadNegotiateProtocolVersion(in zap.Inspector) (minorProtocolVersion int32, unrecognizedOptions []string, ok bool) {
-	in.Reset()
-	if in.Type() != NegotiateProtocolVersion {
+func ReadNegotiateProtocolVersion(in *zap.ReadablePacket) (minorProtocolVersion int32, unrecognizedOptions []string, ok bool) {
+	if in.ReadType() != NegotiateProtocolVersion {
 		return
 	}
-	minorProtocolVersion, ok = in.Int32()
+	minorProtocolVersion, ok = in.ReadInt32()
 	if !ok {
 		return
 	}
 	var numUnrecognizedOptions int32
-	numUnrecognizedOptions, ok = in.Int32()
+	numUnrecognizedOptions, ok = in.ReadInt32()
 	if !ok {
 		return
 	}
 	unrecognizedOptions = make([]string, 0, numUnrecognizedOptions)
 	for i := 0; i < int(numUnrecognizedOptions); i++ {
 		var unrecognizedOption string
-		unrecognizedOption, ok = in.String()
+		unrecognizedOption, ok = in.ReadString()
 		if !ok {
 			return
 		}
@@ -31,12 +28,11 @@ func ReadNegotiateProtocolVersion(in zap.Inspector) (minorProtocolVersion int32,
 	return
 }
 
-func WriteNegotiateProtocolVersion(out zap.Builder, minorProtocolVersion int32, unrecognizedOptions []string) {
-	out.Reset()
-	out.Type(NegotiateProtocolVersion)
-	out.Int32(minorProtocolVersion)
-	out.Int32(int32(len(unrecognizedOptions)))
+func WriteNegotiateProtocolVersion(out *zap.Packet, minorProtocolVersion int32, unrecognizedOptions []string) {
+	out.WriteType(NegotiateProtocolVersion)
+	out.WriteInt32(minorProtocolVersion)
+	out.WriteInt32(int32(len(unrecognizedOptions)))
 	for _, option := range unrecognizedOptions {
-		out.String(option)
+		out.WriteString(option)
 	}
 }
diff --git a/lib/zap/packets/v3.0/parameterstatus.go b/lib/zap/packets/v3.0/parameterstatus.go
index cff7246aa0c17a2a82ce6a401e12276285e246ef..23822d7a4e17c68a4040751693c0063a04cd97a3 100644
--- a/lib/zap/packets/v3.0/parameterstatus.go
+++ b/lib/zap/packets/v3.0/parameterstatus.go
@@ -2,25 +2,23 @@ package packets
 
 import "pggat2/lib/zap"
 
-func ReadParameterStatus(in zap.Inspector) (key, value string, ok bool) {
-	in.Reset()
-	if in.Type() != ParameterStatus {
+func ReadParameterStatus(in *zap.ReadablePacket) (key, value string, ok bool) {
+	if in.ReadType() != ParameterStatus {
 		return
 	}
-	key, ok = in.String()
+	key, ok = in.ReadString()
 	if !ok {
 		return
 	}
-	value, ok = in.String()
+	value, ok = in.ReadString()
 	if !ok {
 		return
 	}
 	return
 }
 
-func WriteParameterStatus(out zap.Builder, key, value string) {
-	out.Reset()
-	out.Type(ParameterStatus)
-	out.String(key)
-	out.String(value)
+func WriteParameterStatus(out *zap.Packet, key, value string) {
+	out.WriteType(ParameterStatus)
+	out.WriteString(key)
+	out.WriteString(value)
 }
diff --git a/lib/zap/packets/v3.0/parse.go b/lib/zap/packets/v3.0/parse.go
index 3d7c3f31be570c76bd26482a20cc7305014ccfd3..d45a82c0047a48000c4264bfa650b438442637fd 100644
--- a/lib/zap/packets/v3.0/parse.go
+++ b/lib/zap/packets/v3.0/parse.go
@@ -4,28 +4,27 @@ import (
 	"pggat2/lib/zap"
 )
 
-func ReadParse(in zap.Inspector) (destination string, query string, parameterDataTypes []int32, ok bool) {
-	in.Reset()
-	if in.Type() != Parse {
+func ReadParse(in *zap.ReadablePacket) (destination string, query string, parameterDataTypes []int32, ok bool) {
+	if in.ReadType() != Parse {
 		return
 	}
-	destination, ok = in.String()
+	destination, ok = in.ReadString()
 	if !ok {
 		return
 	}
-	query, ok = in.String()
+	query, ok = in.ReadString()
 	if !ok {
 		return
 	}
 	var parameterDataTypesCount int16
-	parameterDataTypesCount, ok = in.Int16()
+	parameterDataTypesCount, ok = in.ReadInt16()
 	if !ok {
 		return
 	}
 	parameterDataTypes = make([]int32, 0, int(parameterDataTypesCount))
 	for i := 0; i < int(parameterDataTypesCount); i++ {
 		var parameterDataType int32
-		parameterDataType, ok = in.Int32()
+		parameterDataType, ok = in.ReadInt32()
 		if !ok {
 			return
 		}
@@ -34,13 +33,12 @@ func ReadParse(in zap.Inspector) (destination string, query string, parameterDat
 	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)))
+func WriteParse(out *zap.Packet, destination string, query string, parameterDataTypes []int32) {
+	out.WriteType(Parse)
+	out.WriteString(destination)
+	out.WriteString(query)
+	out.WriteInt16(int16(len(parameterDataTypes)))
 	for _, v := range parameterDataTypes {
-		out.Int32(v)
+		out.WriteInt32(v)
 	}
 }
diff --git a/lib/zap/packets/v3.0/passwordmessage.go b/lib/zap/packets/v3.0/passwordmessage.go
index f777e94c95118f457b1e70ec426f00e8673ba746..1844fcfee3394412bd6a399815a1fbf366bb7b03 100644
--- a/lib/zap/packets/v3.0/passwordmessage.go
+++ b/lib/zap/packets/v3.0/passwordmessage.go
@@ -4,20 +4,18 @@ import (
 	"pggat2/lib/zap"
 )
 
-func ReadPasswordMessage(in zap.Inspector) (string, bool) {
-	in.Reset()
-	if in.Type() != AuthenticationResponse {
+func ReadPasswordMessage(in *zap.ReadablePacket) (string, bool) {
+	if in.ReadType() != AuthenticationResponse {
 		return "", false
 	}
-	password, ok := in.String()
+	password, ok := in.ReadString()
 	if !ok {
 		return "", false
 	}
 	return password, true
 }
 
-func WritePasswordMessage(out zap.Builder, password string) {
-	out.Reset()
-	out.Type(AuthenticationResponse)
-	out.String(password)
+func WritePasswordMessage(out *zap.Packet, password string) {
+	out.WriteType(AuthenticationResponse)
+	out.WriteString(password)
 }
diff --git a/lib/zap/packets/v3.0/readyforquery.go b/lib/zap/packets/v3.0/readyforquery.go
index f023ceb06cc5de23a20eee25300573e0a6d299b5..9fb14d8376a04c3fc3b75d8fadc384f2f3cacb8a 100644
--- a/lib/zap/packets/v3.0/readyforquery.go
+++ b/lib/zap/packets/v3.0/readyforquery.go
@@ -4,20 +4,18 @@ import (
 	"pggat2/lib/zap"
 )
 
-func ReadReadyForQuery(in zap.Inspector) (byte, bool) {
-	in.Reset()
-	if in.Type() != ReadyForQuery {
+func ReadReadyForQuery(in *zap.ReadablePacket) (byte, bool) {
+	if in.ReadType() != ReadyForQuery {
 		return 0, false
 	}
-	state, ok := in.Uint8()
+	state, ok := in.ReadUint8()
 	if !ok {
 		return 0, false
 	}
 	return state, true
 }
 
-func WriteReadyForQuery(out zap.Builder, state uint8) {
-	out.Reset()
-	out.Type(ReadyForQuery)
-	out.Uint8(state)
+func WriteReadyForQuery(out *zap.Packet, state uint8) {
+	out.WriteType(ReadyForQuery)
+	out.WriteUint8(state)
 }
diff --git a/lib/zap/packets/v3.0/saslinitialresponse.go b/lib/zap/packets/v3.0/saslinitialresponse.go
index 6cbcd94b694e7fcc5a74c19c931b8be81629a823..e61cc20f99d3e7ed72af3c906b54b2e7f57247f7 100644
--- a/lib/zap/packets/v3.0/saslinitialresponse.go
+++ b/lib/zap/packets/v3.0/saslinitialresponse.go
@@ -1,22 +1,19 @@
 package packets
 
-import (
-	"pggat2/lib/zap"
-)
+import "pggat2/lib/zap"
 
-func ReadSASLInitialResponse(in zap.Inspector) (mechanism string, initialResponse []byte, ok bool) {
-	in.Reset()
-	if in.Type() != AuthenticationResponse {
+func ReadSASLInitialResponse(in *zap.ReadablePacket) (mechanism string, initialResponse []byte, ok bool) {
+	if in.ReadType() != AuthenticationResponse {
 		return
 	}
 
-	mechanism, ok = in.String()
+	mechanism, ok = in.ReadString()
 	if !ok {
 		return
 	}
 
 	var initialResponseSize int32
-	initialResponseSize, ok = in.Int32()
+	initialResponseSize, ok = in.ReadInt32()
 	if !ok {
 		return
 	}
@@ -24,18 +21,17 @@ func ReadSASLInitialResponse(in zap.Inspector) (mechanism string, initialRespons
 		return
 	}
 
-	initialResponse, ok = in.UnsafeBytes(int(initialResponseSize))
+	initialResponse, ok = in.ReadUnsafeBytes(int(initialResponseSize))
 	return
 }
 
-func WriteSASLInitialResponse(out zap.Builder, mechanism string, initialResponse []byte) {
-	out.Reset()
-	out.Type(AuthenticationResponse)
-	out.String(mechanism)
+func WriteSASLInitialResponse(out *zap.Packet, mechanism string, initialResponse []byte) {
+	out.WriteType(AuthenticationResponse)
+	out.WriteString(mechanism)
 	if initialResponse == nil {
-		out.Int32(-1)
+		out.WriteInt32(-1)
 	} else {
-		out.Int32(int32(len(initialResponse)))
-		out.Bytes(initialResponse)
+		out.WriteInt32(int32(len(initialResponse)))
+		out.WriteBytes(initialResponse)
 	}
 }
diff --git a/lib/zap/reader.go b/lib/zap/reader.go
index f16c4a554baf47b53231cd0eb8d022419549464e..61bc8de86c31ebec23263472c27205ed09bdc0fd 100644
--- a/lib/zap/reader.go
+++ b/lib/zap/reader.go
@@ -1,9 +1,34 @@
 package zap
 
-import "time"
+import "io"
 
 type Reader interface {
-	ReadInto(buffer *Buffer, typed bool) error
+	ReadByte() (byte, error)
+	Read(*Packet) error
+	ReadUntyped(*UntypedPacket) error
+}
+
+type IOReader struct {
+	Reader io.Reader
+}
+
+func (T IOReader) ReadByte() (byte, error) {
+	var res = []byte{0}
+	_, err := io.ReadFull(T.Reader, res)
+	if err != nil {
+		return 0, err
+	}
+	return res[0], err
+}
+
+func (T IOReader) Read(packet *Packet) error {
+	_, err := packet.ReadFrom(T.Reader)
+	return err
+}
 
-	SetReadDeadline(time time.Time) error
+func (T IOReader) ReadUntyped(packet *UntypedPacket) error {
+	_, err := packet.ReadFrom(T.Reader)
+	return err
 }
+
+var _ Reader = IOReader{}
diff --git a/lib/zap/readwriter.go b/lib/zap/readwriter.go
index 22b2a309250d2e694b5a5c9ef842a57780499e85..f98d5197cee6aeafd6769c74025f517c0c09a6ae 100644
--- a/lib/zap/readwriter.go
+++ b/lib/zap/readwriter.go
@@ -4,3 +4,8 @@ type ReadWriter interface {
 	Reader
 	Writer
 }
+
+type CombinedReadWriter struct {
+	Reader
+	Writer
+}
diff --git a/lib/zap/type.go b/lib/zap/type.go
index e26e5d617631afcbe8116694f1b01d219c8862cb..01066a16323472656eaa03e6d4c1b2c546529dae 100644
--- a/lib/zap/type.go
+++ b/lib/zap/type.go
@@ -1,3 +1,3 @@
 package zap
 
-type Type byte
+type Type int
diff --git a/lib/zap/writer.go b/lib/zap/writer.go
index aff1a982107897d4f5761d5a9945384a970a1bb9..26f21b705b8d2ae5ed2ecf338ac6251e76eeef34 100644
--- a/lib/zap/writer.go
+++ b/lib/zap/writer.go
@@ -1,9 +1,38 @@
 package zap
 
-import "time"
+import (
+	"io"
+)
 
 type Writer interface {
-	WriteFrom(buffer *Buffer) error
+	WriteByte(byte) error
+	Write(*Packet) error
+	WriteUntyped(*UntypedPacket) error
+	WriteV(*Packets) error
+}
+
+type IOWriter struct {
+	Writer io.Writer
+}
+
+func (T IOWriter) WriteByte(b byte) error {
+	_, err := T.Writer.Write([]byte{b})
+	return err
+}
 
-	SetWriteDeadline(time time.Time) error
+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{}
diff --git a/lib/zap/zio/readwriter.go b/lib/zap/zio/readwriter.go
deleted file mode 100644
index f1fe3ba3d1b8b54564c47eed4b6e26cff5f62b79..0000000000000000000000000000000000000000
--- a/lib/zap/zio/readwriter.go
+++ /dev/null
@@ -1,47 +0,0 @@
-package zio
-
-import (
-	"io"
-	"time"
-
-	"pggat2/lib/util/dio"
-	"pggat2/lib/zap"
-)
-
-type ReadWriter struct {
-	io dio.ReadWriter
-}
-
-func MakeReadWriter(io dio.ReadWriter) ReadWriter {
-	return ReadWriter{
-		io: io,
-	}
-}
-
-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
-	}
-
-	builder.Length(builder.GetLength())
-
-	_, err = io.ReadFull(T.io, builder.Payload())
-	return err
-}
-
-func (T ReadWriter) WriteFrom(buffer *zap.Buffer) error {
-	_, err := T.io.Write(buffer.Full())
-	return err
-}
-
-func (T ReadWriter) SetReadDeadline(time time.Time) error {
-	return T.io.SetReadDeadline(time)
-}
-
-func (T ReadWriter) SetWriteDeadline(time time.Time) error {
-	return T.io.SetWriteDeadline(time)
-}
-
-var _ zap.ReadWriter = ReadWriter{}
diff --git a/lib/zap3/packets/v3.0/authenticationcleartext.go b/lib/zap3/packets/v3.0/authenticationcleartext.go
deleted file mode 100644
index 594ca6eb4fde79bb389923037a16bb3ce294fa56..0000000000000000000000000000000000000000
--- a/lib/zap3/packets/v3.0/authenticationcleartext.go
+++ /dev/null
@@ -1,24 +0,0 @@
-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
deleted file mode 100644
index 4837b36a49ee988e3a4c9dd5fd87be2f3b82172e..0000000000000000000000000000000000000000
--- a/lib/zap3/packets/v3.0/authenticationmd5.go
+++ /dev/null
@@ -1,30 +0,0 @@
-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
deleted file mode 100644
index ddd35f9f46939bbf86aabea32cabcbfb1d1339a5..0000000000000000000000000000000000000000
--- a/lib/zap3/packets/v3.0/authenticationok.go
+++ /dev/null
@@ -1,24 +0,0 @@
-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
deleted file mode 100644
index eec9dc69d5e9ab2990dbafd78aadba07afb98d52..0000000000000000000000000000000000000000
--- a/lib/zap3/packets/v3.0/authenticationresponse.go
+++ /dev/null
@@ -1,17 +0,0 @@
-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
deleted file mode 100644
index dd9bc38e6b37b4b33a98978bdabe45d75a9b7dbd..0000000000000000000000000000000000000000
--- a/lib/zap3/packets/v3.0/authenticationsasl.go
+++ /dev/null
@@ -1,55 +0,0 @@
-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
deleted file mode 100644
index cf7f18ff42f1125f9d4e3a7d92137fa506370276..0000000000000000000000000000000000000000
--- a/lib/zap3/packets/v3.0/authenticationsaslcontinue.go
+++ /dev/null
@@ -1,27 +0,0 @@
-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
deleted file mode 100644
index b29ae94efd13ff8b0e3d01ce54ee487009e34ebb..0000000000000000000000000000000000000000
--- a/lib/zap3/packets/v3.0/authenticationsaslfinal.go
+++ /dev/null
@@ -1,25 +0,0 @@
-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
deleted file mode 100644
index 74040a54ce33a3eceb4331ba839cb81da2d144b5..0000000000000000000000000000000000000000
--- a/lib/zap3/packets/v3.0/backendkeydata.go
+++ /dev/null
@@ -1,22 +0,0 @@
-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
deleted file mode 100644
index 9691883930d7f2da0d67986cdae80bc471a5e43d..0000000000000000000000000000000000000000
--- a/lib/zap3/packets/v3.0/bind.go
+++ /dev/null
@@ -1,95 +0,0 @@
-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
deleted file mode 100644
index e382f3d3b65f8713910671e3b3eb0cbe2481d5ee..0000000000000000000000000000000000000000
--- a/lib/zap3/packets/v3.0/close.go
+++ /dev/null
@@ -1,26 +0,0 @@
-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
deleted file mode 100644
index a5b52fff301e9ab392a61d7c94ed8957defd79df..0000000000000000000000000000000000000000
--- a/lib/zap3/packets/v3.0/describe.go
+++ /dev/null
@@ -1,28 +0,0 @@
-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
deleted file mode 100644
index d6f36cd59e88479df8888188f9e8d353591c65e3..0000000000000000000000000000000000000000
--- a/lib/zap3/packets/v3.0/errorresponse.go
+++ /dev/null
@@ -1,76 +0,0 @@
-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
deleted file mode 100644
index 7fe488210c45ea31a7423b59c7de9da07c77515e..0000000000000000000000000000000000000000
--- a/lib/zap3/packets/v3.0/errors.go
+++ /dev/null
@@ -1,16 +0,0 @@
-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
deleted file mode 100644
index 7c32249a94cea7809e89b8e7223e3cbeb9e2a479..0000000000000000000000000000000000000000
--- a/lib/zap3/packets/v3.0/execute.go
+++ /dev/null
@@ -1,28 +0,0 @@
-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
deleted file mode 100644
index 73595713bb14c2490ccbc3559bc5245f70ca37a6..0000000000000000000000000000000000000000
--- a/lib/zap3/packets/v3.0/negotiateprotocolversion.go
+++ /dev/null
@@ -1,42 +0,0 @@
-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
deleted file mode 100644
index cff7246aa0c17a2a82ce6a401e12276285e246ef..0000000000000000000000000000000000000000
--- a/lib/zap3/packets/v3.0/parameterstatus.go
+++ /dev/null
@@ -1,26 +0,0 @@
-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
deleted file mode 100644
index 3d7c3f31be570c76bd26482a20cc7305014ccfd3..0000000000000000000000000000000000000000
--- a/lib/zap3/packets/v3.0/parse.go
+++ /dev/null
@@ -1,46 +0,0 @@
-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
deleted file mode 100644
index f777e94c95118f457b1e70ec426f00e8673ba746..0000000000000000000000000000000000000000
--- a/lib/zap3/packets/v3.0/passwordmessage.go
+++ /dev/null
@@ -1,23 +0,0 @@
-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
deleted file mode 100644
index f023ceb06cc5de23a20eee25300573e0a6d299b5..0000000000000000000000000000000000000000
--- a/lib/zap3/packets/v3.0/readyforquery.go
+++ /dev/null
@@ -1,23 +0,0 @@
-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
deleted file mode 100644
index 6cbcd94b694e7fcc5a74c19c931b8be81629a823..0000000000000000000000000000000000000000
--- a/lib/zap3/packets/v3.0/saslinitialresponse.go
+++ /dev/null
@@ -1,41 +0,0 @@
-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
deleted file mode 100644
index 68b3740658189194077803a62ce5e3d9e9d545a5..0000000000000000000000000000000000000000
--- a/lib/zap3/packets/v3.0/types.go
+++ /dev/null
@@ -1,43 +0,0 @@
-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
deleted file mode 100644
index 3ea1005b737d6994c39eb48ca87368fe62a4df12..0000000000000000000000000000000000000000
--- a/lib/zap3/reader.go
+++ /dev/null
@@ -1,24 +0,0 @@
-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
deleted file mode 100644
index b1abf1fbf98917212e0fdf6f95ecb84c93d5e03a..0000000000000000000000000000000000000000
--- a/lib/zap3/type.go
+++ /dev/null
@@ -1,3 +0,0 @@
-package zap3
-
-type Type int
diff --git a/lib/zap3/writer.go b/lib/zap3/writer.go
deleted file mode 100644
index 40fc38bfab22a391c1cecc0390e384ccf0b0b013..0000000000000000000000000000000000000000
--- a/lib/zap3/writer.go
+++ /dev/null
@@ -1,30 +0,0 @@
-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{}