github.com/hirochachacha/plua@v0.0.0-20170217012138-c82f520cc725/object/reflect/chan.go (about) 1 package reflect 2 3 import ( 4 "fmt" 5 "reflect" 6 7 "github.com/hirochachacha/plua/internal/tables" 8 "github.com/hirochachacha/plua/object" 9 "github.com/hirochachacha/plua/object/fnutil" 10 ) 11 12 func buildChanMT() { 13 mt := tables.NewTableSize(0, 6) 14 15 mt.Set(object.TM_METATABLE, object.True) 16 mt.Set(object.TM_NAME, object.String("CHAN*")) 17 mt.Set(object.TM_TOSTRING, object.GoFunction(ctostring)) 18 mt.Set(object.TM_INDEX, object.GoFunction(cindex)) 19 20 mt.Set(object.TM_LEN, object.GoFunction(clength)) 21 mt.Set(object.TM_PAIRS, object.GoFunction(cpairs)) 22 23 mt.Set(object.TM_EQ, cmp(func(x, y reflect.Value) bool { return x.Pointer() == y.Pointer() }, toChan)) 24 25 chanMT = mt 26 } 27 28 func toChan(ap *fnutil.ArgParser, n int) (reflect.Value, *object.RuntimeError) { 29 val, err := toValue(ap, n, "CHAN*") 30 if err != nil { 31 return reflect.Value{}, err 32 } 33 if val.Kind() != reflect.Chan { 34 return reflect.Value{}, ap.TypeError(n, "CHAN*") 35 } 36 return val, nil 37 } 38 39 func ctostring(th object.Thread, args ...object.Value) ([]object.Value, *object.RuntimeError) { 40 ap := fnutil.NewArgParser(th, args) 41 42 ch, err := toChan(ap, 0) 43 if err != nil { 44 return nil, err 45 } 46 47 return []object.Value{object.String(fmt.Sprintf("go channel (0x%x)", ch.Pointer()))}, nil 48 } 49 50 func cindex(th object.Thread, args ...object.Value) ([]object.Value, *object.RuntimeError) { 51 ap := fnutil.NewArgParser(th, args) 52 53 ch, err := toChan(ap, 0) 54 if err != nil { 55 return nil, err 56 } 57 58 name, err := ap.ToGoString(1) 59 if err != nil { 60 return nil, err 61 } 62 63 if !isPublic(name) { 64 switch name { 65 case "send": 66 return []object.Value{object.GoFunction(csend)}, nil 67 case "recv": 68 return []object.Value{object.GoFunction(crecv)}, nil 69 case "close": 70 return []object.Value{object.GoFunction(cclose)}, nil 71 } 72 73 return nil, nil 74 } 75 76 method := ch.MethodByName(name) 77 78 if !method.IsValid() { 79 if ch.CanAddr() { 80 method = ch.Addr().MethodByName(name) 81 } else { 82 self2 := reflect.New(ch.Type()) 83 self2.Elem().Set(ch) 84 method = self2.MethodByName(name) 85 } 86 87 if !method.IsValid() { 88 return nil, nil 89 } 90 } 91 92 return []object.Value{valueOfReflect(method, false)}, nil 93 } 94 95 func clength(th object.Thread, args ...object.Value) ([]object.Value, *object.RuntimeError) { 96 ap := fnutil.NewArgParser(th, args) 97 98 ch, err := toChan(ap, 0) 99 if err != nil { 100 return nil, err 101 } 102 103 return []object.Value{object.Integer(ch.Len())}, nil 104 } 105 106 func csend(th object.Thread, args ...object.Value) ([]object.Value, *object.RuntimeError) { 107 ap := fnutil.NewArgParser(th, args) 108 109 ch, err := toChan(ap, 0) 110 if err != nil { 111 return nil, err 112 } 113 114 x, err := ap.ToValue(1) 115 if err != nil { 116 return nil, err 117 } 118 119 styp := ch.Type() 120 vtyp := styp.Elem() 121 122 if x := toReflectValue(vtyp, x); x.IsValid() { 123 ch.Send(x) 124 125 return nil, nil 126 } 127 128 return nil, object.NewRuntimeError(fmt.Sprintf("cannot use %v (type %s) as type %s in send", x, reflect.TypeOf(x), vtyp)) 129 } 130 131 func crecv(th object.Thread, args ...object.Value) ([]object.Value, *object.RuntimeError) { 132 ap := fnutil.NewArgParser(th, args) 133 134 ch, err := toChan(ap, 0) 135 if err != nil { 136 return nil, err 137 } 138 139 rval, ok := ch.Recv() 140 if !ok { 141 return []object.Value{nil, object.False}, nil 142 } 143 144 return []object.Value{valueOfReflect(rval, false), object.True}, nil 145 } 146 147 func cclose(th object.Thread, args ...object.Value) ([]object.Value, *object.RuntimeError) { 148 ap := fnutil.NewArgParser(th, args) 149 150 ch, err := toChan(ap, 0) 151 if err != nil { 152 return nil, err 153 } 154 155 ch.Close() 156 157 return nil, nil 158 } 159 160 func cpairs(th object.Thread, args ...object.Value) ([]object.Value, *object.RuntimeError) { 161 ap := fnutil.NewArgParser(th, args) 162 163 _, err := toChan(ap, 0) 164 if err != nil { 165 return nil, err 166 } 167 168 return []object.Value{object.GoFunction(cnext), args[0]}, nil 169 } 170 171 func cnext(th object.Thread, args ...object.Value) ([]object.Value, *object.RuntimeError) { 172 ap := fnutil.NewArgParser(th, args) 173 174 ch, err := toChan(ap, 0) 175 if err != nil { 176 return nil, err 177 } 178 179 rval, ok := ch.Recv() 180 if !ok { 181 return nil, nil 182 } 183 184 return []object.Value{nil, valueOfReflect(rval, false)}, nil 185 }