Esempio n. 1
0
File: rmq.go Progetto: glycerine/rmq
//export ReadMsgpackFrame
//
// ReadMsgpackFrame reads the msgpack frame at byteOffset in rawStream, decodes the
// 2-5 bytes of a msgpack binary array (either bin8, bin16, or bin32), and returns
// and the decoded-into-R object and the next byteOffset to use.
//
func ReadMsgpackFrame(rawStream C.SEXP, byteOffset C.SEXP) C.SEXP {

	var start int
	if C.TYPEOF(byteOffset) == C.REALSXP {
		start = int(C.get_real_elt(byteOffset, 0))
	} else if C.TYPEOF(byteOffset) == C.INTSXP {
		start = int(C.get_int_elt(byteOffset, 0))
	} else {
		C.ReportErrorToR_NoReturn(C.CString("read.msgpack.frame(x, byteOffset) requires byteOffset to be a numeric byte-offset number."))
	}

	// rawStream must be a RAWSXP
	if C.TYPEOF(rawStream) != C.RAWSXP {
		C.ReportErrorToR_NoReturn(C.CString("read.msgpack.frame(x, byteOffset) requires x be a RAW vector of bytes."))
	}

	n := int(C.Rf_xlength(rawStream))
	if n == 0 {
		return C.R_NilValue
	}

	if start >= n {
		C.ReportErrorToR_NoReturn(C.CString(fmt.Sprintf("read.msgpack.frame(x, byteOffset) error: byteOffset(%d) is beyond the length of x (x has len %d).", start, n)))
	}

	var decoder [5]byte
	C.memcpy(unsafe.Pointer(&decoder[0]), unsafe.Pointer(C.get_raw_elt_ptr(rawStream, C.ulonglong(start))), C.size_t(5))
	headerSz, _, totalSz, err := DecodeMsgpackBinArrayHeader(decoder[:])
	if err != nil {
		C.ReportErrorToR_NoReturn(C.CString(fmt.Sprintf("ReadMsgpackFrame error trying to decode msgpack frame: %s", err)))
	}

	if start+totalSz > n {
		C.ReportErrorToR_NoReturn(C.CString(fmt.Sprintf("read.msgpack.frame(x, byteOffset) error: byteOffset(%d) plus the frames size(%d) goes beyond the length of x (x has len %d).", start, totalSz, n)))
	}

	bytes := make([]byte, totalSz)
	C.memcpy(unsafe.Pointer(&bytes[0]), unsafe.Pointer(C.get_raw_elt_ptr(rawStream, C.ulonglong(start))), C.size_t(totalSz))

	rObject := decodeMsgpackToR(bytes[headerSz:])
	C.Rf_protect(rObject)
	returnList := C.allocVector(C.VECSXP, C.R_xlen_t(2))
	C.Rf_protect(returnList)
	C.SET_VECTOR_ELT(returnList, C.R_xlen_t(0), C.Rf_ScalarReal(C.double(float64(start+totalSz))))
	C.SET_VECTOR_ELT(returnList, C.R_xlen_t(1), rObject)
	C.Rf_unprotect_ptr(rObject)
	C.Rf_unprotect_ptr(returnList)
	return returnList
}
Esempio n. 2
0
func (this *NumericVector) CopyFrom(src []float64) {
	C.Rf_protect(this.expr)
	defer C.Rf_unprotect(1)
	for i := 0; i < this.length; i++ {
		C.SetNumericVectorElt(this.expr, C.int(i), C.double(src[i]))
	}
}
Esempio n. 3
0
File: core.go Progetto: Gwill/go-R
func SetSymbol(name string, val Expression) {
	nameC := C.CString(name)
	defer C.free(unsafe.Pointer(nameC))
	C.Rf_protect(val.ToSexp())
	defer C.Rf_unprotect(1)
	C.defineVar(C.install(nameC), val.ToSexp(), C.R_GlobalEnv)
}
Esempio n. 4
0
func (this *ComplexVector) Get(i int) complex128 {
	this.boundsCheck(i)
	C.Rf_protect(this.expr)
	defer C.Rf_unprotect(1)

	c := C.ComplexVectorElt(this.expr, C.int(i))
	return complex(float64(c.r), float64(c.i))
}
Esempio n. 5
0
func (this *NumericVector) ToArray() []float64 {
	C.Rf_protect(this.expr)
	defer C.Rf_unprotect(1)
	array := make([]float64, this.length)
	for i := 0; i < this.length; i++ {
		array[i] = float64(C.NumericVectorElt(this.expr, C.int(i)))
	}
	return array
}
Esempio n. 6
0
File: rmq.go Progetto: glycerine/rmq
//export ReadNewlineDelimJson
//
// ReadNewlineDelimJson reads a json object at byteOffset in rawStream, expects
// it to be newline terminated, and returns the
// decoded-into-R object and the next byteOffset to use (the byte just after
// the terminating newline).
//
func ReadNewlineDelimJson(rawStream C.SEXP, byteOffset C.SEXP) C.SEXP {
	C.Rf_protect(rawStream)

	var start int
	if C.TYPEOF(byteOffset) == C.REALSXP {
		start = int(C.get_real_elt(byteOffset, 0))
	} else if C.TYPEOF(byteOffset) == C.INTSXP {
		start = int(C.get_int_elt(byteOffset, 0))
	} else {
		C.ReportErrorToR_NoReturn(C.CString("read.ndjson(x, byteOffset) requires byteOffset to be a numeric byte-offset number."))
	}
	// rawStream must be a RAWSXP
	if C.TYPEOF(rawStream) != C.RAWSXP {
		C.ReportErrorToR_NoReturn(C.CString("read.ndjson(x, byteOffset) requires x be a RAW vector of bytes."))
	}

	n := int(C.Rf_xlength(rawStream))
	if n == 0 {
		return C.R_NilValue
	}

	if start >= n {
		C.ReportErrorToR_NoReturn(C.CString(fmt.Sprintf("read.ndjson(x, byteOffset) error: byteOffset(%d) is at or beyond the length of x (x has len %d).", start, n)))
	}
	// INVAR: start < n

	// find the next newline or end of raw array
	next := int(C.next_newline_pos(rawStream, C.ulonglong(start+1), C.ulonglong(n)))
	totalSz := next - start

	bytes := make([]byte, totalSz)
	fromPtr := unsafe.Pointer(C.get_raw_elt_ptr(rawStream, C.ulonglong(start)))
	C.memcpy(unsafe.Pointer(&bytes[0]), fromPtr, C.size_t(totalSz))
	rObject := decodeJsonToR(bytes)
	C.Rf_protect(rObject)
	returnList := C.allocVector(C.VECSXP, C.R_xlen_t(2))
	C.Rf_protect(returnList)
	C.SET_VECTOR_ELT(returnList, C.R_xlen_t(0), C.Rf_ScalarReal(C.double(float64(start+totalSz))))
	C.SET_VECTOR_ELT(returnList, C.R_xlen_t(1), rObject)
	C.Rf_unprotect_ptr(rObject)
	C.Rf_unprotect_ptr(returnList)
	C.Rf_unprotect_ptr(rawStream)
	return returnList
}
Esempio n. 7
0
func (this *ComplexVector) CopyFrom(src []complex128) {
	C.Rf_protect(this.expr)
	defer C.Rf_unprotect(1)
	for i := 0; i < this.length; i++ {
		var c C.Rcomplex
		c.r = C.double(real(src[i]))
		c.i = C.double(imag(src[i]))
		C.SetComplexVectorElt(this.expr, C.int(i), c)
	}
}
Esempio n. 8
0
func (this *ComplexVector) Set(i int, val complex128) {
	this.boundsCheck(i)
	C.Rf_protect(this.expr)
	defer C.Rf_unprotect(1)

	var c C.Rcomplex
	c.r = C.double(real(val))
	c.i = C.double(imag(val))
	C.SetComplexVectorElt(this.expr, C.int(i), c)
}
Esempio n. 9
0
func (this *ComplexVector) ToArray() []complex128 {
	C.Rf_protect(this.expr)
	defer C.Rf_unprotect(1)
	array := make([]complex128, this.length)
	for i := 0; i < this.length; i++ {
		c := C.ComplexVectorElt(this.expr, C.int(i))
		array[i] = complex(float64(c.r), float64(c.i))
	}
	return array
}
Esempio n. 10
0
File: rmq.go Progetto: go-binder/rmq
//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
}
Esempio n. 11
0
File: rmq.go Progetto: glycerine/rmq
func main() {
	// We always need a main() function to make possible
	// CGO compiler to compile the package as C shared library
	// The 'import "C"' at the top of the file is also required
	// in order to export functions marked with //export

	// Note that main() is not run when the .so library is loaded.

	// However, since this is main, it is also the natural place
	// to give an example also of how to
	// embed R in a Go program, should you wish to do that as
	// well.

	// Note that the following go code is an optional demonstration,
	// and not a part of the R package rmq functionality at its core.

	// Introduction to embedding R:
	//
	// While RMQ is mainly designed to embed Go under R, it
	// defines functions that make embedding R in Go
	// quite easy too. We use SexpToIface() to generate
	// a go inteface{} value. For simple uses, this may be
	// more than enough.
	//
	// If you wish to turn results into
	// a pre-defined Go structure, the interface{} value could
	// transformed into msgpack (as in encodeRIntoMsgpack())
	// and from there automatically parsed into Go structures
	// if you define the Go structures and use
	// https://github.com/tinylib/msgp to generate the
	// go struct <-> msgpack encoding/decoding boilerplate.
	// The tinylib/msgp library uses go generate and is
	// blazing fast. This also avoids maintaining a separate
	// IDL file. Your Go source code is always the defining document.

	var iface interface{}
	C.callInitEmbeddedR()
	myRScript := "rnorm(100)" // generate 100 Gaussian(0,1) samples
	var evalErrorOccurred C.int
	r := C.callParseEval(C.CString(myRScript), &evalErrorOccurred)
	if evalErrorOccurred == 0 && r != C.R_NilValue {
		C.Rf_protect(r)
		iface = SexpToIface(r)
		fmt.Printf("\n Embedding R in Golang example: I got back from evaluating myRScript:\n")
		goon.Dump(iface)
		C.Rf_unprotect(1) // unprotect r
	}
	C.callEndEmbeddedR()
}
Esempio n. 12
0
File: vector.go Progetto: Gwill/go-R
func (this *Vector) Get(i int) *Result {
	this.boundsCheck(i)
	C.Rf_protect(this.expr)
	defer C.Rf_unprotect(1)
	return NewResult(C.GenericVectorElt(this.expr, C.int(i)))
}
Esempio n. 13
0
File: rmq.go Progetto: go-binder/rmq
//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
}
Esempio n. 14
0
File: rmq.go Progetto: go-binder/rmq
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
}
Esempio n. 15
0
func (this *NumericVector) Set(i int, val float64) {
	this.boundsCheck(i)
	C.Rf_protect(this.expr)
	defer C.Rf_unprotect(1)
	C.SetNumericVectorElt(this.expr, C.int(i), C.double(val))
}
Esempio n. 16
0
File: core.go Progetto: Gwill/go-R
func (this *protector) Protect(sexpr C.SEXP) RProtector {
	C.Rf_protect(sexpr)
	this.count++
	return this
}
Esempio n. 17
0
File: rmq.go Progetto: glycerine/rmq
// 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
}
Esempio n. 18
0
File: rmq.go Progetto: glycerine/rmq
//export ListenAndServe
//
// ListenAndServe is the server part that expects calls from client
// in the form of RmqWebsocketCall() invocations.
// The underlying websocket library is the battle tested
// https://github.com/gorilla/websocket library from the
// Gorilla Web toolkit. http://www.gorillatoolkit.org/
//
// addr_ is a string in "ip:port" format. The server
// will bind this address and port on the local host.
//
// handler_ is an R function that takes a single argument.
// It will be called back each time the server receives
// an incoming message. The returned value of handler
// becomes the reply to the client.
//
// rho_ is an R environment in which the handler_ callback
// will occur. The user-level wrapper rmq.server() provides
// a new environment for every call back by default, so
// most users won't need to worry about rho_.
//
// Return value: this is always R_NilValue.
//
// Semantics: ListenAndServe() will start a new
// webserver everytime it is called. If it exits
// due to a call into R_CheckUserInterrupt()
// or Rf_error(), then a background watchdog goroutine
// will notice the lack of heartbeating after 300ms,
// and will immediately shutdown the listening
// websocket server goroutine. Hence cleanup
// is fairly automatic.
//
// Signal handling:
//
// SIGINT (ctrl-c) is noted by R, and since we
// regularly call R_CheckUserInterrupt(), the
// user can stop the server by pressing ctrl-c
// at the R-console. The go-runtime, as embedded
// in the c-shared library, is not accustomed to being
// embedded yet, and so its (system) signal handling
// facilities (e.g. signal.Notify) should *not* be
// used. We go to great pains to actually preserve
// the signal handling that R sets up and expects,
// as allowing the go runtime to see any signals just
// creates heartache and crashes.
//
func ListenAndServe(addr_ C.SEXP, handler_ C.SEXP, rho_ C.SEXP) C.SEXP {

	addr, err := getAddr(addr_)

	if err != nil {
		C.ReportErrorToR_NoReturn(C.CString(err.Error()))
		return C.R_NilValue
	}

	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
		}
	}

	fmt.Printf("ListenAndServe listening on address '%s'...\n", addr)

	// Motivation: One problem when acting as a web server is that
	// webSockHandler will be run on a separate goroutine and this will surely
	// be a separate thread--distinct from the R callback thread. This is a
	// problem because if we call back into R from the goroutine thread
	// instead of R's thread, R will see the small stack and freak out.
	//
	// So: we'll use a channel to send the request to the main R thread
	// for call back into R. The *[]byte passed on these channels represent
	// msgpack serialized R objects.
	requestToRCh := make(chan *[]byte)
	replyFromRCh := make(chan *[]byte)
	reqStopCh := make(chan bool)
	doneCh := make(chan bool)
	var lastControlHeartbeatTimeNano int64

	beatHeart := func() {
		now := int64(time.Now().UnixNano())
		atomic.StoreInt64(&lastControlHeartbeatTimeNano, now)
	}

	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 {
			msg := fmt.Sprintf("server webSockHandler() handler saw "+
				"websocket upgrader.Upgrade() error: '%s'", err)
			fmt.Printf("%s\n", msg)
			http.Error(w, msg, 500)
			return
		}
		defer c.Close()

		_, message, err := c.ReadMessage()
		if err != nil {
			msg := fmt.Sprintf("server webSockHandler() handler saw "+
				"websocket ReadMessage() error: '%s'", err)
			fmt.Printf("%s\n", msg)
			http.Error(w, msg, 500)
			return
		}

		requestToRCh <- &message
		reply := <-replyFromRCh

		err = c.WriteMessage(websocket.BinaryMessage, *reply)
		if err != nil {
			msg := fmt.Sprintf("server webSockHandler() handler saw "+
				"websocket WriteMessage() error: '%s'", err)
			fmt.Printf("%s\n", msg)
			http.Error(w, msg, 500)
			return
		}
	} // end webSockHandler

	// start a new server, to avoid registration issues with
	// the default http library mux/server which may be in use
	// already for other purposes.
	mux := http.NewServeMux()
	mux.HandleFunc("/", webSockHandler)
	server := NewWebServer(addr.String(), mux)
	server.Start()

	// This watchdog will shut the webserver down
	// if lastControlHeartbeatTimeNano goes
	// too long without an update. This will
	// happen when C.R_CheckUserInterrupt()
	// doesn't return below in the main control loop.
	beatHeart()
	go func() {
		for {
			select {
			case <-time.After(time.Millisecond * 100):
				last := atomic.LoadInt64(&lastControlHeartbeatTimeNano)
				lastTm := time.Unix(0, last)
				deadline := lastTm.Add(300 * time.Millisecond)
				now := time.Now()
				if now.After(deadline) {
					VPrintf("\n web-server watchdog: no heartbeat "+
						"after %v, shutting down.\n", now.Sub(lastTm))
					server.Stop()
					return
				}
			}
		}
	}()

	// This is the main control routine that lives on the main R thread.
	// All callbacks into R must come from this thread, as it is a
	// C thread with a big stack. Go routines have tiny stacks and
	// R detects this and crashes if you try to call back from one of them.
	for {

		select {
		case <-time.After(time.Millisecond * 100):
			//
			// Our heartbeat logic:
			//
			// R_CheckUserInterrupt() will check if Ctrl-C
			// was pressed by user and R would like us to stop.
			// (R's SIGINT signal handler is installed in our
			// package init() routine at the top of this file.)
			//
			// Note that R_CheckUserInterrupt() may not return!
			// So, Q: how will the server know to cancel/cleanup?
			// A: we'll have the other goroutines check the following
			// timestamp. If it is too out of date, then they'll
			// know that they should cleanup.
			beatHeart()
			C.R_CheckUserInterrupt()

		case msgpackRequest := <-requestToRCh:

			rRequest := decodeMsgpackToR(*msgpackRequest)
			C.Rf_protect(rRequest)

			// Call into the R handler_ function, and get its reply.
			R_fcall := C.lang2(handler_, rRequest)
			C.Rf_protect(R_fcall)
			if Verbose {
				C.PrintToR(C.CString("listenAndServe: got msg, just prior to eval.\n"))
			}
			evalres := C.eval(R_fcall, rho_)
			C.Rf_protect(evalres)
			if Verbose {
				C.PrintToR(C.CString("listenAndServe: after eval.\n"))
			}

			// send back the reply, first converting to msgpack
			reply := encodeRIntoMsgpack(evalres)
			C.Rf_unprotect(3)
			replyFromRCh <- &reply

		case <-reqStopCh:
			// not sure who should close(reqStopCh). At the moment it isn't used.
			close(doneCh)
			return C.R_NilValue
		}
	}
}
Esempio n. 19
0
func tmFramesToR(slc []*tf.Frame) C.SEXP {
	n := len(slc)
	if n == 0 {
		return C.R_NilValue
	}

	cols := 2

	pti := slc[0].GetPTI()
	firstPti := pti
	var payloadList, payload2List C.SEXP

	switch pti {
	case tf.PtiOneInt64:
		payloadList = C.allocVector(C.STRSXP, C.R_xlen_t(n))
		C.Rf_protect(payloadList)
	case tf.PtiOneFloat64:
		payloadList = C.allocVector(C.REALSXP, C.R_xlen_t(n))
		C.Rf_protect(payloadList)
	case tf.PtiTwo64:
		payloadList = C.allocVector(C.REALSXP, C.R_xlen_t(n))
		C.Rf_protect(payloadList)
		payload2List = C.allocVector(C.STRSXP, C.R_xlen_t(n))
		C.Rf_protect(payload2List)
		cols++

	case tf.PtiUDE:
		payloadList = C.allocVector(C.VECSXP, C.R_xlen_t(n))
		C.Rf_protect(payloadList)

	case tf.PtiZero:
	case tf.PtiNull:
	case tf.PtiNA:
	case tf.PtiNaN:
	}

	returnList := C.allocVector(C.VECSXP, C.R_xlen_t(cols))
	C.Rf_protect(returnList)

	timestampSlice := C.allocVector(C.REALSXP, C.R_xlen_t(n))
	C.Rf_protect(timestampSlice)
	size := unsafe.Sizeof(C.double(0))

	var rhs C.double
	ptrNumSlice := unsafe.Pointer(C.REAL(timestampSlice))
	const msec = 1e6
	for i, f := range slc {
		// timestamp
		tmu := f.Tm()
		ftm := float64(tmu / msec)
		//fmt.Printf("tmu[%v]=%v / ftm=%v\n", i, tmu, ftm)
		rhs = C.double(ftm)
		*((*C.double)(unsafe.Pointer(uintptr(ptrNumSlice) + size*uintptr(i)))) = rhs

		// payload
		pti = f.GetPTI()
		if pti != firstPti {
			panic(fmt.Sprintf("inconsistent pti, firstPti was '%v', now we have '%v'",
				firstPti, pti))
		}
		switch pti {
		case tf.PtiOneInt64:
			C.SET_STRING_ELT(payloadList, C.R_xlen_t(i), C.mkChar(C.CString(fmt.Sprintf("%d", f.Ude))))
		case tf.PtiOneFloat64:
			rhs = C.double(f.V0)
			ptrPayList := unsafe.Pointer(C.REAL(payloadList))
			*((*C.double)(unsafe.Pointer(uintptr(ptrPayList) + size*uintptr(i)))) = rhs

		case tf.PtiTwo64:
			rhs = C.double(f.V0)
			ptrPayList := unsafe.Pointer(C.REAL(payloadList))
			*((*C.double)(unsafe.Pointer(uintptr(ptrPayList) + size*uintptr(i)))) = rhs
			C.SET_STRING_ELT(payload2List, C.R_xlen_t(i), C.mkChar(C.CString(fmt.Sprintf("%d", f.Ude))))

		case tf.PtiUDE:

			// probably json or msgpack, try to decode it.
			evtnum := f.GetEvtnum()
			if evtnum == tf.EvJson || (evtnum >= 2000 && evtnum <= 9999) {
				tmp := decodeJsonToR(f.Data)
				C.Rf_protect(tmp)
				C.SET_VECTOR_ELT(payloadList, C.R_xlen_t(i), tmp)
				C.Rf_unprotect_ptr(tmp)
			} else if evtnum == tf.EvMsgpKafka || evtnum == tf.EvMsgpack {
				tmp := decodeMsgpackToR(f.Data)
				C.Rf_protect(tmp)
				C.SET_VECTOR_ELT(payloadList, C.R_xlen_t(i), tmp)
				C.Rf_unprotect_ptr(tmp)
			}

		case tf.PtiZero:
		case tf.PtiNull:
		case tf.PtiNA:
		case tf.PtiNaN:
		}

	} // end for range slc

	C.SET_VECTOR_ELT(returnList, C.R_xlen_t(0), timestampSlice)
	C.SET_VECTOR_ELT(returnList, C.R_xlen_t(1), payloadList)
	if cols == 3 {
		C.SET_VECTOR_ELT(returnList, C.R_xlen_t(2), payload2List)
		C.Rf_unprotect_ptr(payload2List)
	}

	C.Rf_unprotect_ptr(timestampSlice)
	C.Rf_unprotect_ptr(payloadList)

	C.Rf_unprotect_ptr(returnList)
	return returnList
}
Esempio n. 20
0
func (this *NumericVector) Get(i int) float64 {
	this.boundsCheck(i)
	C.Rf_protect(this.expr)
	defer C.Rf_unprotect(1)
	return float64(C.NumericVectorElt(this.expr, C.int(i)))
}