//export ToMsgpack func ToMsgpack(s C.SEXP) C.SEXP { byteSlice := encodeRIntoMsgpack(s) if len(byteSlice) == 0 { return C.R_NilValue } rawmsg := C.allocVector(C.RAWSXP, C.R_xlen_t(len(byteSlice))) C.Rf_protect(rawmsg) C.memcpy(unsafe.Pointer(C.RAW(rawmsg)), unsafe.Pointer(&byteSlice[0]), C.size_t(len(byteSlice))) C.Rf_unprotect(1) return rawmsg }
//export FromMsgpack func FromMsgpack(s C.SEXP) C.SEXP { // starting from within R, we convert a raw byte vector into R structures. // s must be a RAWSXP if C.TYPEOF(s) != C.RAWSXP { C.ReportErrorToR_NoReturn(C.CString("from.msgpack(x) requires x be a RAW vector of bytes.")) } n := int(C.Rf_xlength(s)) if n == 0 { return C.R_NilValue } bytes := make([]byte, n) C.memcpy(unsafe.Pointer(&bytes[0]), unsafe.Pointer(C.RAW(s)), C.size_t(n)) return decodeMsgpackToR(bytes) }
func toIface(s C.SEXP) interface{} { // generate a go map or slice or scalar value, then encode it n := int(C.Rf_xlength(s)) if n == 0 { return nil // drops type info. Meh. } switch C.TYPEOF(s) { case C.VECSXP: // an R generic vector; e.g list() VPrintf("encodeRIntoMsgpack sees VECSXP\n") // could be a map or a slice. Check out the names. rnames := C.Rf_getAttrib(s, C.R_NamesSymbol) rnamesLen := int(C.Rf_xlength(rnames)) VPrintf("namesLen = %d\n", rnamesLen) if rnamesLen > 0 { myMap := map[string]interface{}{} for i := 0; i < rnamesLen; i++ { myMap[C.GoString(C.get_string_elt(rnames, C.int(i)))] = toIface(C.VECTOR_ELT(s, C.R_xlen_t(i))) } VPrintf("VECSXP myMap = '%#v'\n", myMap) return myMap } else { // else: no names, so we treat it as an array instead of as a map mySlice := make([]interface{}, n) for i := 0; i < n; i++ { mySlice[i] = toIface(C.VECTOR_ELT(s, C.R_xlen_t(i))) } VPrintf("VECSXP mySlice = '%#v'\n", mySlice) return mySlice } case C.REALSXP: // a vector of float64 (numeric) VPrintf("encodeRIntoMsgpack sees REALSXP\n") mySlice := make([]float64, n) for i := 0; i < n; i++ { mySlice[i] = float64(C.get_real_elt(s, C.int(i))) } VPrintf("VECSXP mySlice = '%#v'\n", mySlice) return mySlice case C.INTSXP: // a vector of int32 VPrintf("encodeRIntoMsgpack sees INTSXP\n") mySlice := make([]int, n) for i := 0; i < n; i++ { mySlice[i] = int(C.get_int_elt(s, C.int(i))) } VPrintf("INTSXP mySlice = '%#v'\n", mySlice) return mySlice case C.RAWSXP: VPrintf("encodeRIntoMsgpack sees RAWSXP\n") mySlice := make([]byte, n) C.memcpy(unsafe.Pointer(&mySlice[0]), unsafe.Pointer(C.RAW(s)), C.size_t(n)) VPrintf("RAWSXP mySlice = '%#v'\n", mySlice) return mySlice case C.STRSXP: // a vector of string (pointers to charsxp that are interned) VPrintf("encodeRIntoMsgpack sees STRSXP\n") mySlice := make([]string, n) for i := 0; i < n; i++ { mySlice[i] = C.GoString(C.get_string_elt(s, C.int(i))) } VPrintf("STRSXP mySlice = '%#v'\n", mySlice) return mySlice case C.NILSXP: // c(); an empty vector VPrintf("encodeRIntoMsgpack sees NILSXP\n") return nil case C.CHARSXP: // a single string, interned in a global pool for reuse by STRSXP. VPrintf("encodeRIntoMsgpack sees CHARSXP\n") case C.SYMSXP: VPrintf("encodeRIntoMsgpack sees SYMSXP\n") case C.LISTSXP: VPrintf("encodeRIntoMsgpack sees LISTSXP\n") case C.CLOSXP: VPrintf("encodeRIntoMsgpack sees CLOSXP\n") case C.ENVSXP: VPrintf("encodeRIntoMsgpack sees ENVSXP\n") case C.PROMSXP: VPrintf("encodeRIntoMsgpack sees PROMSXP\n") case C.LANGSXP: VPrintf("encodeRIntoMsgpack sees LANGSXP\n") case C.SPECIALSXP: VPrintf("encodeRIntoMsgpack sees SPECIALSXP\n") case C.BUILTINSXP: VPrintf("encodeRIntoMsgpack sees BUILTINSXP\n") case C.LGLSXP: VPrintf("encodeRIntoMsgpack sees LGLSXP\n") case C.CPLXSXP: VPrintf("encodeRIntoMsgpack sees CPLXSXP\n") case C.DOTSXP: VPrintf("encodeRIntoMsgpack sees DOTSXP\n") case C.ANYSXP: VPrintf("encodeRIntoMsgpack sees ANYSXP\n") case C.EXPRSXP: VPrintf("encodeRIntoMsgpack sees EXPRSXP\n") case C.BCODESXP: VPrintf("encodeRIntoMsgpack sees BCODESXP\n") case C.EXTPTRSXP: VPrintf("encodeRIntoMsgpack sees EXTPTRSXP\n") case C.WEAKREFSXP: VPrintf("encodeRIntoMsgpack sees WEAKREFSXP\n") case C.S4SXP: VPrintf("encodeRIntoMsgpack sees S4SXP\n") default: VPrintf("encodeRIntoMsgpack sees <unknown>\n") } VPrintf("... warning: encodeRIntoMsgpack() ignoring this input.\n") return nil }
//export ListenAndServe func ListenAndServe(addr_ C.SEXP, handler_ C.SEXP, rho_ C.SEXP) C.SEXP { if C.TYPEOF(addr_) != C.STRSXP { fmt.Printf("addr is not a string (STRXSP; instead it is: %d)! addr argument to ListenAndServe() must be a string of form 'ip:port'\n", C.TYPEOF(addr_)) return C.R_NilValue } //msglen := 0 if 0 == int(C.isFunction(handler_)) { // 0 is false C.ReportErrorToR_NoReturn(C.CString("‘handler’ must be a function")) return C.R_NilValue } if rho_ != nil && rho_ != C.R_NilValue { if 0 == int(C.isEnvironment(rho_)) { // 0 is false C.ReportErrorToR_NoReturn(C.CString("‘rho’ should be an environment")) return C.R_NilValue } } caddr := C.R_CHAR(C.STRING_ELT(addr_, 0)) addr := C.GoString(caddr) fmt.Printf("ListenAndServe listening on address '%s'...\n", addr) webSockHandler := func(w http.ResponseWriter, r *http.Request) { if r.URL.Path != "/" { http.Error(w, "Not found", 404) return } if r.Method != "GET" { http.Error(w, "Method not allowed, only GET allowed.", 405) return } c, err := upgrader.Upgrade(w, r, nil) if err != nil { fmt.Print("websocket handler upgrade error:", err) return } defer c.Close() mt, message, err := c.ReadMessage() if err != nil { fmt.Println("read error: ", err) return } // make the call, and get a response msglen := len(message) rawmsg := C.allocVector(C.RAWSXP, C.R_xlen_t(msglen)) C.Rf_protect(rawmsg) C.memcpy(unsafe.Pointer(C.RAW(rawmsg)), unsafe.Pointer(&message[0]), C.size_t(msglen)) // put msg into env that handler_ is called with. C.defineVar(C.install(C.CString("msg")), rawmsg, rho_) R_serialize_fun = C.findVar(C.install(C.CString("serialize")), C.R_GlobalEnv) // todo: callbacks to R functions here not working. don't really need them if R always acts as a client instead. // evaluate C.PrintToR(C.CString("listenAndServe: stuffed msg into env rho_.\n")) //R_fcall := C.lang3(handler_, rawmsg, C.R_NilValue) R_fcall := C.lang3(R_serialize_fun, rawmsg, C.R_NilValue) C.Rf_protect(R_fcall) C.PrintToR(C.CString("listenAndServe: got msg, just prior to eval.\n")) evalres := C.eval(R_fcall, rho_) C.Rf_protect(evalres) C.PrintToR(C.CString("listenAndServe: after eval.\n")) /* var s, t C.SEXP s = C.allocList(3) t = s C.Rf_protect(t) C.SetTypeToLANGSXP(&s) //C.SETCAR(t, R_fcall) C.SETCAR(t, handler_) t = C.CDR(t) C.SETCAR(t, rawmsg) evalres := C.eval(s, rho_) C.Rf_protect(evalres) */ C.PrintToR(C.CString("nnListenAndServe: done with eval.\n")) if C.TYPEOF(evalres) != C.RAWSXP { fmt.Printf("rats! handler result was not RAWSXP raw bytes!\n") } else { //fmt.Printf("recv: %s\n", message) err = c.WriteMessage(mt, message) if err != nil { fmt.Println("write error: ", err) } } C.Rf_unprotect(3) } // end handler func http.HandleFunc("/", webSockHandler) err := http.ListenAndServe(addr, nil) if err != nil { fmt.Println("ListenAndServe: ", err) } return C.R_NilValue }
func decodeHelper(r interface{}, depth int) (s C.SEXP) { VPrintf("decodeHelper() at depth %d, decoded type is %T\n", depth, r) switch val := r.(type) { case string: VPrintf("depth %d found string case: val = %#v\n", depth, val) return C.Rf_mkString(C.CString(val)) case int: VPrintf("depth %d found int case: val = %#v\n", depth, val) return C.Rf_ScalarReal(C.double(float64(val))) case int32: VPrintf("depth %d found int32 case: val = %#v\n", depth, val) return C.Rf_ScalarReal(C.double(float64(val))) case int64: VPrintf("depth %d found int64 case: val = %#v\n", depth, val) return C.Rf_ScalarReal(C.double(float64(val))) case []interface{}: VPrintf("depth %d found []interface{} case: val = %#v\n", depth, val) var sxpTy C.SEXPTYPE = C.VECSXP lenval := len(val) if lenval == 0 { emptyvec := C.allocVector(C.NILSXP, C.R_xlen_t(0)) if depth == 0 { C.Rf_protect(emptyvec) } return emptyvec } if lenval > 0 { first := val[0] VPrintf(" ... also at depth %d, ---> first has type '%T' and value '%v'\n", depth, first, first) switch first.(type) { case string: sxpTy = C.STRSXP stringSlice := C.allocVector(sxpTy, C.R_xlen_t(lenval)) C.Rf_protect(stringSlice) for i := range val { C.SET_STRING_ELT(stringSlice, C.R_xlen_t(i), C.mkChar(C.CString(val[i].(string)))) } if depth != 0 { C.Rf_unprotect(1) // unprotect for stringSlice, now that we are returning it } return stringSlice case int64: // we can only realistically hope to preserve 53 bits worth here. // todo? unless... can we require bit64 package be available somehow? sxpTy = C.REALSXP numSlice := C.allocVector(sxpTy, C.R_xlen_t(lenval)) C.Rf_protect(numSlice) size := unsafe.Sizeof(C.double(0)) naflag := false rmax := int64(C.pow(FLT_RADIX, DBL_MANT_DIG) - 1) //VPrintf("rmax = %v\n", rmax) // rmax = 9007199254740991 rmin := -rmax ptrNumSlice := unsafe.Pointer(C.REAL(numSlice)) var ui uintptr var rhs C.double for i := range val { n := val[i].(int64) fmt.Printf("n = %d, rmax = %d, n > rmax = %v\n", n, rmax, n > rmax) if n < rmin || n > rmax { naflag = true } ui = uintptr(i) rhs = C.double(float64(n)) // Try to avoid any gc activity by avoiding conversions // and hence do pointer arithmetic all at once in one expression. See // https://github.com/golang/go/issues/8994 for discussion. *((*C.double)(unsafe.Pointer(uintptr(ptrNumSlice) + size*ui))) = rhs } if naflag { C.WarnAndContinue(C.CString("integer precision lost while converting to double")) } if depth != 0 { C.Rf_unprotect(1) // unprotect for numSlice, now that we are returning it } return numSlice case float64: sxpTy = C.REALSXP numSlice := C.allocVector(sxpTy, C.R_xlen_t(lenval)) C.Rf_protect(numSlice) size := unsafe.Sizeof(C.double(0)) // unfortunately C.memmove() doesn't work here (I tried). I speculate this is because val[i] is // really wrapped in an interface{} rather than being a actual float64. val *is* an // []interface{} after all. var rhs C.double ptrNumSlice := unsafe.Pointer(C.REAL(numSlice)) for i := range val { rhs = C.double(val[i].(float64)) *((*C.double)(unsafe.Pointer(uintptr(ptrNumSlice) + size*uintptr(i)))) = rhs } if depth != 0 { C.Rf_unprotect(1) // unprotect for numSlice, now that we are returning it } return numSlice } } intslice := C.allocVector(sxpTy, C.R_xlen_t(lenval)) C.Rf_protect(intslice) for i := range val { C.SET_VECTOR_ELT(intslice, C.R_xlen_t(i), decodeHelper(val[i], depth+1)) } if depth != 0 { C.Rf_unprotect(1) // unprotect for intslice, now that we are returning it } return intslice case map[string]interface{}: s = C.allocVector(C.VECSXP, C.R_xlen_t(len(val))) if depth == 0 { // only protect the top parent of the returned value, recursively // geneated are transitively protected by their parent. C.Rf_protect(s) } names := C.allocVector(C.VECSXP, C.R_xlen_t(len(val))) C.Rf_protect(names) VPrintf("depth %d found map[string]interface case: val = %#v\n", depth, val) sortedMapKey, sortedMapVal := makeSortedSlicesFromMap(val) for i := range sortedMapKey { ele := decodeHelper(sortedMapVal[i], depth+1) C.Rf_protect(ele) C.SET_VECTOR_ELT(s, C.R_xlen_t(i), ele) C.Rf_unprotect(1) // unprotect for ele, now that it is safely inside s. ksexpString := C.Rf_mkString(C.CString(sortedMapKey[i])) C.SET_VECTOR_ELT(names, C.R_xlen_t(i), ksexpString) } C.setAttrib(s, C.R_NamesSymbol, names) C.Rf_unprotect(1) // unprotect for names, now that it is attached to s. case []byte: VPrintf("depth %d found []byte case: val = %#v\n", depth, val) rawmsg := C.allocVector(C.RAWSXP, C.R_xlen_t(len(val))) if depth == 0 { C.Rf_protect(rawmsg) } C.memcpy(unsafe.Pointer(C.RAW(rawmsg)), unsafe.Pointer(&val[0]), C.size_t(len(val))) return rawmsg case nil: return C.R_NilValue default: fmt.Printf("unknown type in type switch, val = %#v. type = %T.\n", val, val) } return s }
// new policy: decodeHelper should always return a protected s, // and the user/client/caller of decodeHelper() is responsible // for unprotecting s if they are embedding it. This is // much easier to audit for correctness. // // if jsonHeuristicDecode then we'll treat raw []byte that // start with '{' as JSON and try to decode them too. // func decodeHelper(r interface{}, depth int, jsonHeuristicDecode bool) (s C.SEXP) { defer func() { r := recover() if r != nil { // truncated or mal-formed msgpack can cause us problems... err, isErr := r.(error) if !isErr { err = fmt.Errorf("'%v'", r) } C.ReportErrorToR_NoReturn(C.CString(panicErrIntro + err.Error() + "\n" + string(debug.Stack()))) } }() VPrintf("decodeHelper() at depth %d, decoded type is %T\n", depth, r) switch val := r.(type) { case string: VPrintf("depth %d found string case: val = %#v\n", depth, val) s = C.Rf_mkString(C.CString(val)) C.Rf_protect(s) return s case int: VPrintf("depth %d found int case: val = %#v\n", depth, val) s = C.Rf_ScalarReal(C.double(float64(val))) C.Rf_protect(s) return s case int32: VPrintf("depth %d found int32 case: val = %#v\n", depth, val) s = C.Rf_ScalarReal(C.double(float64(val))) C.Rf_protect(s) return s case int64: VPrintf("depth %d found int64 case: val = %#v\n", depth, val) s = C.Rf_ScalarReal(C.double(float64(val))) C.Rf_protect(s) return s case float64: VPrintf("depth %d found float64 case: val = %#v\n", depth, val) s = C.Rf_ScalarReal(C.double(val)) C.Rf_protect(s) return s case []interface{}: VPrintf("depth %d found []interface{} case: val = %#v\n", depth, val) var sxpTy C.SEXPTYPE = C.VECSXP lenval := len(val) if lenval == 0 { emptyvec := C.allocVector(C.NILSXP, C.R_xlen_t(0)) C.Rf_protect(emptyvec) return emptyvec } if lenval > 0 { first := val[0] VPrintf(" ... also at depth %d, ---> first has type '%T' and value '%v'\n", depth, first, first) switch first.(type) { case string: sxpTy = C.STRSXP stringSlice := C.allocVector(sxpTy, C.R_xlen_t(lenval)) C.Rf_protect(stringSlice) for i := range val { C.SET_STRING_ELT(stringSlice, C.R_xlen_t(i), C.mkChar(C.CString(val[i].(string)))) } return stringSlice case bool: sxpTy = C.LGLSXP boolSlice := C.allocVector(sxpTy, C.R_xlen_t(lenval)) C.Rf_protect(boolSlice) for i := range val { switch val[i].(bool) { case true: C.set_lglsxp_true(boolSlice, C.ulonglong(i)) case false: C.set_lglsxp_false(boolSlice, C.ulonglong(i)) } } return boolSlice case int64: // we can only realistically hope to preserve 53 bits worth here. // todo? unless... can we require bit64 package be available somehow? sxpTy = C.REALSXP numSlice := C.allocVector(sxpTy, C.R_xlen_t(lenval)) C.Rf_protect(numSlice) size := unsafe.Sizeof(C.double(0)) naflag := false rmax := int64(C.pow(FLT_RADIX, DBL_MANT_DIG) - 1) //VPrintf("rmax = %v\n", rmax) // rmax = 9007199254740991 rmin := -rmax ptrNumSlice := unsafe.Pointer(C.REAL(numSlice)) var ui uintptr var rhs C.double for i := range val { n := val[i].(int64) VPrintf("n = %d, rmax = %d, n > rmax = %v\n", n, rmax, n > rmax) if n < rmin || n > rmax { naflag = true } ui = uintptr(i) rhs = C.double(float64(n)) // Try to avoid any gc activity (from the Go runtime) while // in the middle of uintptr <-> unsafe.Pointer conversion, as // if the gc were to catch us in the middle of that conversion // it might crash. // Hence we do pointer arithmetic all at once in one expression, // which is at present (Oct 2015) is the recommended safe way // to do pointer arithmetic in Go. See // https://github.com/golang/go/issues/8994 for discussion. *((*C.double)(unsafe.Pointer(uintptr(ptrNumSlice) + size*ui))) = rhs } if naflag { C.WarnAndContinue(C.CString("integer precision lost while converting to double")) } return numSlice case float64: sxpTy = C.REALSXP numSlice := C.allocVector(sxpTy, C.R_xlen_t(lenval)) C.Rf_protect(numSlice) size := unsafe.Sizeof(C.double(0)) // unfortunately C.memmove() doesn't work here (I tried). I speculate this is because val[i] is // really wrapped in an interface{} rather than being a actual float64. val *is* an // []interface{} after all. var rhs C.double ptrNumSlice := unsafe.Pointer(C.REAL(numSlice)) for i := range val { rhs = C.double(val[i].(float64)) *((*C.double)(unsafe.Pointer(uintptr(ptrNumSlice) + size*uintptr(i)))) = rhs } return numSlice } } intslice := C.allocVector(sxpTy, C.R_xlen_t(lenval)) C.Rf_protect(intslice) for i := range val { elt := decodeHelper(val[i], depth+1, jsonHeuristicDecode) C.SET_VECTOR_ELT(intslice, C.R_xlen_t(i), elt) C.Rf_unprotect_ptr(elt) // safely inside intslice now } return intslice case map[string]interface{}: s = C.allocVector(C.VECSXP, C.R_xlen_t(len(val))) C.Rf_protect(s) names := C.allocVector(C.VECSXP, C.R_xlen_t(len(val))) C.Rf_protect(names) VPrintf("depth %d found map[string]interface case: val = %#v\n", depth, val) sortedMapKey, sortedMapVal := makeSortedSlicesFromMap(val) for i := range sortedMapKey { ele := decodeHelper(sortedMapVal[i], depth+1, jsonHeuristicDecode) C.SET_VECTOR_ELT(s, C.R_xlen_t(i), ele) C.Rf_unprotect_ptr(ele) // unprotect ele now that it is safely inside s. ksexpString := C.Rf_mkString(C.CString(sortedMapKey[i])) C.Rf_protect(ksexpString) C.SET_VECTOR_ELT(names, C.R_xlen_t(i), ksexpString) C.Rf_unprotect_ptr(ksexpString) // safely inside names } C.setAttrib(s, C.R_NamesSymbol, names) C.Rf_unprotect_ptr(names) // safely attached to s. case []byte: VPrintf("depth %d found []byte case: val = %#v\n", depth, val) if jsonHeuristicDecode { if len(val) > 0 && val[0] == '{' { jsonToR := decodeJsonToR(val) C.Rf_protect(jsonToR) return jsonToR } } rawmsg := C.allocVector(C.RAWSXP, C.R_xlen_t(len(val))) C.Rf_protect(rawmsg) if len(val) > 0 { C.memcpy(unsafe.Pointer(C.RAW(rawmsg)), unsafe.Pointer(&val[0]), C.size_t(len(val))) } return rawmsg case nil: s = C.R_NilValue C.Rf_protect(s) // must, for uniformly consistency. else we get protect imbalances. return s case bool: boolmsg := C.allocVector(C.LGLSXP, C.R_xlen_t(1)) C.Rf_protect(boolmsg) if val { C.set_lglsxp_true(boolmsg, 0) } else { C.set_lglsxp_false(boolmsg, 0) } return boolmsg default: fmt.Printf("unknown type in type switch, val = %#v. type = %T.\n", val, val) } return s }