channellib.go 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184
  1. package lua
  2. import (
  3. "reflect"
  4. )
  5. func checkChannel(L *LState, idx int) reflect.Value {
  6. ch := L.CheckChannel(idx)
  7. return reflect.ValueOf(ch)
  8. }
  9. func checkGoroutineSafe(L *LState, idx int) LValue {
  10. v := L.CheckAny(2)
  11. if !isGoroutineSafe(v) {
  12. L.ArgError(2, "can not send a function, userdata, thread or table that has a metatable")
  13. }
  14. return v
  15. }
  16. func OpenChannel(L *LState) int {
  17. var mod LValue
  18. //_, ok := L.G.builtinMts[int(LTChannel)]
  19. // if !ok {
  20. mod = L.RegisterModule(ChannelLibName, channelFuncs)
  21. mt := L.SetFuncs(L.NewTable(), channelMethods)
  22. mt.RawSetString("__index", mt)
  23. L.G.builtinMts[int(LTChannel)] = mt
  24. // }
  25. L.Push(mod)
  26. return 1
  27. }
  28. var channelFuncs = map[string]LGFunction{
  29. "make": channelMake,
  30. "select": channelSelect,
  31. }
  32. func channelMake(L *LState) int {
  33. buffer := L.OptInt(1, 0)
  34. L.Push(LChannel(make(chan LValue, buffer)))
  35. return 1
  36. }
  37. func channelSelect(L *LState) int {
  38. //TODO check case table size
  39. cases := make([]reflect.SelectCase, L.GetTop())
  40. top := L.GetTop()
  41. for i := 0; i < top; i++ {
  42. cas := reflect.SelectCase{
  43. Dir: reflect.SelectSend,
  44. Chan: reflect.ValueOf(nil),
  45. Send: reflect.ValueOf(nil),
  46. }
  47. tbl := L.CheckTable(i + 1)
  48. dir, ok1 := tbl.RawGetInt(1).(LString)
  49. if !ok1 {
  50. L.ArgError(i+1, "invalid select case")
  51. }
  52. switch string(dir) {
  53. case "<-|":
  54. ch, ok := tbl.RawGetInt(2).(LChannel)
  55. if !ok {
  56. L.ArgError(i+1, "invalid select case")
  57. }
  58. cas.Chan = reflect.ValueOf((chan LValue)(ch))
  59. v := tbl.RawGetInt(3)
  60. if !isGoroutineSafe(v) {
  61. L.ArgError(i+1, "can not send a function, userdata, thread or table that has a metatable")
  62. }
  63. cas.Send = reflect.ValueOf(v)
  64. case "|<-":
  65. ch, ok := tbl.RawGetInt(2).(LChannel)
  66. if !ok {
  67. L.ArgError(i+1, "invalid select case")
  68. }
  69. cas.Chan = reflect.ValueOf((chan LValue)(ch))
  70. cas.Dir = reflect.SelectRecv
  71. case "default":
  72. cas.Dir = reflect.SelectDefault
  73. default:
  74. L.ArgError(i+1, "invalid channel direction:"+string(dir))
  75. }
  76. cases[i] = cas
  77. }
  78. if L.ctx != nil {
  79. cases = append(cases, reflect.SelectCase{
  80. Dir: reflect.SelectRecv,
  81. Chan: reflect.ValueOf(L.ctx.Done()),
  82. Send: reflect.ValueOf(nil),
  83. })
  84. }
  85. pos, recv, rok := reflect.Select(cases)
  86. if L.ctx != nil && pos == L.GetTop() {
  87. return 0
  88. }
  89. lv := LNil
  90. if recv.Kind() != 0 {
  91. lv, _ = recv.Interface().(LValue)
  92. if lv == nil {
  93. lv = LNil
  94. }
  95. }
  96. tbl := L.Get(pos + 1).(*LTable)
  97. last := tbl.RawGetInt(tbl.Len())
  98. if last.Type() == LTFunction {
  99. L.Push(last)
  100. switch cases[pos].Dir {
  101. case reflect.SelectRecv:
  102. if rok {
  103. L.Push(LTrue)
  104. } else {
  105. L.Push(LFalse)
  106. }
  107. L.Push(lv)
  108. L.Call(2, 0)
  109. case reflect.SelectSend:
  110. L.Push(tbl.RawGetInt(3))
  111. L.Call(1, 0)
  112. case reflect.SelectDefault:
  113. L.Call(0, 0)
  114. }
  115. }
  116. L.Push(LNumber(pos + 1))
  117. L.Push(lv)
  118. if rok {
  119. L.Push(LTrue)
  120. } else {
  121. L.Push(LFalse)
  122. }
  123. return 3
  124. }
  125. var channelMethods = map[string]LGFunction{
  126. "receive": channelReceive,
  127. "send": channelSend,
  128. "close": channelClose,
  129. }
  130. func channelReceive(L *LState) int {
  131. rch := checkChannel(L, 1)
  132. var v reflect.Value
  133. var ok bool
  134. if L.ctx != nil {
  135. cases := []reflect.SelectCase{{
  136. Dir: reflect.SelectRecv,
  137. Chan: reflect.ValueOf(L.ctx.Done()),
  138. Send: reflect.ValueOf(nil),
  139. }, {
  140. Dir: reflect.SelectRecv,
  141. Chan: rch,
  142. Send: reflect.ValueOf(nil),
  143. }}
  144. _, v, ok = reflect.Select(cases)
  145. } else {
  146. v, ok = rch.Recv()
  147. }
  148. if ok {
  149. L.Push(LTrue)
  150. L.Push(v.Interface().(LValue))
  151. } else {
  152. L.Push(LFalse)
  153. L.Push(LNil)
  154. }
  155. return 2
  156. }
  157. func channelSend(L *LState) int {
  158. rch := checkChannel(L, 1)
  159. v := checkGoroutineSafe(L, 2)
  160. rch.Send(reflect.ValueOf(v))
  161. return 0
  162. }
  163. func channelClose(L *LState) int {
  164. rch := checkChannel(L, 1)
  165. rch.Close()
  166. return 0
  167. }
  168. //