Example #1
0
func loop(rc reflect.Value, wc reflect.Value) {
	readCase := reflect.SelectCase{}
	readCase.Dir = reflect.SelectRecv
	readCase.Chan = wc

	writeCase := reflect.SelectCase{}
	writeCase.Dir = reflect.SelectSend
	writeCase.Chan = rc

	cases := []reflect.SelectCase{readCase, writeCase}

	l := list.New()

	for {
		tc := cases[:1]
		if l.Len() > 0 {
			writeCase.Send = reflect.ValueOf(l.Front().Value)
			cases[1] = writeCase
			tc = cases[:2]
		}

		idx, v, ok := reflect.Select(tc)
		if idx == 0 {
			if ok {
				l.PushBack(v.Interface())
			} else {
				//channel closed
				log.Println("Read channel closed")
				break
			}
		} else if idx == 1 {
			l.Remove(l.Front())
		}
	}
}
Example #2
0
func channelSelect(L *LState) int {
	//TODO check case table size
	cases := make([]reflect.SelectCase, L.GetTop())
	top := L.GetTop()
	for i := 0; i < top; i++ {
		cas := reflect.SelectCase{reflect.SelectSend, reflect.ValueOf(nil), reflect.ValueOf(nil)}
		tbl := L.CheckTable(i + 1)
		dir, ok1 := tbl.RawGetInt(1).(LString)
		if !ok1 {
			L.ArgError(i+1, "invalid select case")
		}
		switch string(dir) {
		case "<-|":
			ch, ok := tbl.RawGetInt(2).(LChannel)
			if !ok {
				L.ArgError(i+1, "invalid select case")
			}
			cas.Chan = reflect.ValueOf((chan LValue)(ch))
			v := tbl.RawGetInt(3)
			if !isGoroutineSafe(v) {
				L.ArgError(i+1, "can not send a function, userdata, thread or table that has a metatable")
			}
			cas.Send = reflect.ValueOf(v)
		case "|<-":
			ch, ok := tbl.RawGetInt(2).(LChannel)
			if !ok {
				L.ArgError(i+1, "invalid select case")
			}
			cas.Chan = reflect.ValueOf((chan LValue)(ch))
			cas.Dir = reflect.SelectRecv
		case "default":
			cas.Dir = reflect.SelectDefault
		default:
			L.ArgError(i+1, "invalid channel direction:"+string(dir))
		}
		cases[i] = cas
	}

	pos, recv, rok := reflect.Select(cases)
	lv := LNil
	if recv.Kind() != 0 {
		lv, _ = recv.Interface().(LValue)
		if lv == nil {
			lv = LNil
		}
	}
	tbl := L.Get(pos + 1).(*LTable)
	last := tbl.RawGetInt(tbl.Len())
	if last.Type() == LTFunction {
		L.Push(last)
		switch cases[pos].Dir {
		case reflect.SelectRecv:
			if rok {
				L.Push(LTrue)
			} else {
				L.Push(LFalse)
			}
			L.Push(lv)
			L.Call(2, 0)
		case reflect.SelectSend:
			L.Push(tbl.RawGetInt(3))
			L.Call(1, 0)
		case reflect.SelectDefault:
			L.Call(0, 0)
		}
	}
	L.Push(LNumber(pos + 1))
	L.Push(lv)
	if rok {
		L.Push(LTrue)
	} else {
		L.Push(LFalse)
	}
	return 3
}