support multi sequence un/serialization
authorMichael Wallner <mike@php.net>
Wed, 15 Dec 2021 12:49:55 +0000 (13:49 +0100)
committerMichael Wallner <mike@php.net>
Wed, 15 Dec 2021 12:51:13 +0000 (13:51 +0100)
ion.c
ion.stub.php
ion_arginfo.h
ion_private.h

diff --git a/ion.c b/ion.c
index b0730c55ef477c5197c17b629c5aeb560c98f9ed..4af7609dc84281a2db189ae5ff872c0eeee6b616 100644 (file)
--- a/ion.c
+++ b/ion.c
@@ -1311,9 +1311,12 @@ ZEND_METHOD(ion_Serializer_PHP, __construct)
        php_ion_serializer_php *obj = php_ion_obj(serializer_php, Z_OBJ_P(ZEND_THIS));
        PTR_CHECK(obj);
 
+       obj->serializer.call_magic = true;
+
        ZEND_PARSE_PARAMETERS_START(0, 3)
                Z_PARAM_OPTIONAL
                Z_PARAM_OBJ_OF_CLASS_OR_NULL(obj->opt, ce_Writer_Options)
+               Z_PARAM_BOOL(obj->serializer.multi_seq)
                Z_PARAM_BOOL(obj->serializer.call_magic)
                Z_PARAM_STR_OR_NULL(obj->serializer.call_custom)
        ZEND_PARSE_PARAMETERS_END();
@@ -1370,10 +1373,14 @@ ZEND_METHOD(ion_Serializer_PHP, serialize)
 ZEND_METHOD(ion_Unserializer_PHP, __construct)
 {
        php_ion_unserializer_php *obj = php_ion_obj(unserializer_php, Z_OBJ_P(ZEND_THIS));
+       PTR_CHECK(obj);
+
+       obj->unserializer.call_magic = true;
 
        ZEND_PARSE_PARAMETERS_START(0, 3)
                Z_PARAM_OPTIONAL
                Z_PARAM_OBJ_OF_CLASS_OR_NULL(obj->opt, ce_Reader_Options)
+               Z_PARAM_BOOL(obj->unserializer.multi_seq)
                Z_PARAM_BOOL(obj->unserializer.call_magic)
                Z_PARAM_STR_OR_NULL(obj->unserializer.call_custom)
        ZEND_PARSE_PARAMETERS_END();
index f3f81f3d27f53aa6cc143601385e6721ebf71614..4e85695c0cc1be2331fda935540258662cd4e698 100644 (file)
@@ -458,6 +458,7 @@ namespace ion\Serializer;
 class PHP implements \ion\Serializer {
     public function __construct(
         public readonly ?\ion\Writer\Options $writerOptions = null,
+        public readonly bool $multiSequence = false,
         public readonly bool $callMagicSerialize = true,
         public readonly ?string $callCustomSerialize = null,
     ) {}
@@ -469,6 +470,7 @@ namespace ion\Unserializer;
 class PHP implements \ion\Unserializer {
     public function __construct(
         public readonly ?\ion\Reader\Options $readerOptions = null,
+        public readonly bool $multiSequence = true,
         public readonly bool $callMagicUnserialize = true,
         public readonly ?string $callCustomUnserialize = null,
     ){}
index 4d5bc27f3b19536cc562b090ded37897150ca88d..ad2a80e72f66af89251b5db4fea0eb1ea008524a 100644 (file)
@@ -1,5 +1,5 @@
 /* This is a generated file, edit the .stub.php file instead.
- * Stub hash: 5dc8abb809cd14ed4c542ca5114bd4ceda42d70b */
+ * Stub hash: 4c467ccb7b924c30cc5471b9212f4bffe0b0ba31 */
 
 ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_ion_serialize, 0, 1, IS_STRING, 0)
        ZEND_ARG_TYPE_INFO(0, data, IS_MIXED, 0)
@@ -428,6 +428,7 @@ ZEND_END_ARG_INFO()
 
 ZEND_BEGIN_ARG_INFO_EX(arginfo_class_ion_Serializer_PHP___construct, 0, 0, 0)
        ZEND_ARG_OBJ_INFO_WITH_DEFAULT_VALUE(0, writerOptions, ion\\Writer\\Options, 1, "null")
+       ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, multiSequence, _IS_BOOL, 0, "false")
        ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, callMagicSerialize, _IS_BOOL, 0, "true")
        ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, callCustomSerialize, IS_STRING, 1, "null")
 ZEND_END_ARG_INFO()
