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  }