// Copyright 2026 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package nettest

import (
	
	
	
	
	
	
	
	
)

// Conn is an in-memory test implementation of net.Conn.
type Conn struct {
	// Conns come in pairs.
	// Writes to one Conn are read by its peer, and vice-versa.
	//
	// A connHalf handles one direction of data flow.
	// A Conn consists of read and write halves.
	// A Conn's peer has the same halves, only swapped.
	//
	// A Conn reads from r and writes to w.
	r, w *connHalf

	// peer is the other endpoint.
	peer *Conn
}

// NewConnPair returns a pair of connected Conns.
func () (*Conn, *Conn) {
	return newConnPair(
		net.TCPAddrFromAddrPort(netip.MustParseAddrPort("192.0.2.1:10000")),
		net.TCPAddrFromAddrPort(netip.MustParseAddrPort("192.0.2.1:10001")),
	)
}

func newConnPair(,  net.Addr) (*Conn, *Conn) {
	 := newConnHalf()
	 := newConnHalf()
	 := &Conn{r: , w: }
	 := &Conn{r: , w: }
	.peer = 
	.peer = 
	.SetReadBufferSize(-1)
	.SetReadBufferSize(-1)
	return , 
}

// Peer returns the other end of the connection.
func ( *Conn) () *Conn {
	return .peer
}

// Read reads data from the connection.
func ( *Conn) ( []byte) ( int,  error) {
	,  = .r.read()
	if  != nil &&  != io.EOF {
		 = &net.OpError{
			Op:     "read",
			Net:    "tcp",
			Source: .RemoteAddr(),
			Addr:   .LocalAddr(),
			Err:    ,
		}
	}
	return , 
}

// CanRead reports whether Read can proceed without blocking.
func ( *Conn) () bool {
	return .r.canRead()
}

// Write writes data to the connection.
func ( *Conn) ( []byte) ( int,  error) {
	,  = .w.write()
	if  != nil {
		 = &net.OpError{
			Op:     "write",
			Net:    "tcp",
			Source: .LocalAddr(),
			Addr:   .RemoteAddr(),
			Err:    ,
		}
	}
	return , 
}

// IsClosed reports whether the connection has been closed.
// A connection is closed if [CloseRead] and [CloseWrite] are both called,
// or if [Close] is called.
//
// To identify when the other side of the Conn has been closed,
// use Conn.Peer().IsClosed().
func ( *Conn) () bool {
	.r.lock()
	 := .r.readClosed
	.r.unlock()
	.w.lock()
	 := .w.writeClosed
	.w.unlock()
	return  && 
}

var errClosedByPeer = errors.New("connection closed by peer")

// CloseRead shuts down the reading side of the connection.
func ( *Conn) () error {
	.r.lock()
	defer .r.unlock()
	.r.buf.Reset() // discard unread data
	.r.readClosed = true
	return nil
}

// CloseWrite shuts down the writing side of the connection.
func ( *Conn) () error {
	.w.lock()
	defer .w.unlock()
	.w.writeClosed = true
	return nil
}

// Close closes the connection.
func ( *Conn) () error {
	.r.lock()
	 := .r.readClosed
	.r.buf.Reset() // discard unread data
	.r.readClosed = true
	 := .r.closeErr
	.r.unlock()

	.w.lock()
	 := .w.writeClosed
	.w.writeClosed = true
	.w.unlock()

	if  &&  {
		 = net.ErrClosed
	}
	if  != nil {
		 = &net.OpError{
			Op:   "close",
			Net:  "tcp",
			Addr: .LocalAddr(),
			Err:  ,
		}
	}
	return 
}

// SetCloseError sets the error returned by Close.
// Close still closes the connection.
// A nil error restores the usual behavior.
func ( *Conn) ( error) {
	.r.lock()
	.r.closeErr = 
	.r.unlock()
}

// LocalAddr returns the (fake) local network address.
func ( *Conn) () net.Addr {
	.r.lock()
	defer .r.unlock()
	return .r.addr
}

// SetLocalAddr sets the local address.
//
// To set the remote address, set the local address of Conn's peer.
func ( *Conn) ( net.Addr) {
	.r.lock()
	defer .r.unlock()
	.r.addr = 
}

// LocalAddr returns the (fake) remote network address.
func ( *Conn) () net.Addr {
	.r.lock()
	defer .r.unlock()
	return .w.addr
}

// SetDeadline sets the read and write deadlines for the connection.
func ( *Conn) ( time.Time) error {
	.SetReadDeadline()
	.SetWriteDeadline()
	return nil
}

// SetReadDeadline sets the read deadline for the connection.
func ( *Conn) ( time.Time) error {
	.r.readDeadline.setDeadline(.r, )
	return nil
}

// SetWriteDeadline sets the write deadline for the connection.
func ( *Conn) ( time.Time) error {
	.w.writeDeadline.setDeadline(.w, )
	return nil
}

// SetReadBufferSize sets the connection's read buffer.
// Writes to the other end of the connection will block so long as the buffer is full.
// Setting the size to 0 blocks all writes until the size is increased.
func ( *Conn) ( int) {
	if  < 0 {
		 = math.MaxInt
	}
	.r.setBufferSize()
}