@@ -438,6 +439,7 @@ ZEND_END_ARG_INFO()
 
 ZEND_BEGIN_ARG_INFO_EX(arginfo_class_ion_Unserializer_PHP___construct, 0, 0, 0)
        ZEND_ARG_OBJ_INFO_WITH_DEFAULT_VALUE(0, readerOptions, ion\\Reader\\Options, 1, "null")
+       ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, multiSequence, _IS_BOOL, 0, "true")
        ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, callMagicUnserialize, _IS_BOOL, 0, "true")
        ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, callCustomUnserialize, IS_STRING, 1, "null")
 ZEND_END_ARG_INFO()
@@ -1643,6 +1645,12 @@ static zend_class_entry *register_class_ion_Serializer_PHP(zend_class_entry *cla
        zend_declare_typed_property(class_entry, property_writerOptions_name, &property_writerOptions_default_value, ZEND_ACC_PUBLIC|ZEND_ACC_READONLY, NULL, (zend_type) ZEND_TYPE_INIT_CLASS(property_writerOptions_class_ion_Writer_Options, 0, MAY_BE_NULL));
        zend_string_release(property_writerOptions_name);
 
+       zval property_multiSequence_default_value;
+       ZVAL_UNDEF(&property_multiSequence_default_value);
+       zend_string *property_multiSequence_name = zend_string_init("multiSequence", sizeof("multiSequence") - 1, 1);
+       zend_declare_typed_property(class_entry, property_multiSequence_name, &property_multiSequence_default_value, ZEND_ACC_PUBLIC|ZEND_ACC_READONLY, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_BOOL));
+       zend_string_release(property_multiSequence_name);
+
        zval property_callMagicSerialize_default_value;
        ZVAL_UNDEF(&property_callMagicSerialize_default_value);
        zend_string *property_callMagicSerialize_name = zend_string_init("callMagicSerialize", sizeof("callMagicSerialize") - 1, 1);
@@ -1673,6 +1681,12 @@ static zend_class_entry *register_class_ion_Unserializer_PHP(zend_class_entry *c
        zend_declare_typed_property(class_entry, property_readerOptions_name, &property_readerOptions_default_value, ZEND_ACC_PUBLIC|ZEND_ACC_READONLY, NULL, (zend_type) ZEND_TYPE_INIT_CLASS(property_readerOptions_class_ion_Reader_Options, 0, MAY_BE_NULL));
        zend_string_release(property_readerOptions_name);
 
+       zval property_multiSequence_default_value;
+       ZVAL_UNDEF(&property_multiSequence_default_value);
+       zend_string *property_multiSequence_name = zend_string_init("multiSequence", sizeof("multiSequence") - 1, 1);
+       zend_declare_typed_property(class_entry, property_multiSequence_name, &property_multiSequence_default_value, ZEND_ACC_PUBLIC|ZEND_ACC_READONLY, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_BOOL));
+       zend_string_release(property_multiSequence_name);
+
        zval property_callMagicUnserialize_default_value;
        ZVAL_UNDEF(&property_callMagicUnserialize_default_value);
        zend_string *property_callMagicUnserialize_name = zend_string_init("callMagicUnserialize", sizeof("callMagicUnserialize") - 1, 1);
