func New(size int) *pipe {
	p := &pipe{
		ch: make(chan *ipx.Packet, size),
	}
	return p
}
New returns a new pipe that buffers `size` number of writes internally.
This is conceptually similar to io.Pipe(), except for the differences
listed in the package description, and the fact that we return only a
single thing that implements both Reader and Writer.
package pipe
import (
	"context"
	"errors"
	"io"
	"sync"
	"github.com/fragglet/ipxbox/ipx"
)
var (
	_ = (ipx.ReadWriteCloser)(&pipe{})
	PipeFullError = errors.New("pipe buffer is full")
)
type pipe struct {
	ch     chan *ipx.Packet
	closed bool
	mu     sync.Mutex
}
func (p *pipe) Close() error {
	p.mu.Lock()
	defer p.mu.Unlock()
	if !p.closed {
		p.closed = true
		close(p.ch)
	}
	return nil
}
func (p *pipe) WritePacket(pkt *ipx.Packet) error {
	p.mu.Lock()
	defer p.mu.Unlock()
	if p.closed {
		return io.ErrClosedPipe
	}
	select {
	case p.ch <- pkt:
		return nil
	default:
		return PipeFullError
	}
}
func (p *pipe) ReadPacket(ctx context.Context) (*ipx.Packet, error) {
	p.mu.Lock()
	closed := p.closed
	p.mu.Unlock()
	if closed {
		return nil, io.ErrClosedPipe
	}
	select {
	case <-ctx.Done():
		return nil, ctx.Err()
	case pkt, ok := <-p.ch:
		if !ok {
			return nil, io.ErrClosedPipe
		}
		return pkt, nil
	}
}