nbsdgames/bubbob/statesaver.py.bak
2022-02-03 13:46:22 +03:30

136 lines
3.7 KiB
Python

"""
A pure Python implementation of statesaver.c that runs on top of PyPy.
See description in statesaver.c.
Difference: this supports new-style instances too.
Use statesaver.standard_build() as the inst_build() if you want.
"""
from _pickle_support import generator_new
import types
def standard_build(self):
if type(self) is types.InstanceType:
# old-style instance
return types.InstanceType(self.__class__)
else:
# new-style instance
return type(self).__new__(type(self))
# ____________________________________________________________
def not_copied(x, memo):
return x
def copy_custom_instance(x, memo):
try:
return memo[id(x)]
except KeyError:
y = x.inst_build()
memo[id(x)] = y
for key, value in x.__dict__.items():
y.__dict__[key] = copyrec(value, memo)
return y
def copy_tuple(x, memo):
return tuple([copyrec(item, memo) for item in x])
def copy_list(x, memo):
try:
return memo[id(x)]
except KeyError:
y = []
memo[id(x)] = y
for item in x:
y.append(copyrec(item, memo))
return y
def copy_dict(x, memo):
try:
return memo[id(x)]
except KeyError:
y = {}
memo[id(x)] = y
for key, value in x.items():
y[copyrec(key, memo)] = copyrec(value, memo)
return y
def copy_function(x, memo):
if not x.func_defaults:
return x # not copied
try:
return memo[id(x)]
except KeyError:
y = types.FunctionType(x.func_code, x.func_globals, x.func_name)
memo[id(x)] = y
y.func_defaults = copyrec(x.func_defaults, memo)
return y
def copy_method(x, memo):
return types.MethodType(copyrec(x.im_func, memo),
copyrec(x.im_self, memo),
x.im_class)
def copy_generator(x, memo):
try:
return memo[id(x)]
except KeyError:
y = generator_new(copyrec(x.gi_frame, memo), x.gi_running)
memo[id(x)] = y
return y
def copy_frame(x, memo):
try:
return memo[id(x)]
except KeyError:
frame_new, args, state = x.__reduce__()
y = frame_new(*args)
memo[id(x)] = y
newstate = []
for item in state:
if not (item is x.f_globals or item is x.f_builtins):
item = copyrec(item, memo)
newstate.append(item)
y.__setstate__(newstate)
return y
def copy_seqiter(x, memo):
try:
return memo[id(x)]
except KeyError:
# XXX self-recursion is not correctly handled here
seqiter_new, args = x.__reduce__()
args = [copyrec(item, memo) for item in args]
y = seqiter_new(*args)
memo[id(x)] = y
return y
# ____________________________________________________________
type_handlers = {tuple: copy_tuple,
list: copy_list,
dict: copy_dict,
types.FunctionType: copy_function,
types.MethodType: copy_method,
types.GeneratorType: copy_generator,
types.FrameType: copy_frame,
type(iter([])): copy_seqiter,
}
def no_handler_found(x, memo):
if hasattr(x, '__dict__') and hasattr(x.__class__, 'inst_build'):
handler = copy_custom_instance
else:
handler = not_copied
type_handlers[x.__class__] = handler
return handler(x, memo)
def copyrec(x, memo):
try:
cls = x.__class__
except AttributeError:
return x # 'cls' is likely an old-style class object
return type_handlers.get(cls, no_handler_found)(x, memo)
def copy(x):
return copyrec(x, {})