2015-09-22 20:54:58 +00:00
|
|
|
package php
|
|
|
|
|
|
|
|
// #include <stdlib.h>
|
2015-09-22 21:14:51 +00:00
|
|
|
// #include <stdbool.h>
|
2015-09-22 20:54:58 +00:00
|
|
|
// #include "value.h"
|
|
|
|
import "C"
|
|
|
|
|
|
|
|
import (
|
2015-10-01 21:57:17 +00:00
|
|
|
"errors"
|
|
|
|
"reflect"
|
2015-09-22 20:54:58 +00:00
|
|
|
"unsafe"
|
|
|
|
)
|
|
|
|
|
2015-10-01 21:57:17 +00:00
|
|
|
var errInvalidType = errors.New("Cannot create value of unknown type")
|
|
|
|
|
2015-09-22 20:54:58 +00:00
|
|
|
type Value struct {
|
|
|
|
value unsafe.Pointer
|
|
|
|
}
|
|
|
|
|
|
|
|
func (v *Value) Ptr() unsafe.Pointer {
|
|
|
|
return v.value
|
|
|
|
}
|
|
|
|
|
|
|
|
func (v *Value) Destroy() {
|
|
|
|
C.value_destroy(v.value)
|
|
|
|
v = nil
|
|
|
|
}
|
|
|
|
|
2015-10-01 21:57:17 +00:00
|
|
|
func NewValue(val interface{}) (*Value, error) {
|
2015-09-22 20:54:58 +00:00
|
|
|
var ptr unsafe.Pointer
|
|
|
|
|
2015-09-26 19:40:41 +00:00
|
|
|
// Determine value type and create PHP value from the concrete type.
|
2015-10-01 21:57:17 +00:00
|
|
|
v := reflect.ValueOf(val)
|
|
|
|
switch v.Kind() {
|
|
|
|
// Bind integer to PHP int type.
|
|
|
|
case reflect.Int:
|
|
|
|
ptr = C.value_create_long(C.long(v.Int()))
|
|
|
|
// Bind floating point number to PHP double type.
|
|
|
|
case reflect.Float64:
|
|
|
|
ptr = C.value_create_double(C.double(v.Float()))
|
|
|
|
// Bind boolean to PHP bool type.
|
|
|
|
case reflect.Bool:
|
|
|
|
ptr = C.value_create_bool(C.bool(v.Bool()))
|
|
|
|
// Bind string to PHP string type.
|
|
|
|
case reflect.String:
|
|
|
|
str := C.CString(v.String())
|
2015-09-22 20:54:58 +00:00
|
|
|
defer C.free(unsafe.Pointer(str))
|
|
|
|
|
2015-10-01 21:57:17 +00:00
|
|
|
ptr = C.value_create_string(str)
|
|
|
|
// Bind slice to PHP indexed array type.
|
|
|
|
case reflect.Slice:
|
|
|
|
ptr = C.value_create_array(C.uint(v.Len()))
|
|
|
|
|
|
|
|
for i := 0; i < v.Len(); i++ {
|
|
|
|
vs, err := NewValue(v.Index(i).Interface())
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
C.value_array_set_index(ptr, C.ulong(i), vs.Ptr())
|
|
|
|
}
|
|
|
|
// Bind map (with integer or string keys) to PHP associative array type.
|
|
|
|
case reflect.Map:
|
|
|
|
t := v.Type().Key().Kind()
|
2015-09-22 20:54:58 +00:00
|
|
|
|
2015-10-01 21:57:17 +00:00
|
|
|
if t == reflect.Int || t == reflect.String {
|
|
|
|
ptr = C.value_create_array(C.uint(v.Len()))
|
|
|
|
|
|
|
|
for _, k := range v.MapKeys() {
|
|
|
|
vm, err := NewValue(v.MapIndex(k).Interface())
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
if t == reflect.Int {
|
|
|
|
C.value_array_set_index(ptr, C.ulong(k.Int()), vm.Ptr())
|
|
|
|
} else {
|
|
|
|
str := C.CString(k.String())
|
|
|
|
|
|
|
|
C.value_array_set_key(ptr, str, vm.Ptr())
|
|
|
|
C.free(unsafe.Pointer(str))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
return nil, errInvalidType
|
|
|
|
}
|
|
|
|
default:
|
|
|
|
return nil, errInvalidType
|
2015-09-22 20:54:58 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return &Value{value: ptr}, nil
|
|
|
|
}
|