channellib.go 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152
  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{reflect.SelectSend, reflect.ValueOf(nil), reflect.ValueOf(nil)}
  43. tbl := L.CheckTable(i + 1)
  44. dir, ok1 := tbl.RawGetInt(1).(LString)
  45. if !ok1 {
  46. L.ArgError(i+1, "invalid select case")
  47. }
  48. switch string(dir) {
  49. case "<-|":
  50. ch, ok := tbl.RawGetInt(2).(LChannel)
  51. if !ok {
  52. L.ArgError(i+1, "invalid select case")
  53. }
  54. cas.Chan = reflect.ValueOf((chan LValue)(ch))
  55. v := tbl.RawGetInt(3)
  56. if !isGoroutineSafe(v) {
  57. L.ArgError(i+1, "can not send a function, userdata, thread or table that has a metatable")
  58. }
  59. cas.Send = reflect.ValueOf(v)
  60. case "|<-":
  61. ch, ok := tbl.RawGetInt(2).(LChannel)
  62. if !ok {
  63. L.ArgError(i+1, "invalid select case")
  64. }
  65. cas.Chan = reflect.ValueOf((chan LValue)(ch))
  66. cas.Dir = reflect.SelectRecv
  67. case "default":
  68. cas.Dir = reflect.SelectDefault
  69. default:
  70. L.ArgError(i+1, "invalid channel direction:"+string(dir))
  71. }
  72. cases[i] = cas
  73. }
  74. pos, recv, rok := reflect.Select(cases)
  75. lv := LNil
  76. if recv.Kind() != 0 {
  77. lv, _ = recv.Interface().(LValue)
  78. if lv == nil {
  79. lv = LNil
  80. }
  81. }
  82. tbl := L.Get(pos + 1).(*LTable)
  83. last := tbl.RawGetInt(tbl.Len())
  84. if last.Type() == LTFunction {
  85. L.Push(last)
  86. switch cases[pos].Dir {
  87. case reflect.SelectRecv:
  88. if rok {
  89. L.Push(LTrue)
  90. } else {
  91. L.Push(LFalse)
  92. }
  93. L.Push(lv)
  94. L.Call(2, 0)
  95. case reflect.SelectSend:
  96. L.Push(tbl.RawGetInt(3))
  97. L.Call(1, 0)
  98. case reflect.SelectDefault:
  99. L.Call(0, 0)
  100. }
  101. }
  102. L.Push(LNumber(pos + 1))
  103. L.Push(lv)
  104. if rok {
  105. L.Push(LTrue)
  106. } else {
  107. L.Push(LFalse)
  108. }
  109. return 3
  110. }
  111. var channelMethods = map[string]LGFunction{
  112. "receive": channelReceive,
  113. "send": channelSend,
  114. "close": channelClose,
  115. }
  116. func channelReceive(L *LState) int {
  117. rch := checkChannel(L, 1)
  118. v, ok := rch.Recv()
  119. if ok {
  120. L.Push(LTrue)
  121. L.Push(v.Interface().(LValue))
  122. } else {
  123. L.Push(LFalse)
  124. L.Push(LNil)
  125. }
  126. return 2
  127. }
  128. func channelSend(L *LState) int {
  129. rch := checkChannel(L, 1)
  130. v := checkGoroutineSafe(L, 2)
  131. rch.Send(reflect.ValueOf(v))
  132. return 0
  133. }
  134. func channelClose(L *LState) int {
  135. rch := checkChannel(L, 1)
  136. rch.Close()
  137. return 0
  138. }
  139. //