|
|
@@ -47,10 +47,81 @@ func NewPrimitiveReference(value interface{}) (*Reference, error) {
|
|
|
case []byte:
|
|
|
return NewBytes(value_)
|
|
|
}
|
|
|
+ return nil, fmt.Errorf("unsupported type: %s", value)
|
|
|
+}
|
|
|
|
|
|
- return nil, fmt.Errorf("unsupported primitive: %s", value)
|
|
|
+func (self *Reference) ToInterface(recurse int) (interface{}, error) {
|
|
|
+ if self.IsLong() {
|
|
|
+ return self.ToInt64()
|
|
|
+ }
|
|
|
+ if self.IsUnicode() {
|
|
|
+ return self.ToString()
|
|
|
+ }
|
|
|
+ if self.IsBool() {
|
|
|
+ return self.ToBool(), nil
|
|
|
+ }
|
|
|
+ if self.IsNone() {
|
|
|
+ return nil, nil
|
|
|
+ }
|
|
|
+ if self.IsFloat() {
|
|
|
+ return self.ToFloat64()
|
|
|
+ }
|
|
|
+ if self.IsBytes() {
|
|
|
+ return self.ToBytes()
|
|
|
+ }
|
|
|
+ if self.IsByteArray() {
|
|
|
+ return self.ByteArrayToBytes()
|
|
|
+ }
|
|
|
+ if self.IsDict() {
|
|
|
+ if recurse <= 0 {
|
|
|
+ return nil, fmt.Errorf("reached recursion limit")
|
|
|
+ }
|
|
|
+ mapValue := make(map[interface{}]interface{})
|
|
|
+
|
|
|
+ dict, err := self.ToMap()
|
|
|
+ if err != nil { return mapValue, err }
|
|
|
+
|
|
|
+ errorNum := 0
|
|
|
+ for key, val := range dict {
|
|
|
+ keyValue, err1 := key.ToInterface(recurse-1)
|
|
|
+ valValue, err2 := val.ToInterface(recurse-1)
|
|
|
+ key.Release()
|
|
|
+ val.Release()
|
|
|
+ if err1 == nil && err2 == nil {
|
|
|
+ mapValue[keyValue] = valValue
|
|
|
+ } else {
|
|
|
+ errorNum ++
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if errorNum > 0 {
|
|
|
+ return mapValue, fmt.Errorf("failed to convert %d primitives from dictionary", errorNum)
|
|
|
+ }
|
|
|
+ return mapValue, nil
|
|
|
+ }
|
|
|
+ if self.IsList() {
|
|
|
+ if recurse <= 0 {
|
|
|
+ return nil, fmt.Errorf("reached recursion limit")
|
|
|
+ }
|
|
|
+ pyList, err := self.ToList()
|
|
|
+ if err != nil { return nil, err }
|
|
|
+ goList := make([]interface{}, len(pyList))
|
|
|
+
|
|
|
+ errorNum := 0
|
|
|
+ for i, item := range pyList {
|
|
|
+ if goList[i], err = item.ToInterface(recurse-1); err != nil {
|
|
|
+ errorNum ++
|
|
|
+ }
|
|
|
+ item.Release()
|
|
|
+ }
|
|
|
+ if errorNum > 0 {
|
|
|
+ return goList, fmt.Errorf("failed to convert %d primitives from list", errorNum)
|
|
|
+ }
|
|
|
+ return goList, nil
|
|
|
+ }
|
|
|
+ return nil, fmt.Errorf("unsupported primitive: %s", self.String())
|
|
|
}
|
|
|
|
|
|
+
|
|
|
//
|
|
|
// None
|
|
|
//
|
|
|
@@ -66,6 +137,10 @@ var BoolType = NewType(&C.PyBool_Type)
|
|
|
var True = NewReference(C.Py_True)
|
|
|
var False = NewReference(C.Py_False)
|
|
|
|
|
|
+func (self *Reference) IsNone() bool {
|
|
|
+ return self.Object == C.Py_None
|
|
|
+}
|
|
|
+
|
|
|
func (self *Reference) IsBool() bool {
|
|
|
return self.Type().IsSubtype(BoolType)
|
|
|
}
|
|
|
@@ -100,10 +175,10 @@ func (self *Reference) IsLong() bool {
|
|
|
}
|
|
|
|
|
|
func (self *Reference) ToInt64() (int64, error) {
|
|
|
- if long := C.PyLong_AsLong(self.Object); !HasException() {
|
|
|
+ if long := C.PyLong_AsLongLong(self.Object); !HasException() {
|
|
|
return int64(long), nil
|
|
|
} else {
|
|
|
- return 0, GetError()
|
|
|
+ return int64(long), GetError()
|
|
|
}
|
|
|
}
|
|
|
|
|
|
@@ -257,6 +332,54 @@ func (self *Reference) SetListItem(index int, item *Reference) error {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+func (self *Reference) ToList() ([]*Reference, error) {
|
|
|
+ var listLen int
|
|
|
+ if listLen = int(C.PyList_Size(self.Object)); HasException() {
|
|
|
+ return nil, GetError()
|
|
|
+ }
|
|
|
+ goList := make([]*Reference, listLen)
|
|
|
+ for i := 0; i < listLen; i++ {
|
|
|
+ index := C.long(int64(i))
|
|
|
+ if item := C.PyList_GetItem(self.Object, index); item != nil {
|
|
|
+ goList[i] = NewReference(item)
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return goList, nil
|
|
|
+}
|
|
|
+
|
|
|
+func (self *Reference) Iteratable() bool {
|
|
|
+ return int(C.PyIter_Check(self.Object)) == 1
|
|
|
+}
|
|
|
+
|
|
|
+func (self *Reference) Iterate(next <-chan bool) (<-chan *Reference, error) {
|
|
|
+ iterator := C.PyObject_GetIter(self.Object)
|
|
|
+ if iterator == nil || HasException() {
|
|
|
+ return nil, GetError()
|
|
|
+ }
|
|
|
+ ch := make(chan *Reference, 1)
|
|
|
+ go func() {
|
|
|
+ defer close(ch)
|
|
|
+ defer C.Py_DecRef(iterator)
|
|
|
+ forLoop:
|
|
|
+ for ;; {
|
|
|
+ if <- next {
|
|
|
+ item := C.PyIter_Next(iterator);
|
|
|
+ if item == nil { break }
|
|
|
+ pyItem := NewReference(item)
|
|
|
+ select {
|
|
|
+ case ch <- pyItem:
|
|
|
+ default:
|
|
|
+ pyItem.Release()
|
|
|
+ break forLoop
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ break
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }()
|
|
|
+ return ch, nil
|
|
|
+}
|
|
|
+
|
|
|
//
|
|
|
// Dict
|
|
|
//
|
|
|
@@ -284,6 +407,80 @@ func (self *Reference) SetDictItem(key *Reference, value *Reference) error {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+func (self *Reference) DictContains(key *Reference) (bool, error) {
|
|
|
+ res := C.PyDict_Contains(self.Object, key.Object)
|
|
|
+ if res == -1 {
|
|
|
+ return false, GetError()
|
|
|
+ }
|
|
|
+ return res == 1, nil
|
|
|
+}
|
|
|
+
|
|
|
+func (self *Reference) DictContainsString(key string) (bool, error) {
|
|
|
+ keyObj, err := NewUnicode(key)
|
|
|
+ if err != nil {
|
|
|
+ return false, err
|
|
|
+ }
|
|
|
+ defer keyObj.Release()
|
|
|
+ res := C.PyDict_Contains(self.Object, keyObj.Object)
|
|
|
+ if res == -1 {
|
|
|
+ return false, GetError()
|
|
|
+ }
|
|
|
+ return res == 1, nil
|
|
|
+}
|
|
|
+
|
|
|
+func (self *Reference) GetDictItemString(key string) *Reference {
|
|
|
+ value_ := C.CString(key)
|
|
|
+ defer C.free(unsafe.Pointer(value_))
|
|
|
+
|
|
|
+ if obj := C.PyDict_GetItemString(self.Object, value_); obj != nil {
|
|
|
+ return NewReference(obj)
|
|
|
+ }
|
|
|
+ return nil
|
|
|
+}
|
|
|
+
|
|
|
+func (self *Reference) GetDictItem(key *Reference) *Reference {
|
|
|
+ if obj := C.PyDict_GetItem(self.Object, key.Object); obj != nil {
|
|
|
+ return NewReference(obj)
|
|
|
+ }
|
|
|
+ return nil
|
|
|
+}
|
|
|
+
|
|
|
+func (self *Reference) DeleteDictItem(key *Reference) error {
|
|
|
+ if ret := C.PyDict_DelItem(self.Object, key.Object); ret != 0 {
|
|
|
+ return GetError()
|
|
|
+ }
|
|
|
+ return nil
|
|
|
+}
|
|
|
+
|
|
|
+func (self *Reference) DeleteDictItemString(key string) error {
|
|
|
+ value_ := C.CString(key)
|
|
|
+ defer C.free(unsafe.Pointer(value_))
|
|
|
+
|
|
|
+ if ret := C.PyDict_DelItemString(self.Object, value_); ret != 0 {
|
|
|
+ return GetError()
|
|
|
+ }
|
|
|
+ return nil
|
|
|
+}
|
|
|
+
|
|
|
+func (self *Reference) ToMap() (map[*Reference]*Reference, error) {
|
|
|
+ keys := C.PyDict_Keys(self.Object)
|
|
|
+ if HasException() {
|
|
|
+ return nil, GetError()
|
|
|
+ }
|
|
|
+ defer C.Py_DecRef(keys)
|
|
|
+ iterator := C.PyObject_GetIter(keys)
|
|
|
+ defer C.Py_DecRef(iterator)
|
|
|
+ dict := make(map[*Reference]*Reference)
|
|
|
+ for {
|
|
|
+ key := C.PyIter_Next(iterator);
|
|
|
+ if key == nil { break }
|
|
|
+ value := C.PyDict_GetItem(self.Object, key)
|
|
|
+ if value == nil { continue }
|
|
|
+ dict[NewReference(key)] = NewReference(value)
|
|
|
+ }
|
|
|
+ return dict, nil
|
|
|
+}
|
|
|
+
|
|
|
//
|
|
|
// Set (mutable)
|
|
|
//
|
|
|
@@ -398,3 +595,21 @@ func (self *Reference) AccessByteArray() (unsafe.Pointer, int, error) {
|
|
|
return nil, 0, GetError()
|
|
|
}
|
|
|
}
|
|
|
+
|
|
|
+//
|
|
|
+// Object
|
|
|
+//
|
|
|
+
|
|
|
+//var ObjectType = NewType(&C.PyObject_Type)
|
|
|
+//
|
|
|
+//func (self *Reference) IsObject() bool {
|
|
|
+// return self.Type().IsSubtype(ObjectType)
|
|
|
+//}
|
|
|
+
|
|
|
+func (self *Reference) IsInstance(cls *Reference) (bool, error) {
|
|
|
+ inst := int64(C.PyObject_IsInstance(self.Object, cls.Object))
|
|
|
+ if HasException() {
|
|
|
+ return false, GetError()
|
|
|
+ }
|
|
|
+ return inst == 1, nil
|
|
|
+}
|