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

.

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