From 10313643fd3afce82bc6fa89812947693b9a89b7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Grubbstr=C3=B6m=20=28Grubba=29?= <grubba@grubba.org> Date: Fri, 21 Jan 2011 17:22:23 +0100 Subject: [PATCH] Serializer: First implementation of the Serializer interface. --- lib/modules/Serializer.pmod/module.pmod | 13 ++ src/builtin.cmod | 203 ++++++++++++++++++++++++ src/program.c | 67 ++++++++ src/program.h | 2 + 4 files changed, 285 insertions(+) create mode 100644 lib/modules/Serializer.pmod/module.pmod diff --git a/lib/modules/Serializer.pmod/module.pmod b/lib/modules/Serializer.pmod/module.pmod new file mode 100644 index 0000000000..ff825b6ec6 --- /dev/null +++ b/lib/modules/Serializer.pmod/module.pmod @@ -0,0 +1,13 @@ + +//! Serialization interface. +//! +//! This module contains APIs to simplify +//! serialization and deserialization of +//! objects. +//! +//! @seealso +//! @[serialize()], @[deserialize()] + +constant Serializable = Builtin.Serializable; +constant serialize = Builtin.serialize; +constant deserialize = Builtin.deserialize; diff --git a/src/builtin.cmod b/src/builtin.cmod index 20d63b7c10..7bba11ca18 100644 --- a/src/builtin.cmod +++ b/src/builtin.cmod @@ -3759,6 +3759,209 @@ PIKECLASS SqlNull /*! @endclass */ +/*! @endmodule + */ + +/*! @module Serializer + */ + +/*! @class Serializable + *! + *! The base class for serializable objects. + *! + *! Inherit this class in classes that need to be serializable. + *! + *! @seealso + *! @[Serializer.serialize()], @[Serializer.deserialize()] + */ +PIKECLASS Serializable +{ + static void low_serialize(int i, struct svalue *fun, int use_setter) + { + struct inherit *inh; + struct program *p = Pike_fp->current_object->prog; + struct svalue *save_sp = Pike_sp; + + inh = p->inherits + i; + p = inh->prog; + + for (i = 0; i < p->num_identifier_references; i++) { + struct reference *ref = PTR_FROM_INT(p, i); + struct identifier *id; + if ((ref->id_flags & ID_HIDDEN) || + ((ref->id_flags & (ID_PRIVATE|ID_INHERITED)) == + (ID_PRIVATE|ID_INHERITED))) { + continue; + } + id = ID_FROM_PTR(p, ref); + if (!IDENTIFIER_IS_VARIABLE(id->identifier_flags)) { + continue; + } + ref_push_string(id->name); + ref_push_type_value(id->type); + if (use_setter) { + push_function(get_setter(Pike_fp->current_object, + i + inh->identifier_level), + f_Setter_cq__backtick_28_29_fun_num); + } else { + low_object_index_no_free(Pike_sp, Pike_fp->current_object, + i + inh->identifier_level); + Pike_sp++; + } + apply_svalue(fun, 3); + pop_stack(); + } + if (Pike_sp != save_sp) { + /* Not likely, but... */ + pop_n_elems(Pike_sp - save_sp); + } + } + + /*! @decl void _serialize(object o, @ + *! function(string, type, mixed:void) serializer) + *! + *! Dispatch function for serialization. + *! + *! @param o + *! Object to serialize. Always a context of the current object. + *! + *! @param serializer + *! Function to be called once for every variable + *! in the inheriting class. + *! + *! The @[serializer] function will be called with three arguments: + *! @dl + *! @item + *! @tt{symbol@} - The symbol name. + *! @item + *! @tt{symbol_type@} - The type of the symbol. + *! @item + *! @tt{value@} - The value of the symbol. + *! @enddl + *! + *! @note + *! The symbols will be listed in the order they were defined + *! in the class. + *! + *! @note + *! This function is typically called via @[Serializer.serialize()]. + */ + PIKEFUN void _serialize(object o, + function(string, type, mixed:void) serializer) + flags ID_PROTECTED; + rawtype tFunc(tObj tFunc(tStr tType(tMix) tMix, tVoid), tVoid); + { + if (o != Pike_fp->current_object) { + SIMPLE_BAD_ARG_ERROR("_serialize", 1, "this"); + } + low_serialize(Pike_sp[-args].subtype, serializer, 0); + pop_n_elems(args); + push_int(0); + } + + /*! @decl _deserialize(object o, @ + *! function(string, type, @ + *! function(mixed:void): mixed) deserializer) + *! + *! Dispatch function for deserialization. + *! + *! @param o + *! Object to serialize. Always a context of the current object. + *! + *! @param deserializer + *! Function to be called once for every variable + *! in the inheriting class. + *! + *! The @[deserializer] function will be called with three arguments: + *! @dl + *! @item + *! @tt{symbol@} - The symbol name. + *! @item + *! @tt{symbol_type@} - The type of the symbol. + *! @item + *! @tt{setter@} - Function that sets the symbol value. + *! @enddl + *! + *! @note + *! The symbols will be listed in the order they were defined + *! in the class. + *! + *! @note + *! This function is typically called via @[Serializer.deserialize()]. + */ + PIKEFUN void _deserialize(object o, + function(string, type, + function(mixed:void): mixed) deserializer) + flags ID_PROTECTED; + rawtype tFunc(tObj tFunc(tStr tType(tMix) tFunc(tMix, tVoid), tVoid), tVoid); + { + if (o != Pike_fp->current_object) { + SIMPLE_BAD_ARG_ERROR("_serialize", 1, "this"); + } + low_serialize(Pike_sp[-args].subtype, deserializer, 1); + pop_n_elems(args); + push_int(0); + } +} +/*! @endclass + */ + +/*! @decl void serialize(object o, @ + *! function(string, type, mixed:void) serializer) + *! + *! Call @[LFUN::_serialize()] in @[o]. + *! + *! @seealso + *! @[deserialize()], @[LFUN::_serialize()], + *! @[Serializable()->_serialize()] + */ +PIKEFUN void serialize(object o, + function(string, type, mixed:void) serializer) + rawtype tFunc(tObj tFunc(tStr tType(tMix) tMix, tVoid), tVoid); +{ + struct inherit *inh; + struct program *p; + ptrdiff_t fun; + if (!(p = o->prog)) { + Pike_error("Indexing a destructed object.\n"); + } + inh = p->inherits + Pike_sp[-args].subtype; + p = inh->prog; + if ((fun = low_find_lfun(p, LFUN__SERIALIZE)) == -1) { + Pike_error("Serialization not supported by object.\n"); + } + apply_low(o, fun + inh->identifier_level, args); +} + +/*! @decl void deserialize(object o, @ + *! function(string, type, + *! function(mixed:void):void) deserializer) + *! + *! Call @[LFUN::_deserialize()] in @[o]. + *! + *! @seealso + *! @[serialize()], @[LFUN::_deserialize()], + *! @[Serializable()->_deserialize()] + */ +PIKEFUN void deserialize(object o, + function(string, type, + function(mixed:void):void) deserializer) + rawtype tFunc(tObj tFunc(tStr tType(tMix) tFunc(tMix, tVoid), tVoid), tVoid); +{ + struct inherit *inh; + struct program *p; + ptrdiff_t fun; + if (!(p = o->prog)) { + Pike_error("Indexing a destructed object.\n"); + } + inh = p->inherits + Pike_sp[-args].subtype; + p = inh->prog; + if ((fun = low_find_lfun(p, LFUN__DESERIALIZE)) == -1) { + Pike_error("Deserialization not supported by object.\n"); + } + apply_low(o, fun + inh->identifier_level, args); +} + /*! @endmodule */ diff --git a/src/program.c b/src/program.c index 6a1016fd2c..d68ee65e99 100644 --- a/src/program.c +++ b/src/program.c @@ -160,6 +160,8 @@ const char *const lfun_names[] = { /* NOTE: After this point there are only fake lfuns. */ "_search", "_types", + "_serialize", + "_deserialize", }; struct pike_string *lfun_strings[NELEM(lfun_names)]; @@ -218,6 +220,8 @@ static const char *const raw_lfun_types[] = { /* NOTE: After this point there are only fake lfuns. */ tFuncV(tZero tOr(tZero, tVoid), tVoid, tMix), /* "_search", */ tFuncV(tNone,tVoid,tArray), /* "_types", */ + tFuncV(tObj tZero, tVoid, tVoid), /* "_serialize", */ + tFuncV(tObj tZero, tVoid, tVoid), /* "_deserialize", */ }; /* These two are not true LFUNs! */ @@ -1149,6 +1153,69 @@ static struct pike_type *lfun_setter_type_string = NULL; *! @[::_types()] */ +/*! @decl void lfun::_serialize(object o, @ + *! function(string, type, mixed:void) serializer) + *! + *! Dispatch function for @[Serializer.serialize()]. + *! + *! @param o + *! Object to serialize. Always a context of the current object. + *! + *! @param serializer + *! Function to be called once for every variable + *! to serialize. + *! + *! The @[serializer] function expects to be called with three arguments: + *! @dl + *! @item + *! @tt{symbol@} - The symbol name. + *! @item + *! @tt{symbol_type@} - The type of the symbol. + *! @item + *! @tt{value@} - The value of the symbol. + *! @enddl + *! + *! @note + *! A default implementation of @[lfun::_serialize()] and + *! @[lfun::_deserialize()] is available in @[Serializer.Serializable]. + *! + *! @seealso + *! @[lfun::_deserialize()], @[Serializer.serialize()], + *! @[Serializer.Serializable()->_serialize()] + */ + +/*! @decl void lfun::_deserialize(object o, @ + *! function(string, type, @ + *! function(mixed:void): mixed) deserializer) + *! + *! Dispatch function for @[Serialization.deserialize()]. + *! + *! @param o + *! Object to serialize. Always a context of the current object. + *! + *! @param deserializer + *! Function to be called once for every variable + *! to serialize. + *! + *! The @[deserializer] function expects to be called with three arguments: + *! @dl + *! @item + *! @tt{symbol@} - The symbol name. + *! @item + *! @tt{symbol_type@} - The type of the symbol. + *! @item + *! @tt{setter@} - Function that sets the symbol value. + *! @enddl + *! + *! @note + *! A default implementation of @[lfun::_serialize()] and + *! @[lfun::_deserialize()] is available in @[Serializer.Serializable]. + *! + *! @seealso + *! @[lfun::_serialize()], @[Serializer.deserialize()], + *! @[Serializer.Serializable()->_deserialize()] + */ + /*! @decl mixed lfun::`symbol() *! @decl mixed lfun::`->symbol() *! diff --git a/src/program.h b/src/program.h index 6348474a7c..c685659811 100644 --- a/src/program.h +++ b/src/program.h @@ -109,6 +109,8 @@ extern struct pike_string *type_check_system_string; */ #define LFUN__SEARCH 45 #define LFUN__TYPES 46 +#define LFUN__SERIALIZE 47 +#define LFUN__DESERIALIZE 48 extern const char *const lfun_names[]; -- GitLab