xyselect

package
v1.0.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 21, 2022 License: MIT Imports: 4 Imported by: 0

README

Introduction

Xyselect is a library used to call select with an unknown number of case statements.

Features

The main object in the library is Selector, a custom usage of select statement.

There are two types of Selector, which are R (stand for reflect) and E (stand for exhausted).

E selector uses a center channel to receive all selected channels, so that it doesn't support to wait on a sending channel. Moreover, E selector creates a goroutine to wait on the center channel, and that goroutine only stops when all selected channels closed. For this reason, you should call Select until get an error of ExhaustedError to ensure the goroutine stopped.

R selector uses the built-in library, reflect, to customize select statement. It supports to wait on both receiving and sending channels. It also does not create any goroutine while using.

Each selector has its own advantage, while R selector more flexible, E selector is faster.

Visit pkg.go.dev for more details.

Benchmark

op name time per op
RSelector 728ns
ESelector 679ns

Example

var c = make(chan int)
go func() { 
    c <- 10
    close(c)
}()

var eselector = xyselect.E()
eselector.Recv(xyselect.C(c))

var _, v, _ = eselector.Select(false)
fmt.Println(v)

// Output:
// 10
var rselector = xyselect.R()
var c = make(chan int)
var rc = xyselect.C(c)

go func() { c <- 10 }()
rselector.Recv(rc)
var _, v, _ = rselector.Select(false)
fmt.Println("receive", v)

rselector.Send(c, 20)
rselector.Select(false)
fmt.Println("send", <-rc)

// Output:
// receive 10
// send 20

Documentation

Index

Examples

Constants

This section is empty.

Variables

View Source
var (
	SelectorError      = egen.NewClass("SelectorError")
	ClosedChannelError = SelectorError.NewClass("ClosedChannelError")
	ExhaustedError     = SelectorError.NewClass("ExhaustedError")
)

Functions

func C

func C[T any](c <-chan T) <-chan any

C creates a read-only chan any from read-only chan T. This channel is only closed when c channel is closed.

Types

type Selector

type Selector struct {
	// contains filtered or unexported fields
}

Selector is the struct supporting thread-safe, type-safe selector.

func E

func E() *Selector

IMPORTANT: ONLY use this selector if (1) exhausted-select, a type of select which is only stopped when all channels are closed, if the selector is exhausted, the error returned in Select() method will be StoppedError; (2) only receiving cases.

ESelector is the exhausted-version selector. Its workflow is that all channels will send its received values to a center channel. Instead of calling select statement with all channels, you only need to receive on the center one.

When ESelector adds a case of channel, it creates a goroutine which receives values of that channel until it is closed. For a received value, the goroutine will send that value to the center channel.

The center channel is only closed if all channel-cases are closed. This is the reason why you must call Select until there is no any alive channel.

Example
package main

import (
	"fmt"

	"github.com/xybor/xyplatform/xyselect"
)

func main() {
	var c = make(chan int)
	go func() {
		c <- 10
		close(c)
	}()

	var eselector = xyselect.E()
	eselector.Recv(xyselect.C(c))

	var _, v, _ = eselector.Select(false)
	fmt.Println(v)

}
Output:

10

func R

func R() *Selector

RSelector is the reflect-version selector. It uses reflect module to handle customized select statement.

Example
package main

import (
	"fmt"

	"github.com/xybor/xyplatform/xyselect"
)

func main() {
	var rselector = xyselect.R()
	var c = make(chan int)
	var rc = xyselect.C(c)

	go func() { c <- 10 }()
	rselector.Recv(rc)
	var _, v, _ = rselector.Select(false)
	fmt.Println("receive", v)

	rselector.Send(c, 20)
	rselector.Select(false)
	fmt.Println("send", <-rc)

}
Output:

receive 10
send 20

func (*Selector) Recv

func (s *Selector) Recv(c <-chan any) int

Recv adds a receiving case to selector. If the channel is not the type of chan any, using xyselector.C to cast it. This method returns the index of the added case. The received value is returned by the second parameter of Select() method.

For example:

var c1 = make(chan any)
var c2 = make(chan int)
selector.Recv(c1)
selector.Recv(xyselector.C(c2))

func (*Selector) Select

func (s *Selector) Select(isDefault bool) (index int, v any, err error)

Select executes a select operation described by the list of cases in selector.

Like the Go select statement, it blocks until at least one of the cases can proceed and then executes that case. If isDefault is true, it will be the non-blocking select.

It returns the index of the chosen case (-1 if default case), the value received, and a error of selector. Nil for the case of receiving is not closed. ClosedChannelError if the channel is closed in receiving case, ExhaustedError if there is no more available channel in exhausted-selector.

func (*Selector) Send

func (s *Selector) Send(c any, v any) int

Send adds a sending case to selector. The first parameter c must be a writable channel. This method returns the index of the added case.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL