Commit 8b61f77a authored by Kirill Smelkov's avatar Kirill Smelkov

.

parent 7757f824
...@@ -132,6 +132,7 @@ func zclassOf(obj IPersistent) string { ...@@ -132,6 +132,7 @@ func zclassOf(obj IPersistent) string {
} }
var rIPersistent = reflect.TypeOf((*IPersistent)(nil)).Elem() // typeof(IPersistent) var rIPersistent = reflect.TypeOf((*IPersistent)(nil)).Elem() // typeof(IPersistent)
var rPersistent = reflect.TypeOf(Persistent{}) // typeof(Persistent)
var rGhostable = reflect.TypeOf((*Ghostable)(nil)).Elem() // typeof(Ghostable) var rGhostable = reflect.TypeOf((*Ghostable)(nil)).Elem() // typeof(Ghostable)
var rStateful = reflect.TypeOf((*Stateful)(nil)).Elem() // typeof(Stateful) var rStateful = reflect.TypeOf((*Stateful)(nil)).Elem() // typeof(Stateful)
var rPyStateful = reflect.TypeOf((*PyStateful)(nil)).Elem() // typeof(PyStateful) var rPyStateful = reflect.TypeOf((*PyStateful)(nil)).Elem() // typeof(PyStateful)
...@@ -139,7 +140,7 @@ var rPyStateful = reflect.TypeOf((*PyStateful)(nil)).Elem() // typeof(PyStatef ...@@ -139,7 +140,7 @@ var rPyStateful = reflect.TypeOf((*PyStateful)(nil)).Elem() // typeof(PyStatef
// RegisterClass registers ZODB class to correspond to Go type. // RegisterClass registers ZODB class to correspond to Go type.
// //
// typ must embed IPersistent; *typ must implement IPersistent. // typ must embed Persistent; *typ must implement IPersistent.
// //
// typ must be convertible to stateType; stateType must implement Ghostable and // typ must be convertible to stateType; stateType must implement Ghostable and
// either Stateful or PyStateful(*) // either Stateful or PyStateful(*)
...@@ -152,7 +153,7 @@ var rPyStateful = reflect.TypeOf((*PyStateful)(nil)).Elem() // typeof(PyStatef ...@@ -152,7 +153,7 @@ var rPyStateful = reflect.TypeOf((*PyStateful)(nil)).Elem() // typeof(PyStatef
func RegisterClass(class string, typ, stateType reflect.Type) { func RegisterClass(class string, typ, stateType reflect.Type) {
badf := func(format string, argv ...interface{}) { badf := func(format string, argv ...interface{}) {
msg := fmt.Sprintf(format, argv...) msg := fmt.Sprintf(format, argv...)
panic(fmt.Sprintf("zodb: register class (%q, %q): %s", class, typ, msg)) panic(fmt.Sprintf("zodb: register class (%q, %q, %q): %s", class, typ, stateType, msg))
} }
if class == "" { if class == "" {
...@@ -162,38 +163,29 @@ func RegisterClass(class string, typ, stateType reflect.Type) { ...@@ -162,38 +163,29 @@ func RegisterClass(class string, typ, stateType reflect.Type) {
badf("class already registered for %q", zc.typ) badf("class already registered for %q", zc.typ)
} }
// typ must have IPersistent embedded // typ must embed Persistent
// TODO later change to directly embedding non-pointer Persistent | PyPersistent basef, ok := typ.FieldByName("Persistent")
// (optimize memory + less allocation) if !(ok && basef.Anonymous && basef.Type == rPersistent) {
basef, ok := typ.FieldByName("IPersistent") badf("%q does not embed Persistent", typ)
if !(ok && basef.Anonymous && basef.Type == rIPersistent) {
badf("type does not embed IPersistent")
} }
ptype := reflect.PtrTo(typ)
ptstate := reflect.PtrTo(stateType)
switch { switch {
case !typ.Implements(rIPersistent): case !ptype.Implements(rIPersistent):
// typ must not override IPersistent methods with e.g. different signature badf("%q does not implement IPersistent", ptype)
badf("does not implement IPersistent")
case !typ.Implements(rGhostable): case !ptstate.Implements(rGhostable):
badf("does not implement Ghostable") badf("%q does not implement Ghostable", ptstate)
} }
stateful := typ.Implements(rStateful) stateful := ptstate.Implements(rStateful)
pystateful := typ.Implements(rPyStateful) pystateful := ptstate.Implements(rPyStateful)
if !(stateful || pystateful) { if !(stateful || pystateful) {
badf("does not implement any of Stateful or PyStateful") badf("%q does not implement any of Stateful or PyStateful", ptstate)
}
// find out if typ implements PyStateful and, if yes, use PyPersistent as base
if pystateful {
// XXX
} }
// XXX check if class was already registered
// XXX check class != ""
zc := &zclass{class: class, typ: typ, stateType: stateType} zc := &zclass{class: class, typ: typ, stateType: stateType}
classTab[class] = zc classTab[class] = zc
typeTab[typ] = zc typeTab[typ] = zc
......
...@@ -16,6 +16,7 @@ package zodb ...@@ -16,6 +16,7 @@ package zodb
import ( import (
"context" "context"
"reflect"
"sync" "sync"
"lab.nexedi.com/kirr/go123/mem" "lab.nexedi.com/kirr/go123/mem"
...@@ -115,6 +116,8 @@ const ( ...@@ -115,6 +116,8 @@ const (
// //
// XXX it requires it to embed and provide Ghostable + Stateful. // XXX it requires it to embed and provide Ghostable + Stateful.
type Persistent struct { type Persistent struct {
zclass *zclass // ZODB class of this object.
jar *Connection jar *Connection
oid Oid oid Oid
serial Tid serial Tid
...@@ -124,8 +127,8 @@ type Persistent struct { ...@@ -124,8 +127,8 @@ type Persistent struct {
refcnt int32 refcnt int32
// Persistent should be the base for the instance. // Persistent should be the base for the instance.
// instance is additionally either Stateful | PyStateful. // instance is additionally Ghostable and (Stateful | PyStateful).
instance interface{IPersistent; Ghostable} // XXX Ghostable also not good here instance IPersistent // XXX Ghostable also not good here
loading *loadState loading *loadState
} }
...@@ -209,13 +212,12 @@ func (obj *Persistent) PActivate(ctx context.Context) (err error) { ...@@ -209,13 +212,12 @@ func (obj *Persistent) PActivate(ctx context.Context) (err error) {
// try to pass loaded state to object // try to pass loaded state to object
if err == nil { if err == nil {
// XXX wrong: obj.instance is not Stateful (not to show it to public API) switch istate := obj.istate().(type) {
switch inst := obj.instance.(type) {
case Stateful: case Stateful:
err = inst.SetState(state) // XXX err ctx err = istate.SetState(state) // XXX err ctx
case PyStateful: case PyStateful:
err = pySetState(inst, state) // XXX err ctx err = pySetState(istate, obj.zclass.class, state) // XXX err ctx
default: default:
panic("!stateful instance") panic("!stateful instance")
...@@ -260,7 +262,7 @@ func (obj *Persistent) PDeactivate() { ...@@ -260,7 +262,7 @@ func (obj *Persistent) PDeactivate() {
} }
obj.serial = 0 obj.serial = 0
obj.instance.DropState() obj.istate().DropState()
obj.state = GHOST obj.state = GHOST
obj.loading = nil obj.loading = nil
} }
...@@ -276,7 +278,16 @@ func (obj *Persistent) PInvalidate() { ...@@ -276,7 +278,16 @@ func (obj *Persistent) PInvalidate() {
} }
obj.serial = 0 obj.serial = 0
obj.instance.DropState() obj.istate().DropState()
obj.state = GHOST obj.state = GHOST
obj.loading = nil obj.loading = nil
} }
// istate returns .instance casted to corresponding stateType.
//
// returns: Ghostable + (Stateful | PyStateful).
func (obj *Persistent) istate() Ghostable {
xstateful := reflect.ValueOf(obj.instance).Convert(reflect.PtrTo(obj.zclass.stateType))
return xstateful.Interface().(Ghostable)
}
...@@ -37,8 +37,9 @@ type PyStateful interface { ...@@ -37,8 +37,9 @@ type PyStateful interface {
} }
// pySetState decodes raw state as zodb/py serialized stream, and sets decoded // pySetState decodes raw state as zodb/py serialized stream, and sets decoded
// state on PyStateful obj. // state on PyStateful obj. It is an error if decoded state has python class
func pySetState(obj PyStateful, state *mem.Buf) error { // not as specified.
func pySetState(obj PyStateful, objClass string, state *mem.Buf) error {
pyclass, pystate, err := PyData(state.Data).Decode() pyclass, pystate, err := PyData(state.Data).Decode()
if err != nil { if err != nil {
return err // XXX err ctx return err // XXX err ctx
...@@ -46,7 +47,7 @@ func pySetState(obj PyStateful, state *mem.Buf) error { ...@@ -46,7 +47,7 @@ func pySetState(obj PyStateful, state *mem.Buf) error {
class := pyclassPath(pyclass) class := pyclassPath(pyclass)
if objClass := zclassOf(obj); class != objClass { if class != objClass {
// complain that pyclass changed // complain that pyclass changed
// (both ref and object data use pyclass so it indeed can be different) // (both ref and object data use pyclass so it indeed can be different)
return &wrongClassError{want: objClass, have: class} // XXX + err ctx return &wrongClassError{want: objClass, have: class} // XXX + err ctx
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment