// Copyright 2010 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 net

import (
	
	
	
	
)

// pipeDeadline is an abstraction for handling timeouts.
type pipeDeadline struct {
	mu     sync.Mutex // Guards timer and cancel
	timer  *time.Timer
	cancel chan struct{} // Must be non-nil
}

func makePipeDeadline() pipeDeadline {
	return pipeDeadline{cancel: make(chan struct{})}
}

// set sets the point in time when the deadline will time out.
// A timeout event is signaled by closing the channel returned by waiter.
// Once a timeout has occurred, the deadline can be refreshed by specifying a
// t value in the future.
//
// A zero value for t prevents timeout.
func ( *pipeDeadline) ( time.Time) {
	.mu.Lock()
	defer .mu.Unlock()

	if .timer != nil && !.timer.Stop() {
		<-.cancel // Wait for the timer callback to finish and close cancel
	}
	.timer = nil

	// Time is zero, then there is no deadline.
	 := isClosedChan(.cancel)
	if .IsZero() {
		if  {
			.cancel = make(chan struct{})
		}
		return
	}

	// Time in the future, setup a timer to cancel in the future.
	if  := time.Until();  > 0 {
		if  {
			.cancel = make(chan struct{})
		}
		.timer = time.AfterFunc(, func() {
			close(.cancel)
		})
		return
	}

	// Time in the past, so close immediately.
	if ! {
		close(.cancel)
	}
}

// wait returns a channel that is closed when the deadline is exceeded.
func ( *pipeDeadline) () chan struct{} {
	.mu.Lock()
	defer .mu.Unlock()
	return .cancel
}

func isClosedChan( <-chan struct{}) bool {
	select {
	case <-:
		return true
	default:
		return false
	}
}

type pipeAddr struct{}

func (pipeAddr) () string { return "pipe" }
func (pipeAddr) () string  { return "pipe" }

type pipe struct {
	wrMu sync.Mutex // Serialize Write operations

	// Used by local Read to interact with remote Write.
	// Successful receive on rdRx is always followed by send on rdTx.
	rdRx <-chan []byte
	rdTx chan<- int

	// Used by local Write to interact with remote Read.
	// Successful send on wrTx is always followed by receive on wrRx.
	wrTx chan<- []byte
	wrRx <-chan int

	once       sync.Once // Protects closing localDone
	localDone  chan struct{}
	remoteDone <-chan struct{}

	readDeadline  pipeDeadline
	writeDeadline pipeDeadline
}

// Pipe creates a synchronous, in-memory, full duplex
// network connection; both ends implement the [Conn] interface.
// Reads on one end are matched with writes on the other,
// copying data directly between the two; there is no internal
// buffering.
func () (Conn, Conn) {
	 := make(chan []byte)
	 := make(chan []byte)
	 := make(chan int)
	 := make(chan int)
	 := make(chan struct{})
	 := make(chan struct{})

	 := &pipe{
		rdRx: , rdTx: ,
		wrTx: , wrRx: ,
		localDone: , remoteDone: ,
		readDeadline:  makePipeDeadline(),
		writeDeadline: makePipeDeadline(),
	}
	 := &pipe{
		rdRx: , rdTx: ,
		wrTx: , wrRx: ,
		localDone: , remoteDone: ,
		readDeadline:  makePipeDeadline(),
		writeDeadline: makePipeDeadline(),
	}
	return , 
}

func (*pipe) () Addr  { return pipeAddr{} }
func (*pipe) () Addr { return pipeAddr{} }

func ( *pipe) ( []byte) (int, error) {
	,  := .read()
	if  != nil &&  != io.EOF &&  != io.ErrClosedPipe {
		 = &OpError{Op: "read", Net: "pipe", Err: }
	}
	return , 
}

func ( *pipe) ( []byte) ( int,  error) {
	switch {
	case isClosedChan(.localDone):
		return 0, io.ErrClosedPipe
	case isClosedChan(.remoteDone):
		return 0, io.EOF
	case isClosedChan(.readDeadline.wait()):
		return 0, os.ErrDeadlineExceeded
	}

	select {
	case  := <-.rdRx:
		 := copy(, )
		.rdTx <- 
		return , nil
	case <-.localDone:
		return 0, io.ErrClosedPipe
	case <-.remoteDone:
		return 0, io.EOF
	case <-.readDeadline.wait():
		return 0, os.ErrDeadlineExceeded
	}
}

func ( *pipe) ( []byte) (int, error) {
	,  := .write()
	if  != nil &&  != io.ErrClosedPipe {
		 = &OpError{Op: "write", Net: "pipe", Err: }
	}
	return , 
}

func ( *pipe) ( []byte) ( int,  error) {
	switch {
	case isClosedChan(.localDone):
		return 0, io.ErrClosedPipe
	case isClosedChan(.remoteDone):
		return 0, io.ErrClosedPipe
	case isClosedChan(.writeDeadline.wait()):
		return 0, os.ErrDeadlineExceeded
	}

	.wrMu.Lock() // Ensure entirety of b is written together
	defer .wrMu.Unlock()
	for  := true;  || len() > 0;  = false {
		select {
		case .wrTx <- :
			 := <-.wrRx
			 = [:]
			 += 
		case <-.localDone:
			return , io.ErrClosedPipe
		case <-.remoteDone:
			return , io.ErrClosedPipe
		case <-.writeDeadline.wait():
			return , os.ErrDeadlineExceeded
		}
	}
	return , nil
}

func ( *pipe) ( time.Time) error {
	if isClosedChan(.localDone) || isClosedChan(.remoteDone) {
		return io.ErrClosedPipe
	}
	.readDeadline.set()
	.writeDeadline.set()
	return nil
}

func ( *pipe) ( time.Time) error {
	if isClosedChan(.localDone) || isClosedChan(.remoteDone) {
		return io.ErrClosedPipe
	}
	.readDeadline.set()
	return nil
}

func ( *pipe) ( time.Time) error {
	if isClosedChan(.localDone) || isClosedChan(.remoteDone) {
		return io.ErrClosedPipe
	}
	.writeDeadline.set()
	return nil
}

func ( *pipe) () error {
	.once.Do(func() { close(.localDone) })
	return nil
}