package evalimport ()// Port conveys data stream. It always consists of a byte band and a channel band.typePortstruct {File *os.FileChanchaninterface{}closeFileboolcloseChanbool}// Returns a copy of the Port with the Close* flags unset.func ( *Port) () *Port {return &Port{.File, .Chan, false, false}}// Closes a Port.func ( *Port) () {if == nil {return }if .closeFile { .File.Close() }if .closeChan {close(.Chan) }}var (// ClosedChan is a closed channel, suitable as a placeholder input channel.ClosedChan = getClosedChan()// BlackholeChan is a channel that absorbs all values written to it, // suitable as a placeholder output channel.BlackholeChan = getBlackholeChan()// DevNull is /dev/null, suitable as a placeholder file for either input or // output.DevNull = getDevNull()// DummyInputPort is a port made up from DevNull and ClosedChan, suitable as // a placeholder input port.DummyInputPort = &Port{File: DevNull, Chan: ClosedChan}// DummyOutputPort is a port made up from DevNull and BlackholeChan, // suitable as a placeholder output port.DummyOutputPort = &Port{File: DevNull, Chan: BlackholeChan})func () chaninterface{} { := make(chaninterface{})close()return}func () chaninterface{} { := make(chaninterface{})gofunc() {forrange { } }()return}func () *os.File { , := os.Open(os.DevNull)if != nil {fmt.Fprintf(os.Stderr,"cannot open %s, shell might not function normally\n", os.DevNull) }return}// PipePort returns an output *Port whose value and byte components are both// piped. The supplied functions are called on a separate goroutine with the// read ends of the value and byte components of the port. It also returns a// function to clean up the port and wait for the callbacks to finish.func ( func(<-chaninterface{}), func(*os.File)) (*Port, func(), error) { , , := os.Pipe()if != nil {returnnil, nil, } := make(chaninterface{}, outputCaptureBufferSize)varsync.WaitGroup .Add(2)gofunc() {defer .Done() () }()gofunc() {defer .Done()defer .Close() () }() := &Port{Chan: , closeChan: true, File: , closeFile: true} := func() { .close() .Wait() }return , , nil}// CapturePort returns an output *Port whose value and byte components are// both connected to an internal pipe that saves the output. It also returns a// function to call to obtain the captured output.func () (*Port, func() []interface{}, error) { := []interface{}{}varsync.Mutex , , := PipePort(func( <-chaninterface{}) {for := range { .Lock() = append(, ) .Unlock() } },func( *os.File) { := bufio.NewReader()for { , := .ReadString('\n')if != "" { := strutil.ChopLineEnding() .Lock() = append(, ) .Unlock() }if != nil {if != io.EOF {logger.Println("error on reading:", ) }break } } })if != nil {returnnil, nil, }return , func() []interface{} { ()return }, nil}// StringCapturePort is like CapturePort, but processes value outputs by// stringifying them and prepending an output marker.func () (*Port, func() []string, error) {var []stringvarsync.Mutex := func( string) { .Lock()defer .Unlock() = append(, ) } , , := PipePort(func( <-chaninterface{}) {for := range { ("▶ " + vals.ToString()) } },func( *os.File) { := bufio.NewReader()for { , := .ReadString('\n')if != nil {if != io.EOF { ("i/o error: " + .Error()) }break } (strutil.ChopLineEnding()) } })if != nil {returnnil, nil, }return , func() []string { ()return }, nil}// Buffer size for the channel to use in FilePort. The value has been chosen// arbitrarily.constfilePortChanSize = 32// FilePort returns an output *Port where the byte component is the file itself,// and the value component is converted to an internal channel that writes// each value to the file, prepending with a prefix. It also returns a cleanup// function, which should be called when the *Port is no longer needed.func ( *os.File, string) (*Port, func()) { := make(chaninterface{}, filePortChanSize) := make(chanstruct{})gofunc() {for := range { .WriteString() .WriteString(vals.Repr(, vals.NoPretty)) .WriteString("\n") }close() }()return &Port{File: , Chan: }, func() {close() <- }}// PortsFromStdFiles is a shorthand for calling PortsFromFiles with os.Stdin,// os.Stdout and os.Stderr.func ( string) ([]*Port, func()) {returnPortsFromFiles([3]*os.File{os.Stdin, os.Stdout, os.Stderr}, )}// PortsFromFiles builds 3 ports from 3 files. It also returns a function that// should be called when the ports are no longer needed.func ( [3]*os.File, string) ([]*Port, func()) { , := FilePort([1], ) , := FilePort([2], )return []*Port{{File: [0], Chan: ClosedChan}, , }, func() { () () }}
The pages are generated with Goldsv0.2.8-preview. (GOOS=darwin GOARCH=arm64)