// SetReadError causes any currently blocked and future Read calls to return
// a net.OpError wrapping err. It does not affect the other half of the connection.
// Reads will return any buffered data before returning the error,
// including data written after the error is set and io.EOF after the other end is closed.
// A nil error restores the usual behavior.
func ( *Conn) ( error) {
	.r.lock()
	defer .r.unlock()
	.r.readErr = 
}

// SetWriteError causes any currently blocked and future Write calls to return
// a net.OpError wrapping err. It does not affect the other half of the connection.
// Writes will not write data to the connection buffer while an error is set.
// A nil error restores the usual behavior.
func ( *Conn) ( error) {
	.w.lock()
	defer .w.unlock()
	.w.writeErr = 
}

// connHalf is one direction data flow in a Conn.
// The connHalf contains a buffer.
// Writes to the connHalf push to the buffer and reads pull from it.
type connHalf struct {
	addr net.Addr

	// A half can be readable and/or writable.
	//
	// These four channels act as a lock,
	// and allow waiting for readability/writability.
	// When the half is unlocked, exactly one channel contains a value.
	// When the half is locked, all channels are empty.
	lockr  chan struct{} // readable
	lockw  chan struct{} // writable
	lockrw chan struct{} // readable and writable
	lockc  chan struct{} // neither readable nor writable

	// Read and write timeouts.
	readDeadline, writeDeadline connDeadline

	bufMax int // maximum buffer size
	buf    bytes.Buffer

	readClosed, writeClosed bool
	readErr, writeErr       error // errors returned by reads/writes
	closeErr                error // error returned by closing the conn reading from this half
}

func newConnHalf( net.Addr) *connHalf {
	 := &connHalf{
		addr:   ,
		lockw:  make(chan struct{}, 1),
		lockr:  make(chan struct{}, 1),
		lockrw: make(chan struct{}, 1),
		lockc:  make(chan struct{}, 1),
		bufMax: math.MaxInt, // unlimited
	}
	.unlock()
	return 
}

// lock locks h.
func ( *connHalf) () {
	select {
	case <-.lockw: // writable
	case <-.lockr: // readable
	case <-.lockrw: // readable and writable
	case <-.lockc: // neither readable nor writable
	}
}

// unlock unlocks h.
func ( *connHalf) () {
	 := .canReadLocked()
	 := .canWriteLocked()
	switch {
	case  && :
		.lockrw <- struct{}{} // readable and writable
	case :
		.lockr <- struct{}{} // readable
	case :
		.lockw <- struct{}{} // writable
	default:
		.lockc <- struct{}{} // neither readable nor writable
	}
}

func ( *connHalf) () bool {
	.lock()
	defer .unlock()
	return .canReadLocked()
}

func ( *connHalf) () bool {
	return .readErr != nil || .readDeadline.expired || .buf.Len() > 0 || .readClosed || .writeClosed
}

func ( *connHalf) () bool {
	return .writeErr != nil || .writeDeadline.expired || .bufMax > .buf.Len() || .readClosed || .writeClosed
}

// waitAndLockForRead waits until h is readable and locks it.
func ( *connHalf) () {
	select {
	case <-.lockr:
		// readable
	case <-.lockrw:
		// readable and writable
	}
}

// waitAndLockForWrite waits until h is writable and locks it.
func ( *connHalf) () {
	select {
	case <-.lockw:
		// writable
	case <-.lockrw:
		// readable and writable
	}
}

func ( *connHalf) ( []byte) ( int,  error) {
	.waitAndLockForRead()
	defer .unlock()
	if .readClosed {
		return 0, net.ErrClosed
	}
	if .readDeadline.expired {
		return 0, os.ErrDeadlineExceeded
	}
	if .buf.Len() > 0 {
		return .buf.Read()
	}
	if .writeClosed {
		return 0, io.EOF
	}
	return 0, .readErr
}

func ( *connHalf) ( int) {
	.lock()
	defer .unlock()
	.bufMax = 
}

func ( *connHalf) ( []byte) ( int,  error) {
	for  < len() {
		,  := .writePartial([:])
		 += 
		if  != nil {
			return , 
		}
	}
	return , nil
}

func ( *connHalf) ( []byte) ( int,  error) {
	.waitAndLockForWrite()
	defer .unlock()
	if .writeClosed {
		return 0, net.ErrClosed
	}
	if .writeDeadline.expired {
		return 0, os.ErrDeadlineExceeded
	}
	if .readClosed {
		return 0, errClosedByPeer
	}
	if .writeErr != nil {
		return 0, .writeErr
	}
	 := .bufMax - .buf.Len()
	if  < len() {
		 = [:]
	}
	return .buf.Write()
}

type connDeadline struct {
	timer   *time.Timer
	expired bool
}

type locker interface {
	lock()
	unlock()
}

func ( *connDeadline) ( locker,  time.Time) {
	.lock()
	defer .unlock()
	if .timer != nil {
		.timer.Stop()
		.timer = nil
	}
	if .IsZero() {
		// No deadline.
		.expired = false
		return
	}
	 := time.Until()
	if  <= 0 {
		// Deadline has already passed.
		.expired = true
		return
	}
	// Deadline is in the future.
	.expired = false
	var  *time.Timer
	 = time.AfterFunc(, func() {
		.lock()
		defer .unlock()
		if .timer ==  {
			.timer = nil
			.expired = true
		}
	})
	.timer = 
}