index 6aa8932a710dbeacc9820a715dc093d9d818e512..84b50b933cc7684e265e8ea9d7431f855c791814 100644 (file)
@@ -22,6 +22,7 @@ typedef struct php_ion_serializer {
 
        zend_string *call_custom;
        zend_bool call_magic;
+       zend_bool multi_seq;
 
        uint32_t level;
        HashTable *ids;
@@ -44,6 +45,7 @@ typedef struct php_ion_unserializer {
 
        zend_string *call_custom;
        zend_bool call_magic;
+       zend_bool multi_seq;
 
        uint32_t level;
        HashTable *ids;
@@ -1234,6 +1236,41 @@ static inline void php_ion_serialize_zval(php_ion_serializer *ser, zval *zv)
 
 php_ion_decl(serializer_php, Serializer_PHP, php_ion_serializer_php_dtor(obj));
 
+static inline void php_ion_serialize_ex(php_ion_serializer *ser, zval *zv)
+{
+       HashPosition pos;
+       HashTable *arr = NULL;
+
+       if (ser->multi_seq) {
+               if (Z_TYPE_P(zv) != IS_ARRAY || !zend_array_is_list(Z_ARRVAL_P(zv))) {
+                       zend_throw_exception_ex(spl_ce_InvalidArgumentException, IERR_INVALID_ARG,
+                                       "Expected a packed, consecutively numerically indexed array as argument to the multi sequence serializer");
+                       return;
+               }
+
+               arr = Z_ARRVAL_P(zv);
+
+               zend_hash_internal_pointer_reset_ex(arr, &pos);
+               zv = zend_hash_get_current_data_ex(arr, &pos);
+       }
+
+       while (zv) {
+               /* start off with a global PHP annotation instead of repeating it all over the place */
+               if (0 == php_ion_globals_serializer_step()) {
+                       ION_STRING is;
+                       ION_CHECK(ion_writer_add_annotation(ser->writer, ion_string_assign_cstr(&is, ZEND_STRL("PHP"))));
+               }
+               php_ion_serialize_zval(ser, zv);
+               php_ion_globals_serializer_exit();
+
+               if (!ser->multi_seq) {
+                       break;
+               }
+               zend_hash_move_forward_ex(arr, &pos);
+               zv = zend_hash_get_current_data_ex(arr, &pos);
+       }
+}
+
 void php_ion_serialize(php_ion_serializer *ser, zval *zv, zval *return_value)
 {
        zend_object *zo_opt = NULL, *zo_ser = NULL;
@@ -1261,14 +1298,9 @@ void php_ion_serialize(php_ion_serializer *ser, zval *zv, zval *return_value)
        ser->writer = writer->writer;
        ser->buffer = &writer->buffer.str;
 
-       /* start off with a global PHP annotation instead of repeating it all over the place */
-       if (0 == php_ion_globals_serializer_step()) {
-               ION_STRING is;
-               ION_CHECK(ion_writer_add_annotation(ser->writer, ion_string_assign_cstr(&is, ZEND_STRL("PHP"))),
-                               if (zo_ser) OBJ_RELEASE(zo_ser));
+       if (!EG(exception)) {
+               php_ion_serialize_ex(ser, zv);
        }
-       php_ion_serialize_zval(ser, zv);
-       php_ion_globals_serializer_exit();
 
        /* make sure to flush when done, else str.s might not contain everything until the writer is closed */
        ion_writer_flush(ser->writer, NULL);
@@ -1886,6 +1918,28 @@ unserialize_struct: ;
 
 php_ion_decl(unserializer_php, Unserializer_PHP, php_ion_unserializer_php_dtor(obj));
 
+static inline void php_ion_unserialize_ex(php_ion_unserializer *ser, zval *return_value)
+{
+       if (ser->multi_seq) {
+               array_init(return_value);
+       }
+
+       do {
+               zval tmp;
+               ZVAL_NULL(&tmp);
+               php_ion_globals_unserializer_step();
+               php_ion_unserialize_zval(ser, &tmp, NULL);
+               php_ion_globals_unserializer_exit();
+               ION_CATCH(zval_ptr_dtor(&tmp));
+
+               if (!ser->multi_seq) {
+                       RETURN_COPY_VALUE(&tmp);
+               } else if (ser->type != tid_EOF) {
+                       zend_hash_next_index_insert(Z_ARRVAL_P(return_value), &tmp);
+               }
+       } while (ser->type != tid_EOF);
+}
+
 void php_ion_unserialize(php_ion_unserializer *ser, zval *zdata, zval *return_value)
 {
        zend_object *zo_opt = NULL, *zo_ser = NULL;
@@ -1930,11 +1984,10 @@ void php_ion_unserialize(php_ion_unserializer *ser, zval *zdata, zval *return_va
 
        php_ion_reader_ctor(reader);
        ser->reader = reader->reader;
-       ION_CATCH();
 
-       php_ion_globals_unserializer_step();
-       php_ion_unserialize_zval(ser, return_value, NULL);
-       php_ion_globals_unserializer_exit();
+       if (!EG(exception)) {
+               php_ion_unserialize_ex(ser, return_value);
+       }
 
        OBJ_RELEASE(zo_reader);
        if (zo_opt)  {