initial ci
authorMichael Wallner <mike@php.net>
Mon, 6 Dec 2021 20:27:40 +0000 (21:27 +0100)
committerMichael Wallner <mike@php.net>
Mon, 6 Dec 2021 20:27:40 +0000 (21:27 +0100)
14 files changed:
.editorconfig [new file with mode: 0644]
.gitignore [new file with mode: 0644]
AUTHORS [new file with mode: 0644]
CONTRIBUTING.md [new file with mode: 0644]
CREDITS [new file with mode: 0644]
EXPERIMENTAL [new file with mode: 0644]
LICENSE [new file with mode: 0644]
config.m4 [new file with mode: 0644]
gen_stub.php.diff [new file with mode: 0644]
ion.c [new file with mode: 0644]
ion.stub.php [new file with mode: 0644]
ion_arginfo.h [new file with mode: 0644]
ion_private.h [new file with mode: 0644]
php_ion.h [new file with mode: 0644]

diff --git a/.editorconfig b/.editorconfig
new file mode 100644 (file)
index 0000000..7105c46
--- /dev/null
@@ -0,0 +1,27 @@
+; see http://editorconfig.org
+root = true
+
+[*]
+end_of_line = lf
+insert_final_newline = true
+indent_style = tab
+charset = utf-8
+trim_trailing_whitespace = true
+
+[*.php]
+indent_style = space
+indent_size = 4
+
+[*.md]
+trim_trailing_whitespace = false
+
+[*.json]
+indent_style = space
+indent_size = 4
+
+[package.xml]
+indent_style = space
+indent_size = 1
+
+[config.w32]
+end_of_line = crlf
diff --git a/.gitignore b/.gitignore
new file mode 100644 (file)
index 0000000..ae434fe
--- /dev/null
@@ -0,0 +1,41 @@
+*.lo
+*.la
+.libs
+acinclude.m4
+aclocal.m4
+autom4te.cache
+build
+config.guess
+config.h
+config.h.in
+config.log
+config.nice
+config.status
+config.sub
+configure
+configure.ac
+configure.in
+include
+install-sh
+libtool
+ltmain.sh
+Makefile
+Makefile.fragments
+Makefile.global
+Makefile.objects
+missing
+mkinstalldirs
+modules
+php_test_results_*.txt
+phpt.*
+run-test-info.php
+run-tests.php
+tests/**/*.diff
+tests/**/*.out
+tests/**/*.php
+tests/**/*.exp
+tests/**/*.log
+tests/**/*.sh
+tests/**/*.db
+tests/**/*.mem
+tmp-php.ini
diff --git a/AUTHORS b/AUTHORS
new file mode 100644 (file)
index 0000000..67bbd91
--- /dev/null
+++ b/AUTHORS
@@ -0,0 +1 @@
+Michael Wallner <mike@php.net>
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
new file mode 100644 (file)
index 0000000..968bd44
--- /dev/null
@@ -0,0 +1,39 @@
+# Contributor Code of Conduct
+
+As contributors and maintainers of this project, and in the interest of
+fostering an open and welcoming community, we pledge to respect all people who
+contribute through reporting issues, posting feature requests, updating
+documentation, submitting pull requests or patches, and other activities.
+
+We are committed to making participation in this project a harassment-free
+experience for everyone, regardless of level of experience, gender, gender
+identity and expression, sexual orientation, disability, personal appearance,
+body size, race, ethnicity, age, religion, or nationality.
+
+Examples of unacceptable behavior by participants include:
+
+* The use of sexualized language or imagery
+* Personal attacks
+* Trolling or insulting/derogatory comments
+* Public or private harassment
+* Publishing other's private information, such as physical or electronic
+  addresses, without explicit permission
+* Other unethical or unprofessional conduct.
+
+Project maintainers have the right and responsibility to remove, edit, or reject
+comments, commits, code, wiki edits, issues, and other contributions that are
+not aligned to this Code of Conduct. By adopting this Code of Conduct, project
+maintainers commit themselves to fairly and consistently applying these
+principles to every aspect of managing this project. Project maintainers who do
+not follow or enforce the Code of Conduct may be permanently removed from the
+project team.
+
+This code of conduct applies both within project spaces and in public spaces
+when an individual is representing the project or its community.
+
+Instances of abusive, harassing, or otherwise unacceptable behavior may be
+reported by opening an issue or contacting one or more of the project maintainers.
+
+This Code of Conduct is adapted from the
+[Contributor Covenant](http://contributor-covenant.org), version 1.2.0,
+available at http://contributor-covenant.org/version/1/2/0/.
diff --git a/CREDITS b/CREDITS
new file mode 100644 (file)
index 0000000..e0f497d
--- /dev/null
+++ b/CREDITS
@@ -0,0 +1,2 @@
+ion
+Michael Wallner
\ No newline at end of file
diff --git a/EXPERIMENTAL b/EXPERIMENTAL
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/LICENSE b/LICENSE
new file mode 100644 (file)
index 0000000..2cb49b2
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,22 @@
+Copyright (c) 2021, Michael Wallner <mike@php.net>.
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+    * Redistributions of source code must retain the above copyright notice,
+      this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
+FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/config.m4 b/config.m4
new file mode 100644 (file)
index 0000000..4d85c67
--- /dev/null
+++ b/config.m4
@@ -0,0 +1,56 @@
+
+PHP_ARG_WITH([ion],
+  [for ion support],
+  [AS_HELP_STRING([--with-ion],
+    [path to libion])],
+  [no])
+
+if test "$PHP_ION" != "no"; then
+
+  SEARCH_PATH="/usr/local /usr"     # you might want to change this
+  SEARCH_FOR="/include/ionc/ion.h"  # you most likely want to change this
+  if test -r $PHP_ION/$SEARCH_FOR; then # path given as parameter
+    ION_DIR=$PHP_ION
+  else # search default path list
+    AC_MSG_CHECKING([for ion files in default path])
+    for i in $SEARCH_PATH ; do
+      if test -r $i/$SEARCH_FOR; then
+        ION_DIR=$i
+        AC_MSG_RESULT(found in $i)
+      fi
+    done
+  fi
+  dnl
+  if test -z "$ION_DIR"; then
+    AC_MSG_RESULT([not found])
+    AC_MSG_ERROR([Please reinstall the ion distribution])
+  fi
+
+  PHP_ADD_INCLUDE($ION_DIR/include)
+
+  LIBNAME=ionc
+  LIBSYMBOL=ion_error_to_str
+  PHP_CHECK_LIBRARY($LIBNAME, $LIBSYMBOL,
+  [
+    PHP_ADD_LIBRARY_WITH_PATH($LIBNAME, $ION_DIR/$PHP_LIBDIR, ION_SHARED_LIBADD)
+  ],[
+    AC_MSG_ERROR([could not link with ionc library.])
+  ],[
+    -L$ION_DIR/$PHP_LIBDIR -lm
+  ])
+  LIBNAME=decNumber
+  LIBSYMBOL=decQuadFromInt32
+  PHP_CHECK_LIBRARY($LIBNAME, $LIBSYMBOL,
+  [
+    PHP_ADD_LIBRARY_WITH_PATH($LIBNAME, $ION_DIR/$PHP_LIBDIR, ION_SHARED_LIBADD)
+  ],[
+    AC_MSG_ERROR([could not link with ionc library.])
+  ],[
+    -L$ION_DIR/$PHP_LIBDIR -lm
+  ])
+
+  PHP_SUBST(ION_SHARED_LIBADD)
+  AC_DEFINE(HAVE_ION, 1, [ Have ion support ])
+
+  PHP_NEW_EXTENSION(ion, ion.c, $ext_shared)
+fi
diff --git a/gen_stub.php.diff b/gen_stub.php.diff
new file mode 100644 (file)
index 0000000..d01ec3d
--- /dev/null
@@ -0,0 +1,90 @@
+diff --git a/build/gen_stub.php b/build/gen_stub.php
+index 5f74d26dbc3..01a19988161 100755
+--- a/build/gen_stub.php
++++ b/build/gen_stub.php
+@@ -793,7 +793,7 @@ class FunctionName implements FunctionOrMethodName {
+     }
+     public function getDeclarationName(): string {
+-        return $this->name->getLast();
++        return strtr($this->name->toString(), "\\", "_");
+     }
+     public function getDeclaration(): string {
+@@ -1152,8 +1152,8 @@ class FuncInfo {
+             if ($namespace) {
+                 // Render A\B as "A\\B" in C strings for namespaces
+                 return sprintf(
+-                    "\tZEND_NS_FE(\"%s\", %s, %s)\n",
+-                    addslashes($namespace), $declarationName, $this->getArgInfoName());
++                    "\tZEND_NS_RAW_FENTRY(\"%s\", \"%s\", ZEND_FN(%s), %s, 0)\n",
++                    addslashes($namespace), substr((string)$this->name, strlen($namespace)+1), $declarationName, $this->getArgInfoName());
+             } else {
+                 return sprintf("\tZEND_FE(%s, %s)\n", $declarationName, $this->getArgInfoName());
+             }
+@@ -1608,7 +1608,7 @@ class EnumCaseInfo {
+     public function getDeclaration(): string {
+         $escapedName = addslashes($this->name);
+         if ($this->value === null) {
+-            $code = "\n\tzend_enum_add_case_cstr(class_entry, \"$escapedName\", NULL);\n";
++            $code = "\tzend_enum_add_case_cstr(class_entry, \"$escapedName\", NULL);\n";
+         } else {
+             $evaluator = new ConstExprEvaluator(function (Expr $expr) {
+                 throw new Exception("Enum case $this->name has an unsupported value");
+@@ -2369,7 +2369,7 @@ function parseFunctionLike(
+ function parseProperty(
+     Name $class,
+     int $flags,
+-    Stmt\PropertyProperty $property,
++    Stmt\PropertyProperty|Node\Param $property,
+     ?Node $type,
+     ?DocComment $comment,
+     PrettyPrinterAbstract $prettyPrinter
+@@ -2404,13 +2404,23 @@ function parseProperty(
+         }
+     }
++    $default = $property->default;
++    if ($property instanceof Node\Param) {
++        $name = $property->var->name;
++        if ($property->flags & Stmt\Class_::MODIFIER_READONLY) {
++            $default = null;
++        }
++    } else {
++        $name = $property->name;
++    }
++
+     return new PropertyInfo(
+-        new PropertyName($class, $property->name->__toString()),
++        new PropertyName($class, (string) $name),
+         $flags,
+         $propertyType,
+         $phpDocType ? Type::fromString($phpDocType) : null,
+-        $property->default,
+-        $property->default ? $prettyPrinter->prettyPrintExpr($property->default) : null,
++        $default,
++        $default ? $prettyPrinter->prettyPrintExpr($default) : null,
+         $isDocReadonly
+     );
+ }
+@@ -2594,6 +2604,20 @@ function handleStatements(FileInfo $fileInfo, array $stmts, PrettyPrinterAbstrac
+                         $classStmt,
+                         $cond
+                     );
++                    if ($classStmt->name->toString() === "__construct") {
++                        foreach ($classStmt->params as $param) {
++                            if ($param->flags) {
++                                $propertyInfos[] = parseProperty(
++                                    $className,
++                                    $param->flags,
++                                    $param,
++                                    $param->type,
++                                    $param->getDocComment(),
++                                    $prettyPrinter
++                                );
++                            }
++                        }
++                    }
+                 } else if ($classStmt instanceof Stmt\EnumCase) {
+                     $enumCaseInfos[] = new EnumCaseInfo(
+                         $classStmt->name->toString(), $classStmt->expr);
diff --git a/ion.c b/ion.c
new file mode 100644 (file)
index 0000000..a4915e3
--- /dev/null
+++ b/ion.c
@@ -0,0 +1,1536 @@
+/*
+    +--------------------------------------------------------------------+
+    | PECL :: ion                                                        |
+    +--------------------------------------------------------------------+
+    | Redistribution and use in source and binary forms, with or without |
+    | modification, are permitted provided that the conditions mentioned |
+    | in the accompanying LICENSE file are met.                          |
+    +--------------------------------------------------------------------+
+    | Copyright (c) 2021, Michael Wallner <mike@php.net>                 |
+    +--------------------------------------------------------------------+
+*/
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include "php.h"
+#include "ext/standard/info.h"
+
+#include "Zend/zend_enum.h"
+#include "Zend/zend_exceptions.h"
+#include "Zend/zend_closures.h"
+#include "Zend/zend_interfaces.h"
+#include "Zend/zend_smart_str.h"
+
+#include "ext/date/php_date.h"
+#include "ext/spl/spl_exceptions.h"
+#include "ext/spl/spl_iterators.h"
+
+#define DECNUMDIGITS 34 /* DECQUAD_Pmax */
+#include "ionc/ion.h"
+
+#include "php_ion.h"
+#define ZEND_ARG_VARIADIC_OBJ_TYPE_MASK(pass_by_ref, name, classname, type_mask, default_value) \
+       { #name, ZEND_TYPE_INIT_CLASS_CONST_MASK(#classname, type_mask | _ZEND_ARG_INFO_FLAGS(pass_by_ref, 1, 0)), default_value },
+#include "ion_arginfo.h"
+#include "ion_private.h"
+
+ZEND_METHOD(ion_Symbol_ImportLocation, __construct)
+{
+       zend_long location;
+       php_ion_symbol_iloc *obj = php_ion_obj(symbol_iloc, Z_OBJ_P(ZEND_THIS));
+
+       PTR_CHECK(obj);
+
+       ZEND_PARSE_PARAMETERS_START(2, 2)
+               Z_PARAM_STR(obj->name)
+               Z_PARAM_LONG(location)
+       ZEND_PARSE_PARAMETERS_END();
+
+       obj->loc.location = location;
+       php_ion_symbol_iloc_ctor(obj);
+}
+ZEND_METHOD(ion_Symbol, __construct)
+{
+       zend_long sid = -1;
+       php_ion_symbol *obj = php_ion_obj(symbol, Z_OBJ_P(ZEND_THIS));
+
+       PTR_CHECK(obj);
+
+       ZEND_PARSE_PARAMETERS_START(1, 3)
+               Z_PARAM_STR(obj->value)
+               Z_PARAM_OPTIONAL
+               Z_PARAM_LONG(sid)
+               Z_PARAM_OBJ_OF_CLASS_OR_NULL(obj->iloc, ce_Symbol_ImportLocation)
+       ZEND_PARSE_PARAMETERS_END();
+
+       obj->sym.sid = sid;
+       php_ion_symbol_ctor(obj);
+}
+ZEND_METHOD(ion_Symbol, equals)
+{
+       zend_object *other_obj;
+       php_ion_symbol *sym = php_ion_obj(symbol, Z_OBJ_P(ZEND_THIS));
+
+       OBJ_CHECK(sym);
+
+       ZEND_PARSE_PARAMETERS_START(1, 1)
+               Z_PARAM_OBJ_OF_CLASS(other_obj, ce_Symbol)
+       ZEND_PARSE_PARAMETERS_END();
+
+       BOOL eq = FALSE;
+       iERR err = ion_symbol_is_equal(
+               &sym->sym,
+               &php_ion_obj(symbol, other_obj)->sym, &eq);
+       ION_CHECK(err);
+       RETVAL_BOOL(eq);
+}
+ZEND_METHOD(ion_Timestamp, __construct)
+{
+       zend_long precision;
+       zend_string *fmt = NULL, *dt = NULL;
+       zval *tz = NULL;
+       php_ion_timestamp *obj = php_ion_obj(timestamp, Z_OBJ_P(ZEND_THIS));
+       PTR_CHECK(obj);
+
+       ZEND_PARSE_PARAMETERS_START(1, 4)
+               Z_PARAM_LONG(precision)
+               Z_PARAM_OPTIONAL
+               Z_PARAM_STR_OR_NULL(fmt)
+               Z_PARAM_STR(dt)
+               Z_PARAM_ZVAL(tz)
+       ZEND_PARSE_PARAMETERS_END();
+
+       php_ion_timestamp_ctor(obj, precision, fmt, dt, tz);
+}
+ZEND_METHOD(ion_Timestamp, __toString)
+{
+       php_ion_timestamp *obj = php_ion_obj(timestamp, Z_OBJ_P(ZEND_THIS));
+       OBJ_CHECK(obj);
+
+       ZEND_PARSE_PARAMETERS_NONE();
+
+       zval fmt;
+       ZVAL_NULL(&fmt);
+       zend_call_method_with_1_params(&obj->std, obj->std.ce, NULL, "format", return_value,
+               zend_read_property(obj->std.ce, &obj->std, ZEND_STRL("format"), 0, &fmt));
+}
+ZEND_METHOD(ion_Decimal, __construct)
+{
+       php_ion_decimal *obj = php_ion_obj(decimal, Z_OBJ_P(ZEND_THIS));
+       PTR_CHECK(obj);
+
+       zend_long num;
+       zend_string *zstr;
+       ZEND_PARSE_PARAMETERS_START(1, 2)
+               Z_PARAM_STR_OR_LONG(zstr, num)
+               Z_PARAM_OPTIONAL
+               Z_PARAM_OBJ_OF_CLASS_OR_NULL(obj->ctx, ce_Decimal_Context)
+       ZEND_PARSE_PARAMETERS_END();
+
+       if (zstr) {
+               ION_CHECK(ion_decimal_from_string(&obj->dec, zstr->val,
+                       obj->ctx ? &php_ion_obj(decimal_ctx, obj->ctx)->ctx : NULL));
+       } else if (num <= INT32_MAX && num >= INT32_MIN) {
+               ION_CHECK(ion_decimal_from_int32(&obj->dec, num));
+       } else if (num > 0 && num <= UINT32_MAX) {
+               ION_CHECK(ion_decimal_from_uint32(&obj->dec, num));
+       } else {
+               zend_throw_exception_ex(spl_ce_OverflowException, 0,
+                       "Integer value out of bounds: " ZEND_LONG_FMT " (INT32_MIN < n < UINT32_MAX)", num);
+               return;
+       }
+
+       php_ion_decimal_ctor(obj);
+}
+ZEND_METHOD(ion_Decimal, equals)
+{
+       php_ion_decimal *obj = php_ion_obj(decimal, Z_OBJ_P(ZEND_THIS));
+       PTR_CHECK(obj);
+
+       zend_object *dec_obj;
+       ZEND_PARSE_PARAMETERS_START(1, 1)
+               Z_PARAM_OBJ_OF_CLASS(dec_obj, ce_Decimal)
+       ZEND_PARSE_PARAMETERS_END();
+
+       BOOL is = FALSE;
+       ION_CHECK(ion_decimal_equals(&obj->dec, &php_ion_obj(decimal, dec_obj)->dec,
+               obj->ctx ? &php_ion_obj(decimal_ctx, obj->ctx)->ctx : NULL, &is));
+       RETURN_BOOL(is);
+}
+ZEND_METHOD(ion_Decimal, zero)
+{
+       php_ion_decimal *obj = php_ion_obj(decimal, Z_OBJ_P(ZEND_THIS));
+       PTR_CHECK(obj);
+
+       ZEND_PARSE_PARAMETERS_NONE();
+
+       ION_CHECK(ion_decimal_zero(&obj->dec));
+}
+ZEND_METHOD(ion_Decimal, __toString)
+{
+       php_ion_decimal *obj = php_ion_obj(decimal, Z_OBJ_P(ZEND_THIS));
+       PTR_CHECK(obj);
+
+       ZEND_PARSE_PARAMETERS_NONE();
+
+       RETURN_STR(php_ion_decimal_to_string(&obj->dec));
+}
+ZEND_METHOD(ion_Decimal, toInt)
+{
+       php_ion_decimal *obj = php_ion_obj(decimal, Z_OBJ_P(ZEND_THIS));
+       PTR_CHECK(obj);
+
+       ZEND_PARSE_PARAMETERS_NONE();
+
+       int32_t i32 = 0;
+       iERR err = ion_decimal_to_int32(&obj->dec,
+               obj->ctx ? &php_ion_obj(decimal_ctx, obj->ctx)->ctx : NULL, &i32);
+       if (IERR_OK == err) {
+               RETURN_LONG(i32);
+       }
+       if (!ion_decimal_is_negative(&obj->dec)) {
+               uint32_t u32 = 0;
+               err = ion_decimal_to_uint32(&obj->dec,
+                       obj->ctx ? &php_ion_obj(decimal_ctx, obj->ctx)->ctx : NULL, &u32);
+               if (IERR_OK == err) {
+                       RETURN_LONG(u32);
+               }
+       }
+       ION_CHECK(err);
+}
+ZEND_METHOD(ion_Reader_Options, __construct)
+{
+       php_ion_reader_options *opt = php_ion_obj(reader_options, Z_OBJ_P(ZEND_THIS));
+       zend_bool ret_sys_val = false, skip_validation = false;
+       zend_long ch_nl = 0xa, max_depth = 10, max_ann, max_ann_buf = 512,
+                       sym_thr = 0x1000, uval_thr = 0x1000, chunk_thr = 0x1000, alloc_pgsz = 0x1000;
+
+       PTR_CHECK(opt);
+
+       ZEND_PARSE_PARAMETERS_START(0, 13)
+               Z_PARAM_OPTIONAL
+        // public readonly ?\ion\Catalog $catalog = null,
+               Z_PARAM_OBJ_OF_CLASS_OR_NULL(opt->cat, ce_Catalog)
+        // public readonly ?\ion\Decimal\Context $decimalContext = null,
+               Z_PARAM_OBJ_OF_CLASS_OR_NULL(opt->dec_ctx, ce_Decimal_Context)
+        // public readonly ?\Closure $onContextChange = null,
+               Z_PARAM_OBJ_OF_CLASS_OR_NULL(opt->cb, zend_ce_closure);
+        // public readonly bool $returnSystemValues = false,
+               Z_PARAM_BOOL(ret_sys_val)
+        // public readonly int $newLine = 0xa,
+               Z_PARAM_LONG(ch_nl)
+        // public readonly int $maxContainerDepth = 10,
+               Z_PARAM_LONG(max_depth)
+        // public readonly int $maxAnnotations = 10,
+               Z_PARAM_LONG(max_ann)
+        // public readonly int $maxAnnotationBuffered = 512,
+               Z_PARAM_LONG(max_ann_buf)
+        // public readonly int $symbolThreshold = 4096,
+               Z_PARAM_LONG(sym_thr)
+        // public readonly int $userValueThreshold = 4096,
+               Z_PARAM_LONG(uval_thr)
+        // public readonly int $chunkThreshold = 4096,
+               Z_PARAM_LONG(chunk_thr)
+        // public readonly int $allocationPageSize = 4096,
+               Z_PARAM_LONG(alloc_pgsz)
+        // public readonly bool $skipCharacterValidation = false,
+               Z_PARAM_BOOL(skip_validation)
+       ZEND_PARSE_PARAMETERS_END();
+
+       opt->opt.context_change_notifier = EMPTY_READER_CHANGE_NOTIFIER;
+       if (opt->cb) {
+               update_property_obj(&opt->std, ZEND_STRL("onContextChange"), opt->cb);
+       }
+       if (opt->cat) {
+               update_property_obj(&opt->std, ZEND_STRL("catalog"), opt->cat);
+               opt->opt.pcatalog = php_ion_obj(catalog, opt->cat)->cat;
+       }
+       if (opt->dec_ctx) {
+               update_property_obj(&opt->std, ZEND_STRL("decimalContext"), opt->dec_ctx);
+               opt->opt.decimal_context = &php_ion_obj(decimal_ctx, opt->dec_ctx)->ctx;
+       }
+       zend_update_property_bool(opt->std.ce, &opt->std, ZEND_STRL("returnSystemValues"),
+               opt->opt.return_system_values = ret_sys_val);
+       zend_update_property_long(opt->std.ce, &opt->std, ZEND_STRL("newLine"),
+               opt->opt.new_line_char = ch_nl);
+       zend_update_property_long(opt->std.ce, &opt->std, ZEND_STRL("maxContainerDepth"),
+               opt->opt.max_container_depth = max_depth);
+       zend_update_property_long(opt->std.ce, &opt->std, ZEND_STRL("maxAnnotationCount"),
+               opt->opt.max_annotation_count = max_ann);
+       zend_update_property_long(opt->std.ce, &opt->std, ZEND_STRL("maxAnnotationBuffered"),
+               opt->opt.max_annotation_buffered = max_ann_buf);
+       zend_update_property_long(opt->std.ce, &opt->std, ZEND_STRL("symbolThreshold"),
+               opt->opt.symbol_threshold = sym_thr);
+       zend_update_property_long(opt->std.ce, &opt->std, ZEND_STRL("userValueThreshold"),
+               opt->opt.user_value_threshold = uval_thr);
+       zend_update_property_long(opt->std.ce, &opt->std, ZEND_STRL("chunkThreshold"),
+               opt->opt.chunk_threshold = chunk_thr);
+       zend_update_property_long(opt->std.ce, &opt->std, ZEND_STRL("allocationPageSize"),
+               opt->opt.allocation_page_size = alloc_pgsz);
+       zend_update_property_long(opt->std.ce, &opt->std, ZEND_STRL("skipCharacterValidation"),
+               opt->opt.skip_character_validation = skip_validation);
+}
+ZEND_METHOD(ion_Reader_Reader, hasChildren)
+{
+       php_ion_reader *obj = php_ion_obj(reader, Z_OBJ_P(ZEND_THIS));
+
+       OBJ_CHECK(obj);
+       ZEND_PARSE_PARAMETERS_NONE();
+
+       ION_TYPE t;
+       ION_CHECK(ion_reader_get_type(obj->reader, &t));
+       switch (ION_TYPE_INT(t)) {
+               case tid_LIST_INT:
+               case tid_SEXP_INT:
+               case tid_STRUCT_INT:
+                       RETVAL_TRUE;
+                       break;
+               default:
+                       RETVAL_FALSE;
+                       break;
+       }
+}
+ZEND_METHOD(ion_Reader_Reader, getChildren)
+{
+       php_ion_reader *obj = php_ion_obj(reader, Z_OBJ_P(ZEND_THIS));
+       OBJ_CHECK(obj);
+
+       ZEND_PARSE_PARAMETERS_NONE();
+
+       ION_CHECK(ion_reader_step_in(obj->reader));
+
+       RETURN_ZVAL(ZEND_THIS, 1, 0);
+}
+ZEND_METHOD(ion_Reader_Reader, rewind)
+{
+       php_ion_reader *obj = php_ion_obj(reader, Z_OBJ_P(ZEND_THIS));
+       OBJ_CHECK(obj);
+
+       ZEND_PARSE_PARAMETERS_NONE();
+
+       ION_CHECK(ion_reader_next(obj->reader, &obj->state));
+}
+ZEND_METHOD(ion_Reader_Reader, next)
+{
+       php_ion_reader *obj = php_ion_obj(reader, Z_OBJ_P(ZEND_THIS));
+       OBJ_CHECK(obj);
+
+       ZEND_PARSE_PARAMETERS_NONE();
+
+       if (obj->state == tid_EOF) {
+               SIZE depth = 0;
+               ION_CHECK(ion_reader_get_depth(obj->reader, &depth));
+               if (depth) {
+                       ION_CHECK(ion_reader_step_out(obj->reader));
+               }
+       }
+       ION_CHECK(ion_reader_next(obj->reader, &obj->state));
+}
+ZEND_METHOD(ion_Reader_Reader, valid)
+{
+       php_ion_reader *obj = php_ion_obj(reader, Z_OBJ_P(ZEND_THIS));
+       OBJ_CHECK(obj);
+
+       ZEND_PARSE_PARAMETERS_NONE();
+       RETURN_BOOL(obj->state != tid_none && obj->state != tid_EOF);
+}
+ZEND_METHOD(ion_Reader_Reader, key)
+{
+       php_ion_reader *obj = php_ion_obj(reader, Z_OBJ_P(ZEND_THIS));
+       OBJ_CHECK(obj);
+
+       ZEND_PARSE_PARAMETERS_NONE();
+       RETURN_IONTYPE(obj->state);
+}
+ZEND_METHOD(ion_Reader_Reader, current)
+{
+       ZEND_PARSE_PARAMETERS_NONE();
+       RETURN_ZVAL(ZEND_THIS, 1, 0);
+}
+ZEND_METHOD(ion_Reader_Reader, getType)
+{
+       php_ion_reader *obj = php_ion_obj(reader, Z_OBJ_P(ZEND_THIS));
+       OBJ_CHECK(obj);
+
+       ZEND_PARSE_PARAMETERS_NONE();
+
+       ION_TYPE typ;
+       ION_CHECK(ion_reader_get_type(obj->reader, &typ));
+       RETURN_IONTYPE(typ);
+}
+ZEND_METHOD(ion_Reader_Reader, hasAnnotations)
+{
+       php_ion_reader *obj = php_ion_obj(reader, Z_OBJ_P(ZEND_THIS));
+       OBJ_CHECK(obj);
+
+       ZEND_PARSE_PARAMETERS_NONE();
+
+       BOOL has = FALSE;
+       ION_CHECK(ion_reader_has_any_annotations(obj->reader, &has));
+       RETURN_BOOL(has);
+}
+ZEND_METHOD(ion_Reader_Reader, hasAnnotation)
+{
+       php_ion_reader *obj = php_ion_obj(reader, Z_OBJ_P(ZEND_THIS));
+       OBJ_CHECK(obj);
+
+       zend_string *ann_zstr;
+       ZEND_PARSE_PARAMETERS_START(1, 1);
+               Z_PARAM_STR(ann_zstr);
+       ZEND_PARSE_PARAMETERS_END();
+
+       ION_STRING ann_istr;
+       BOOL has = FALSE;
+       ION_CHECK(ion_reader_has_annotation(obj->reader, ion_string_from_zend(&ann_istr, ann_zstr), &has));
+       RETURN_BOOL(has);
+}
+ZEND_METHOD(ion_Reader_Reader, isNull)
+{
+       php_ion_reader *obj = php_ion_obj(reader, Z_OBJ_P(ZEND_THIS));
+       OBJ_CHECK(obj);
+
+       ZEND_PARSE_PARAMETERS_NONE();
+
+       BOOL is = FALSE;
+       ION_CHECK(ion_reader_is_null(obj->reader, &is));
+       RETURN_BOOL(is);
+}
+ZEND_METHOD(ion_Reader_Reader, isInStruct)
+{
+       php_ion_reader *obj = php_ion_obj(reader, Z_OBJ_P(ZEND_THIS));
+       OBJ_CHECK(obj);
+
+       ZEND_PARSE_PARAMETERS_NONE();
+
+       BOOL is = FALSE;
+       ION_CHECK(ion_reader_is_in_struct(obj->reader, &is));
+       RETURN_BOOL(is);
+}
+ZEND_METHOD(ion_Reader_Reader, getFieldName)
+{
+       php_ion_reader *obj = php_ion_obj(reader, Z_OBJ_P(ZEND_THIS));
+       OBJ_CHECK(obj);
+
+       ZEND_PARSE_PARAMETERS_NONE();
+
+       ION_STRING name;
+       ION_CHECK(ion_reader_get_field_name(obj->reader, &name));
+       RETURN_STRINGL((char *) name.value, name.length);
+}
+ZEND_METHOD(ion_Reader_Reader, getFieldNameSymbol)
+{
+       php_ion_reader *obj = php_ion_obj(reader, Z_OBJ_P(ZEND_THIS));
+       OBJ_CHECK(obj);
+
+       ZEND_PARSE_PARAMETERS_NONE();
+
+       ION_SYMBOL *sym_ptr;
+       ION_CHECK(ion_reader_get_field_name_symbol(obj->reader, &sym_ptr));
+
+       php_ion_symbol_zval(sym_ptr, return_value);
+}
+ZEND_METHOD(ion_Reader_Reader, getAnnotations)
+{
+       php_ion_reader *obj = php_ion_obj(reader, Z_OBJ_P(ZEND_THIS));
+       OBJ_CHECK(obj);
+
+       ZEND_PARSE_PARAMETERS_NONE();
+
+       int32_t count, max;
+       if (obj->opt) {
+               max = php_ion_obj(reader_options, obj->opt)->opt.max_annotation_count;
+       } else {
+               max = 10;
+       }
+       ION_STRING *ptr = ecalloc(sizeof(*ptr), max);
+       iERR err = ion_reader_get_annotations(obj->reader, ptr, max, &count);
+       if (!err) {
+               array_init_size(return_value, count);
+               for (int32_t i = 0; i < count; ++i) {
+                       add_next_index_str(return_value, zend_string_from_ion(&ptr[i]));
+               }
+       }
+       efree(ptr);
+       ION_CHECK(err);
+}
+ZEND_METHOD(ion_Reader_Reader, getAnnotationSymbols)
+{
+       php_ion_reader *obj = php_ion_obj(reader, Z_OBJ_P(ZEND_THIS));
+       OBJ_CHECK(obj);
+
+       ZEND_PARSE_PARAMETERS_NONE();
+
+       int32_t count, max = php_ion_obj(reader_options, obj->opt)->opt.max_annotation_count;
+       ION_SYMBOL *ptr = ecalloc(sizeof(*ptr), max);
+       iERR err = ion_reader_get_annotation_symbols(obj->reader, ptr, max, &count);
+       if (!err) {
+               array_init_size(return_value, count);
+               for (int32_t i = 0; i < count; ++i) {
+                       zval zsym;
+                       php_ion_symbol_zval(&ptr[i], &zsym);
+                       add_next_index_zval(return_value, &zsym);
+               }
+       }
+       efree(ptr);
+       ION_CHECK(err);
+}
+ZEND_METHOD(ion_Reader_Reader, countAnnotations)
+{
+       php_ion_reader *obj = php_ion_obj(reader, Z_OBJ_P(ZEND_THIS));
+       OBJ_CHECK(obj);
+
+       ZEND_PARSE_PARAMETERS_NONE();
+
+       SIZE sz = 0;
+       ION_CHECK(ion_reader_get_annotation_count(obj->reader, &sz));
+       RETURN_LONG(sz);
+}
+ZEND_METHOD(ion_Reader_Reader, getAnnotation)
+{
+       php_ion_reader *obj = php_ion_obj(reader, Z_OBJ_P(ZEND_THIS));
+       OBJ_CHECK(obj);
+
+       zend_long idx;
+       ZEND_PARSE_PARAMETERS_START(1, 1)
+               Z_PARAM_LONG(idx);
+       ZEND_PARSE_PARAMETERS_END();
+
+       ION_STRING ann;
+       ION_CHECK(ion_reader_get_an_annotation(obj->reader, idx, &ann));
+       RETURN_STRINGL((char *) ann.value, ann.length);
+}
+ZEND_METHOD(ion_Reader_Reader, getAnnotationSymbol)
+{
+       php_ion_reader *obj = php_ion_obj(reader, Z_OBJ_P(ZEND_THIS));
+       OBJ_CHECK(obj);
+
+       zend_long idx;
+       ZEND_PARSE_PARAMETERS_START(1, 1)
+               Z_PARAM_LONG(idx);
+       ZEND_PARSE_PARAMETERS_END();
+
+       ION_SYMBOL sym;
+       ION_CHECK(ion_reader_get_an_annotation_symbol(obj->reader, idx, &sym));
+       php_ion_symbol_zval(&sym, return_value);
+}
+ZEND_METHOD(ion_Reader_Reader, readNull)
+{
+       php_ion_reader *obj = php_ion_obj(reader, Z_OBJ_P(ZEND_THIS));
+       OBJ_CHECK(obj);
+
+       ZEND_PARSE_PARAMETERS_NONE();
+
+       ION_TYPE typ;
+       ION_CHECK(ion_reader_read_null(obj->reader, &typ));
+       RETURN_OBJ_COPY(php_ion_type_fetch(typ));
+}
+ZEND_METHOD(ion_Reader_Reader, readBool)
+{
+       php_ion_reader *obj = php_ion_obj(reader, Z_OBJ_P(ZEND_THIS));
+       OBJ_CHECK(obj);
+
+       ZEND_PARSE_PARAMETERS_NONE();
+
+       BOOL b;
+       ION_CHECK(ion_reader_read_bool(obj->reader, &b));
+       RETURN_BOOL(b);
+}
+ZEND_METHOD(ion_Reader_Reader, readInt)
+{
+       php_ion_reader *obj = php_ion_obj(reader, Z_OBJ_P(ZEND_THIS));
+       OBJ_CHECK(obj);
+
+       ZEND_PARSE_PARAMETERS_NONE();
+
+       php_ion_unserialize_int(obj, return_value);
+}
+ZEND_METHOD(ion_Reader_Reader, readFloat)
+{
+       php_ion_reader *obj = php_ion_obj(reader, Z_OBJ_P(ZEND_THIS));
+       OBJ_CHECK(obj);
+
+       ZEND_PARSE_PARAMETERS_NONE();
+
+       ION_CHECK(ion_reader_read_double(obj->reader, &Z_DVAL_P(return_value)));
+}
+ZEND_METHOD(ion_Reader_Reader, readDecimal)
+{
+       php_ion_reader *obj = php_ion_obj(reader, Z_OBJ_P(ZEND_THIS));
+       OBJ_CHECK(obj);
+
+       ZEND_PARSE_PARAMETERS_NONE();
+
+       object_init_ex(return_value, ce_Decimal);
+       php_ion_decimal *dec = php_ion_obj(decimal, Z_OBJ_P(return_value));
+       ION_CHECK(ion_reader_read_ion_decimal(obj->reader, &dec->dec));
+       php_ion_decimal_ctor(dec);
+}
+ZEND_METHOD(ion_Reader_Reader, readTimestamp)
+{
+       php_ion_reader *obj = php_ion_obj(reader, Z_OBJ_P(ZEND_THIS));
+       OBJ_CHECK(obj);
+
+       ZEND_PARSE_PARAMETERS_NONE();
+
+       php_ion_unserialize_timestamp(obj, return_value);
+}
+ZEND_METHOD(ion_Reader_Reader, readSymbol)
+{
+       php_ion_reader *obj = php_ion_obj(reader, Z_OBJ_P(ZEND_THIS));
+       OBJ_CHECK(obj);
+
+       ZEND_PARSE_PARAMETERS_NONE();
+
+       ION_SYMBOL sym;
+       ION_CHECK(ion_reader_read_ion_symbol(obj->reader, &sym));
+       php_ion_symbol_zval(&sym, return_value);
+}
+ZEND_METHOD(ion_Reader_Reader, readString)
+{
+       php_ion_reader *obj = php_ion_obj(reader, Z_OBJ_P(ZEND_THIS));
+       OBJ_CHECK(obj);
+
+       ZEND_PARSE_PARAMETERS_NONE();
+
+       ION_STRING str;
+       ION_CHECK(ion_reader_read_string(obj->reader, &str));
+       RETURN_STRINGL((char *) str.value, str.length);
+}
+
+typedef iERR (*read_part_fn)(ION_READER *, BYTE *, SIZE, SIZE *);
+static void read_part(INTERNAL_FUNCTION_PARAMETERS, read_part_fn fn)
+{
+       php_ion_reader *obj = php_ion_obj(reader, Z_OBJ_P(ZEND_THIS));
+       OBJ_CHECK(obj);
+
+       zval *ref;
+       zend_string *zstr;
+       zend_long len = 0x1000;
+       ZEND_PARSE_PARAMETERS_START(1, 1)
+               Z_PARAM_ZVAL(ref)
+               Z_PARAM_OPTIONAL
+               Z_PARAM_LONG(len)
+       ZEND_PARSE_PARAMETERS_END();
+
+       ZVAL_DEREF(ref);
+
+       if (Z_TYPE_P(ref) == IS_STRING && Z_STRLEN_P(ref) == len) {
+               /* reuse */
+               zstr = Z_STR_P(ref);
+       } else {
+               zval_dtor(ref);
+               zstr = zend_string_alloc(len, 0);
+       }
+
+       SIZE read = 0;
+       ION_CHECK(fn(obj->reader, (BYTE *) zstr->val, zstr->len, &read), goto fail);
+       if (read > 0) {
+               if (read < zstr->len) {
+                       zstr = zend_string_truncate(zstr, read, 0);
+               }
+               ZVAL_STR(ref, zstr);
+               RETURN_TRUE;
+       }
+fail:
+       if (zstr != Z_STR_P(ref)) {
+               zend_string_release(zstr);
+       }
+       ZVAL_EMPTY_STRING(ref);
+       RETURN_FALSE;
+}
+ZEND_METHOD(ion_Reader_Reader, readStringPart)
+{
+       read_part(INTERNAL_FUNCTION_PARAM_PASSTHRU, ion_reader_read_partial_string);
+}
+ZEND_METHOD(ion_Reader_Reader, readLob)
+{
+       php_ion_reader *obj = php_ion_obj(reader, Z_OBJ_P(ZEND_THIS));
+       OBJ_CHECK(obj);
+
+       ZEND_PARSE_PARAMETERS_NONE();
+
+       php_ion_unserialize_lob(obj, return_value);
+}
+ZEND_METHOD(ion_Reader_Reader, readLobPart)
+{
+       read_part(INTERNAL_FUNCTION_PARAM_PASSTHRU, ion_reader_read_lob_partial_bytes);
+}
+ZEND_METHOD(ion_Reader_Reader, getPosition)
+{
+       php_ion_reader *obj = php_ion_obj(reader, Z_OBJ_P(ZEND_THIS));
+       OBJ_CHECK(obj);
+
+       ZEND_PARSE_PARAMETERS_NONE();
+
+       int64_t bytes = 0;
+       int32_t dummy;
+       ION_CHECK(ion_reader_get_position(obj->reader, &bytes, &dummy, &dummy));
+       RETURN_LONG(bytes);
+}
+ZEND_METHOD(ion_Reader_Reader, getDepth)
+{
+       php_ion_reader *obj = php_ion_obj(reader, Z_OBJ_P(ZEND_THIS));
+       OBJ_CHECK(obj);
+
+       ZEND_PARSE_PARAMETERS_NONE();
+
+       SIZE depth = 0;
+       ION_CHECK(ion_reader_get_depth(obj->reader, &depth));
+       RETURN_LONG(depth);
+}
+ZEND_METHOD(ion_Reader_Reader, seek)
+{
+       php_ion_reader *obj = php_ion_obj(reader, Z_OBJ_P(ZEND_THIS));
+       OBJ_CHECK(obj);
+
+       zend_long off, len = -1;
+       ZEND_PARSE_PARAMETERS_START(1, 2)
+               Z_PARAM_LONG(off)
+               Z_PARAM_OPTIONAL
+               Z_PARAM_LONG(len)
+       ZEND_PARSE_PARAMETERS_END();
+
+       ION_CHECK(ion_reader_seek(obj->reader, off, len));
+}
+ZEND_METHOD(ion_Reader_Reader, getValueOffset)
+{
+       php_ion_reader *obj = php_ion_obj(reader, Z_OBJ_P(ZEND_THIS));
+       OBJ_CHECK(obj);
+
+       ZEND_PARSE_PARAMETERS_NONE();
+
+       POSITION off = 0;
+       ION_CHECK(ion_reader_get_value_offset(obj->reader, &off));
+       RETURN_LONG(off);
+}
+ZEND_METHOD(ion_Reader_Reader, getValueLength)
+{
+       php_ion_reader *obj = php_ion_obj(reader, Z_OBJ_P(ZEND_THIS));
+       OBJ_CHECK(obj);
+
+       ZEND_PARSE_PARAMETERS_NONE();
+
+       SIZE len = 0;
+       ION_CHECK(ion_reader_get_value_length(obj->reader, &len));
+       RETURN_LONG(len);
+}
+ZEND_METHOD(ion_Reader_Buffer_Reader, __construct)
+{
+       php_ion_reader *obj = php_ion_obj(reader, Z_OBJ_P(ZEND_THIS));
+       PTR_CHECK(obj);
+
+       zend_string *zstr;
+       ZEND_PARSE_PARAMETERS_START(1, 2)
+               Z_PARAM_STR(zstr)
+               Z_PARAM_OPTIONAL
+               Z_PARAM_OBJ_OF_CLASS_OR_NULL(obj->opt, ce_Reader_Options)
+       ZEND_PARSE_PARAMETERS_END();
+
+       obj->type = BUFFER_READER;
+       obj->buffer = zend_string_copy(zstr);
+
+       php_ion_reader_ctor(obj);
+}
+ZEND_METHOD(ion_Reader_Buffer_Reader, getBuffer)
+{
+       php_ion_reader *obj = php_ion_obj(reader, Z_OBJ_P(ZEND_THIS));
+       OBJ_CHECK(obj);
+
+       ZEND_PARSE_PARAMETERS_NONE();
+       RETURN_STR_COPY(obj->buffer);
+}
+
+ZEND_METHOD(ion_Reader_Stream_Reader, __construct)
+{
+       php_ion_reader *obj = php_ion_obj(reader, Z_OBJ_P(ZEND_THIS));
+       PTR_CHECK(obj);
+
+       zval *zstream;
+       ZEND_PARSE_PARAMETERS_START(1, 2)
+               Z_PARAM_RESOURCE(zstream)
+               Z_PARAM_OPTIONAL
+               Z_PARAM_OBJ_OF_CLASS_OR_NULL(obj->opt, ce_Reader_Options)
+       ZEND_PARSE_PARAMETERS_END();
+
+       obj->type = STREAM_READER;
+       php_stream_from_zval_no_verify(obj->stream.ptr, zstream);
+
+       php_ion_reader_ctor(obj);
+}
+ZEND_METHOD(ion_Reader_Stream_Reader, getStream)
+{
+       php_ion_reader *obj = php_ion_obj(reader, Z_OBJ_P(ZEND_THIS));
+       OBJ_CHECK(obj);
+
+       ZEND_PARSE_PARAMETERS_NONE();
+       PTR_CHECK(obj->stream.ptr);
+
+       GC_ADDREF(obj->stream.ptr->res);
+       RETURN_RES(obj->stream.ptr->res);
+}
+ZEND_METHOD(ion_Reader_Stream_Reader, resetStream)
+{
+       php_ion_reader *obj = php_ion_obj(reader, Z_OBJ_P(ZEND_THIS));
+       OBJ_CHECK(obj);
+
+       zval *zstream;
+       ZEND_PARSE_PARAMETERS_START(1, 1);
+               Z_PARAM_RESOURCE(zstream);
+       ZEND_PARSE_PARAMETERS_END();
+
+       ION_CHECK(ion_reader_reset_stream(&obj->reader, obj, php_ion_reader_stream_handler));
+
+       if (obj->stream.ptr) {
+               zend_list_delete(obj->stream.ptr->res);
+       }
+       php_stream_from_zval_no_verify(obj->stream.ptr, zstream);
+       PTR_CHECK(obj->stream.ptr);
+       Z_ADDREF_P(zstream);
+}
+ZEND_METHOD(ion_Reader_Stream_Reader, resetStreamWithLength)
+{
+       php_ion_reader *obj = php_ion_obj(reader, Z_OBJ_P(ZEND_THIS));
+       OBJ_CHECK(obj);
+
+       zval *zstream;
+       zend_long length;
+       ZEND_PARSE_PARAMETERS_START(1, 2);
+               Z_PARAM_RESOURCE(zstream);
+               Z_PARAM_LONG(length)
+       ZEND_PARSE_PARAMETERS_END();
+
+       ION_CHECK(ion_reader_reset_stream_with_length(&obj->reader, obj, php_ion_reader_stream_handler, length));
+
+       if (obj->stream.ptr) {
+               zend_list_delete(obj->stream.ptr->res);
+       }
+       php_stream_from_zval_no_verify(obj->stream.ptr, zstream);
+       PTR_CHECK(obj->stream.ptr);
+       Z_ADDREF_P(zstream);
+}
+ZEND_METHOD(ion_Writer_Options, __construct)
+{
+       php_ion_writer_options *obj = php_ion_obj(writer_options, Z_OBJ_P(ZEND_THIS));
+       PTR_CHECK(obj);
+
+       zend_bool binary = false, compact_floats = false, escape = false, pretty = false,
+                       tabs = true, small_cntr_inl = true, suppress_sys = false, flush = false;
+       zend_long indent = 2, max_depth = 10, max_ann = 10, temp = 0x400, alloc = 0x1000;
+       ZEND_PARSE_PARAMETERS_START(0, 16)
+               Z_PARAM_OPTIONAL
+               //public readonly ?\ion\Catalog $catalog = null,
+               Z_PARAM_OBJ_OF_CLASS_OR_NULL(obj->cat, ce_Catalog)
+               //public readonly ?\ion\Collection $encodingSymbolTable = null,
+               Z_PARAM_OBJ_OF_CLASS_OR_NULL(obj->col, ce_Collection)
+               //public readonly ?\ion\Decimal\Context $decimalContext = null,
+               Z_PARAM_OBJ_OF_CLASS_OR_NULL(obj->dec_ctx, ce_Decimal_Context)
+               //public readonly bool $outputBinary = false,
+               Z_PARAM_BOOL(binary)
+               //public readonly bool $compactFloats = false,
+               Z_PARAM_BOOL(compact_floats)
+               //public readonly bool $escapeNonAscii = false,
+               Z_PARAM_BOOL(escape)
+               //public readonly bool $prettyPrint = false,
+               Z_PARAM_BOOL(pretty)
+               //public readonly bool $indentTabs = true,
+               Z_PARAM_BOOL(tabs)
+               //public readonly int $indentSize = 2,
+               Z_PARAM_LONG(indent)
+               //public readonly bool $smallContainersInline = true,
+               Z_PARAM_BOOL(small_cntr_inl)
+               //public readonly bool $suppressSystemValues = false,
+               Z_PARAM_BOOL(suppress_sys)
+               //public readonly bool $flushEveryValue = false,
+               Z_PARAM_BOOL(flush)
+               //public readonly int $maxContainerDepth = 10,
+               Z_PARAM_LONG(max_depth)
+               //public readonly int $maxAnnotations = 10,
+               Z_PARAM_LONG(max_ann)
+               //public readonly int $tempBufferSize = 0x400,
+               Z_PARAM_LONG(temp)
+               //public readonly int $allocationPageSize = 0x1000,
+               Z_PARAM_LONG(alloc)
+       ZEND_PARSE_PARAMETERS_END();
+
+       if (obj->cat) {
+               update_property_obj(&obj->std, ZEND_STRL("catalog"), obj->cat);
+               obj->opt.pcatalog = php_ion_obj(catalog, obj->cat)->cat;
+       }
+       if (obj->col) {
+               // TODO
+       }
+       if (obj->dec_ctx) {
+               update_property_obj(&obj->std, ZEND_STRL("decimalContext"), obj->dec_ctx);
+               obj->opt.decimal_context = &php_ion_obj(decimal_ctx, obj->dec_ctx)->ctx;
+       }
+       zend_update_property_bool(obj->std.ce, &obj->std, ZEND_STRL("outputBinary"),
+                       obj->opt.output_as_binary = binary);
+       zend_update_property_bool(obj->std.ce, &obj->std, ZEND_STRL("comactFloats"),
+                       obj->opt.compact_floats = compact_floats);
+       zend_update_property_bool(obj->std.ce, &obj->std, ZEND_STRL("excapeNonAscii"),
+                       obj->opt.escape_all_non_ascii = escape);
+       zend_update_property_bool(obj->std.ce, &obj->std, ZEND_STRL("prettyPrint"),
+                       obj->opt.pretty_print = pretty);
+       zend_update_property_bool(obj->std.ce, &obj->std, ZEND_STRL("indentTabs"),
+                       obj->opt.indent_with_tabs = tabs);
+       zend_update_property_long(obj->std.ce, &obj->std, ZEND_STRL("indentSize"),
+                       obj->opt.indent_size = indent);
+       zend_update_property_bool(obj->std.ce, &obj->std, ZEND_STRL("smallContainersInline"),
+                       obj->opt.small_containers_in_line = small_cntr_inl);
+       zend_update_property_bool(obj->std.ce, &obj->std, ZEND_STRL("suppressSystemValues"),
+                       obj->opt.supress_system_values = suppress_sys);
+       zend_update_property_bool(obj->std.ce, &obj->std, ZEND_STRL("flushEveryValue"),
+                       obj->opt.flush_every_value = flush);
+       zend_update_property_long(obj->std.ce, &obj->std, ZEND_STRL("maxContainerDepth"),
+                       obj->opt.max_container_depth = max_depth);
+       zend_update_property_long(obj->std.ce, &obj->std, ZEND_STRL("maxAnnotations"),
+                       obj->opt.max_annotation_count = max_ann);
+       zend_update_property_long(obj->std.ce, &obj->std, ZEND_STRL("tempBufferSize"),
+                       obj->opt.temp_buffer_size = temp);
+       zend_update_property_long(obj->std.ce, &obj->std, ZEND_STRL("allocationPageSize"),
+                       obj->opt.allocation_page_size = alloc);
+}
+ZEND_METHOD(ion_Writer_Writer, writeNull)
+{
+       php_ion_writer *obj = php_ion_obj(writer, Z_OBJ_P(ZEND_THIS));
+       OBJ_CHECK(obj);
+
+       ZEND_PARSE_PARAMETERS_NONE();
+
+       ION_CHECK(ion_writer_write_null(obj->writer));
+}
+ZEND_METHOD(ion_Writer_Writer, writeTypedNull)
+{
+       php_ion_writer *obj = php_ion_obj(writer, Z_OBJ_P(ZEND_THIS));
+       OBJ_CHECK(obj);
+
+       zend_object *typ_obj;
+       ZEND_PARSE_PARAMETERS_START(1, 1)
+               Z_PARAM_OBJ_OF_CLASS(typ_obj, ce_Type)
+       ZEND_PARSE_PARAMETERS_END();
+
+       php_ion_type *typ = php_ion_obj(type, typ_obj);
+       OBJ_CHECK(typ);
+       ION_CHECK(ion_writer_write_typed_null(obj->writer, php_ion_obj(type, typ)->typ));
+}
+ZEND_METHOD(ion_Writer_Writer, writeBool)
+{
+       php_ion_writer *obj = php_ion_obj(writer, Z_OBJ_P(ZEND_THIS));
+       OBJ_CHECK(obj);
+
+       zend_bool b;
+       ZEND_PARSE_PARAMETERS_START(1, 1)
+               Z_PARAM_BOOL(b)
+       ZEND_PARSE_PARAMETERS_END();
+
+       ION_CHECK(ion_writer_write_bool(obj->writer, b));
+}
+ZEND_METHOD(ion_Writer_Writer, writeInt)
+{
+       php_ion_writer *obj = php_ion_obj(writer, Z_OBJ_P(ZEND_THIS));
+       OBJ_CHECK(obj);
+
+       zend_long l;
+       zend_string *s;
+       ZEND_PARSE_PARAMETERS_START(1, 1)
+               Z_PARAM_STR_OR_LONG(s, l)
+       ZEND_PARSE_PARAMETERS_END();
+
+       if (s) {
+               ION_INT *i;
+               ION_CHECK(ion_int_alloc(obj->writer, &i));
+               ION_CHECK(ion_int_from_chars(i, s->val, s->len));
+               ION_CHECK(ion_writer_write_ion_int(obj->writer, i));
+               ion_int_free(i);
+       } else {
+               ION_CHECK(ion_writer_write_int64(obj->writer, l));
+       }
+}
+ZEND_METHOD(ion_Writer_Writer, writeFloat)
+{
+       php_ion_writer *obj = php_ion_obj(writer, Z_OBJ_P(ZEND_THIS));
+       OBJ_CHECK(obj);
+
+       double d;
+       ZEND_PARSE_PARAMETERS_START(1, 1)
+               Z_PARAM_DOUBLE(d)
+       ZEND_PARSE_PARAMETERS_END();
+
+       ION_CHECK(ion_writer_write_double(obj->writer, d));
+}
+ZEND_METHOD(ion_Writer_Writer, writeDecimal)
+{
+       php_ion_writer *obj = php_ion_obj(writer, Z_OBJ_P(ZEND_THIS));
+       OBJ_CHECK(obj);
+
+       zend_object *dec_obj;
+       zend_string *dec_str;
+       ZEND_PARSE_PARAMETERS_START(1, 1)
+               Z_PARAM_OBJ_OF_CLASS_OR_STR(dec_obj, ce_Decimal, dec_str)
+       ZEND_PARSE_PARAMETERS_END();
+
+       if (dec_str) {
+               ION_STRING s;
+               ION_CHECK(ion_writer_write_string(obj->writer, ion_string_from_zend(&s, dec_str)));
+       } else {
+               php_ion_decimal *dec = php_ion_obj(decimal, dec_obj);
+               ION_CHECK(ion_writer_write_ion_decimal(obj->writer, &dec->dec));
+       }
+}
+ZEND_METHOD(ion_Writer_Writer, writeTimestamp)
+{
+       php_ion_writer *obj = php_ion_obj(writer, Z_OBJ_P(ZEND_THIS));
+       OBJ_CHECK(obj);
+
+       zend_object *ts_obj;
+       zend_string *ts_str;
+       ZEND_PARSE_PARAMETERS_START(1, 1)
+               Z_PARAM_OBJ_OF_CLASS_OR_STR(ts_obj, ce_Timestamp, ts_str)
+       ZEND_PARSE_PARAMETERS_END();
+
+       decContext *ctx = NULL;
+       if (obj->opt) {
+               ctx = php_ion_obj(reader_options, obj->opt)->opt.decimal_context;
+       }
+
+       ION_TIMESTAMP tmp = {0};
+       if (ts_str) {
+               SIZE used;
+               ION_CHECK(ion_timestamp_parse(&tmp, ts_str->val, ts_str->len, &used, ctx));
+       } else {
+               php_ion_timestamp *ts = php_ion_obj(timestamp, ts_obj);
+               OBJ_CHECK(ts);
+               ion_timestamp_from_php(&tmp, ts, ctx);
+       }
+       ION_CHECK(ion_writer_write_timestamp(obj->writer, &tmp));
+}
+ZEND_METHOD(ion_Writer_Writer, writeSymbol)
+{
+       php_ion_writer *obj = php_ion_obj(writer, Z_OBJ_P(ZEND_THIS));
+       OBJ_CHECK(obj);
+
+       zend_object *sym_obj;
+       zend_string *sym_str;
+       ZEND_PARSE_PARAMETERS_START(1, 1)
+               Z_PARAM_OBJ_OF_CLASS_OR_STR(sym_obj, ce_Symbol, sym_str);
+       ZEND_PARSE_PARAMETERS_END();
+
+       if (sym_str) {
+               ION_STRING is;
+               ION_CHECK(ion_writer_write_symbol(obj->writer, ion_string_from_zend(&is, sym_str)));
+       } else {
+               php_ion_symbol *sym = php_ion_obj(symbol, sym_obj);
+               PTR_CHECK(sym);
+               ION_CHECK(ion_writer_write_ion_symbol(obj->writer, &sym->sym));
+       }
+}
+ZEND_METHOD(ion_Writer_Writer, writeString)
+{
+       php_ion_writer *obj = php_ion_obj(writer, Z_OBJ_P(ZEND_THIS));
+       OBJ_CHECK(obj);
+
+       zend_string *str;
+       ZEND_PARSE_PARAMETERS_START(1, 1)
+               Z_PARAM_STR(str)
+       ZEND_PARSE_PARAMETERS_END();
+
+       ION_STRING is;
+       ION_CHECK(ion_writer_write_string(obj->writer, ion_string_from_zend(&is, str)));
+}
+ZEND_METHOD(ion_Writer_Writer, writeCLob)
+{
+       php_ion_writer *obj = php_ion_obj(writer, Z_OBJ_P(ZEND_THIS));
+       OBJ_CHECK(obj);
+
+       zend_string *str;
+       ZEND_PARSE_PARAMETERS_START(1, 1)
+               Z_PARAM_STR(str)
+       ZEND_PARSE_PARAMETERS_END();
+
+       ION_CHECK(ion_writer_write_clob(obj->writer, (BYTE *) str->val, str->len));
+}
+ZEND_METHOD(ion_Writer_Writer, writeBLob)
+{
+       php_ion_writer *obj = php_ion_obj(writer, Z_OBJ_P(ZEND_THIS));
+       OBJ_CHECK(obj);
+
+       zend_string *str;
+       ZEND_PARSE_PARAMETERS_START(1, 1)
+               Z_PARAM_STR(str)
+       ZEND_PARSE_PARAMETERS_END();
+
+       ION_CHECK(ion_writer_write_blob(obj->writer, (BYTE *) str->val, str->len));
+}
+ZEND_METHOD(ion_Writer_Writer, startLob)
+{
+       php_ion_writer *obj = php_ion_obj(writer, Z_OBJ_P(ZEND_THIS));
+       OBJ_CHECK(obj);
+
+       zend_object *typ_obj;
+       ZEND_PARSE_PARAMETERS_START(1, 1)
+               Z_PARAM_OBJ_OF_CLASS(typ_obj, ce_Type)
+       ZEND_PARSE_PARAMETERS_END();
+
+       php_ion_type *typ = php_ion_obj(type, typ_obj);
+       OBJ_CHECK(typ);
+       ION_CHECK(ion_writer_start_lob(obj->writer, php_ion_obj(type, typ)->typ));
+}
+ZEND_METHOD(ion_Writer_Writer, appendLob)
+{
+       php_ion_writer *obj = php_ion_obj(writer, Z_OBJ_P(ZEND_THIS));
+       OBJ_CHECK(obj);
+
+       zend_string *str;
+       ZEND_PARSE_PARAMETERS_START(1, 1)
+               Z_PARAM_STR(str)
+       ZEND_PARSE_PARAMETERS_END();
+
+       ION_CHECK(ion_writer_append_lob(obj->writer, (BYTE *) str->val, str->len));
+}
+ZEND_METHOD(ion_Writer_Writer, finishLob)
+{
+       php_ion_writer *obj = php_ion_obj(writer, Z_OBJ_P(ZEND_THIS));
+       OBJ_CHECK(obj);
+
+       ZEND_PARSE_PARAMETERS_NONE();
+
+       ION_CHECK(ion_writer_finish_lob(obj->writer));
+}
+ZEND_METHOD(ion_Writer_Writer, startContainer)
+{
+       php_ion_writer *obj = php_ion_obj(writer, Z_OBJ_P(ZEND_THIS));
+       OBJ_CHECK(obj);
+
+       zend_object *typ_obj;
+       ZEND_PARSE_PARAMETERS_START(1, 1)
+               Z_PARAM_OBJ_OF_CLASS(typ_obj, ce_Type)
+       ZEND_PARSE_PARAMETERS_END();
+
+       php_ion_type *typ = php_ion_obj(type, typ_obj);
+       OBJ_CHECK(typ);
+       ION_CHECK(ion_writer_start_container(obj->writer, php_ion_obj(type, typ)->typ));
+}
+ZEND_METHOD(ion_Writer_Writer, finishContainer)
+{
+       php_ion_writer *obj = php_ion_obj(writer, Z_OBJ_P(ZEND_THIS));
+       OBJ_CHECK(obj);
+
+       ZEND_PARSE_PARAMETERS_NONE();
+
+       ION_CHECK(ion_writer_finish_container(obj->writer));
+}
+ZEND_METHOD(ion_Writer_Writer, writeFieldName)
+{
+       php_ion_writer *obj = php_ion_obj(writer, Z_OBJ_P(ZEND_THIS));
+       OBJ_CHECK(obj);
+
+       zend_object *sym_obj;
+       zend_string *sym_str;
+       ZEND_PARSE_PARAMETERS_START(1, 1)
+               Z_PARAM_OBJ_OF_CLASS_OR_STR(sym_obj, ce_Symbol, sym_str);
+       ZEND_PARSE_PARAMETERS_END();
+
+       if (sym_str) {
+               ION_STRING is;
+               ION_CHECK(ion_writer_write_field_name(obj->writer, ion_string_from_zend(&is, sym_str)));
+       } else {
+               php_ion_symbol *sym = php_ion_obj(symbol, sym_obj);
+               PTR_CHECK(sym);
+               ION_CHECK(ion_writer_write_field_name_symbol(obj->writer, &sym->sym));
+       }
+}
+ZEND_METHOD(ion_Writer_Writer, writeAnnotation)
+{
+       php_ion_writer *obj = php_ion_obj(writer, Z_OBJ_P(ZEND_THIS));
+       OBJ_CHECK(obj);
+
+       zval *args;
+       unsigned argc;
+       ZEND_PARSE_PARAMETERS_START(1, -1)
+               Z_PARAM_VARIADIC('+', args, argc);
+       ZEND_PARSE_PARAMETERS_END();
+
+       for (unsigned i = 0; i < argc; ++i) {
+               switch (Z_TYPE(args[i])) {
+               case IS_STRING:
+                       ION_STRING is;
+                       ION_CHECK(ion_writer_add_annotation(obj->writer, ion_string_from_zend(&is, Z_STR(args[i]))));
+                       break;
+
+               case IS_OBJECT:
+                       ION_CHECK(ion_writer_add_annotation_symbol(obj->writer, &php_ion_obj(symbol, Z_OBJ(args[i]))->sym));
+                       break;
+               }
+       }
+}
+ZEND_METHOD(ion_Writer_Writer, getDepth)
+{
+       php_ion_writer *obj = php_ion_obj(writer, Z_OBJ_P(ZEND_THIS));
+       OBJ_CHECK(obj);
+
+       ZEND_PARSE_PARAMETERS_NONE();
+
+       SIZE depth;
+       ION_CHECK(ion_writer_get_depth(obj->writer, &depth));
+       RETURN_LONG(depth);
+}
+ZEND_METHOD(ion_Writer_Writer, flush)
+{
+       php_ion_writer *obj = php_ion_obj(writer, Z_OBJ_P(ZEND_THIS));
+       OBJ_CHECK(obj);
+
+       ZEND_PARSE_PARAMETERS_NONE();
+
+       SIZE flushed;
+       ION_CHECK(ion_writer_flush(obj->writer, &flushed));
+       if (obj->type == BUFFER_WRITER) {
+               smart_str_0(&obj->buffer.str);
+       }
+       RETURN_LONG(flushed);
+}
+ZEND_METHOD(ion_Writer_Writer, finish)
+{
+       php_ion_writer *obj = php_ion_obj(writer, Z_OBJ_P(ZEND_THIS));
+       OBJ_CHECK(obj);
+
+       ZEND_PARSE_PARAMETERS_NONE();
+
+       SIZE flushed;
+       ION_CHECK(ion_writer_finish(obj->writer, &flushed));
+       if (obj->type == BUFFER_WRITER) {
+               smart_str_0(&obj->buffer.str);
+       }
+       RETURN_LONG(flushed);
+}
+ZEND_METHOD(ion_Writer_Writer, writeOne)
+{
+}
+ZEND_METHOD(ion_Writer_Writer, writeAll)
+{
+}
+ZEND_METHOD(ion_Writer_Buffer_Writer, __construct)
+{
+       php_ion_writer *obj = php_ion_obj(writer, Z_OBJ_P(ZEND_THIS));
+       PTR_CHECK(obj);
+
+       zval *ref;
+       ZEND_PARSE_PARAMETERS_START(1, 2)
+               Z_PARAM_ZVAL(ref)
+               Z_PARAM_OPTIONAL
+               Z_PARAM_OBJ_OF_CLASS_OR_NULL(obj->opt, ce_Writer_Options)
+       ZEND_PARSE_PARAMETERS_END();
+
+       obj->type = BUFFER_WRITER;
+       ZVAL_COPY(&obj->buffer.val, ref);
+       zval_dtor(Z_REFVAL_P(ref));
+
+       php_ion_writer_ctor(obj);
+}
+ZEND_METHOD(ion_Writer_Buffer_Writer, getBuffer)
+{
+       php_ion_writer *obj = php_ion_obj(writer, Z_OBJ_P(ZEND_THIS));
+       OBJ_CHECK(obj);
+
+       ZEND_PARSE_PARAMETERS_NONE();
+
+       RETVAL_STR(zend_string_dup(obj->buffer.str.s, 0));
+}
+ZEND_METHOD(ion_Writer_Stream_Writer, __construct)
+{
+       php_ion_writer *obj = php_ion_obj(writer, Z_OBJ_P(ZEND_THIS));
+       PTR_CHECK(obj);
+
+       zval *zstream;
+       ZEND_PARSE_PARAMETERS_START(1, 2)
+               Z_PARAM_RESOURCE(zstream)
+               Z_PARAM_OPTIONAL
+               Z_PARAM_OBJ_OF_CLASS_OR_NULL(obj->opt, ce_Writer_Options)
+       ZEND_PARSE_PARAMETERS_END();
+
+       obj->type = STREAM_WRITER;
+       php_stream_from_zval_no_verify(obj->stream.ptr, zstream);
+
+       php_ion_writer_ctor(obj);
+}
+ZEND_METHOD(ion_Writer_Stream_Writer, getStream)
+{
+       php_ion_writer *obj = php_ion_obj(writer, Z_OBJ_P(ZEND_THIS));
+       OBJ_CHECK(obj);
+
+       ZEND_PARSE_PARAMETERS_NONE();
+       PTR_CHECK(obj->stream.ptr);
+
+       GC_ADDREF(obj->stream.ptr->res);
+       RETURN_RES(obj->stream.ptr->res);
+}
+
+ZEND_METHOD(ion_PHP_Serializer, __construct)
+{
+       zend_object *obj = Z_OBJ_P(ZEND_THIS);
+
+       zend_object *writer_obj;
+       zend_bool call_magic = true;
+       zend_string *call_custom = NULL;
+       ZEND_PARSE_PARAMETERS_START(1, 3)
+               Z_PARAM_OBJ_OF_CLASS(writer_obj, ce_Writer)
+               Z_PARAM_OPTIONAL
+               Z_PARAM_BOOL(call_magic)
+               Z_PARAM_STR_OR_NULL(call_custom)
+       ZEND_PARSE_PARAMETERS_END();
+
+       update_property_obj(obj, ZEND_STRL("writer"), writer_obj);
+       zend_update_property_bool(obj->ce, obj, ZEND_STRL("callMagicSerialize"),
+                       php_ion_obj(writer, writer_obj)->php.call_magic_serialize = call_magic);
+       if (call_custom) {
+               zend_update_property_str(obj->ce, obj, ZEND_STRL("callCustomSerialize"), call_custom);
+               php_ion_obj(writer, writer_obj)->php.custom_serialize = zend_string_tolower(call_custom);
+       } else {
+               zend_update_property_null(obj->ce, obj, ZEND_STRL("callCustomSerialize"));
+       }
+}
+ZEND_METHOD(ion_PHP_Serializer, __invoke)
+{
+       zend_object *obj = Z_OBJ_P(ZEND_THIS);
+
+       zval *data;
+       ZEND_PARSE_PARAMETERS_START(1, 1)
+               Z_PARAM_ZVAL(data)
+       ZEND_PARSE_PARAMETERS_END();
+
+       zval tmp, *zwriter;
+       if ((zwriter = zend_read_property(obj->ce, obj, ZEND_STRL("writer"), 0, &tmp))) {
+               if (Z_OBJCE_P(zwriter) == ce_Writer_Buffer_Writer || Z_OBJCE_P(zwriter) == ce_Writer_Stream_Writer) {
+                       php_ion_writer *writer = php_ion_obj(writer, Z_OBJ_P(zwriter));
+                       php_ion_serialize(writer, data, &writer->buffer.val);
+                       RETURN_STR_COPY(writer->buffer.str.s);
+               } else {
+                       zend_call_method_with_1_params(obj, obj->ce, NULL /* TODO */, "serialize", return_value, data);
+               }
+       }
+}
+ZEND_METHOD(ion_PHP_Serializer, serialize)
+{
+       //zend_object *obj = Z_OBJ_P(ZEND_THIS);
+
+       zval *data;
+       ZEND_PARSE_PARAMETERS_START(1, 1)
+               Z_PARAM_ZVAL(data)
+       ZEND_PARSE_PARAMETERS_END();
+
+       // TODO
+}
+ZEND_METHOD(ion_PHP_Unserializer, __construct)
+{
+       zend_object *obj = Z_OBJ_P(ZEND_THIS);
+
+       zend_object *reader_obj;
+       zend_bool call_magic = true;
+       zend_string *call_custom = NULL;
+       ZEND_PARSE_PARAMETERS_START(1, 3)
+               Z_PARAM_OBJ_OF_CLASS(reader_obj, ce_Reader)
+               Z_PARAM_OPTIONAL
+               Z_PARAM_BOOL(call_magic)
+               Z_PARAM_STR_OR_NULL(call_custom)
+       ZEND_PARSE_PARAMETERS_END();
+
+       update_property_obj(obj, ZEND_STRL("reader"), reader_obj);
+       zend_update_property_bool(obj->ce, obj, ZEND_STRL("callMagicUnserialize"),
+                       php_ion_obj(reader, reader_obj)->php.call_magic_unserialize = call_magic);
+       if (call_custom) {
+               zend_update_property_str(obj->ce, obj, ZEND_STRL("callCustomUnserialize"), call_custom);
+               php_ion_obj(reader, reader_obj)->php.custom_unserialize = zend_string_tolower(call_custom);
+       } else {
+               zend_update_property_null(obj->ce, obj, ZEND_STRL("callCustomUnserialize"));
+       }
+}
+ZEND_METHOD(ion_PHP_Unserializer, __invoke)
+{
+       zend_object *obj = Z_OBJ_P(ZEND_THIS);
+
+       zval zreader;
+       if (zend_read_property(obj->ce, obj, ZEND_STRL("reader"), 0, &zreader)) {
+               if (Z_OBJCE(zreader) == ce_Reader_Buffer_Reader || Z_OBJCE(zreader) == ce_Reader_Stream_Reader) {
+                       php_ion_unserialize(php_ion_obj(reader, Z_OBJ(zreader)), NULL, return_value);
+               } else {
+                       zend_call_method_with_0_params(obj, obj->ce, NULL /* TODO */, "unserialize", return_value);
+               }
+       }
+}
+ZEND_METHOD(ion_PHP_Unserializer, unserialize)
+{
+       //zend_object *obj = Z_OBJ_P(ZEND_THIS);
+
+       ZEND_PARSE_PARAMETERS_NONE();
+
+       // TODO
+}
+
+ZEND_FUNCTION(ion_serialize)
+{
+       zval *zv;
+       zend_object *zo_opt = NULL;
+       ZEND_PARSE_PARAMETERS_START(1, 2)
+               Z_PARAM_ZVAL(zv)
+               Z_PARAM_OPTIONAL
+               Z_PARAM_OBJ_OF_CLASS_OR_NULL(zo_opt, ce_Writer_Options)
+       ZEND_PARSE_PARAMETERS_END();
+
+       zval zwriter;
+       object_init_ex(&zwriter, ce_Writer_Buffer_Writer);
+
+       php_ion_writer *obj = php_ion_obj(writer, Z_OBJ(zwriter));
+       obj->opt = zo_opt;
+       obj->type = BUFFER_WRITER;
+
+       php_ion_writer_ctor(obj);
+
+       php_ion_serialize(obj, zv, return_value);
+       zval_ptr_dtor(&zwriter);
+}
+ZEND_FUNCTION(ion_unserialize)
+{
+       zend_string *zstr;
+       zend_object *zo_opt = NULL;
+       ZEND_PARSE_PARAMETERS_START(1, 2)
+               Z_PARAM_STR(zstr)
+               Z_PARAM_OPTIONAL
+               Z_PARAM_OBJ_OF_CLASS_OR_NULL(zo_opt, ce_Reader_Options)
+       ZEND_PARSE_PARAMETERS_END();
+
+       zval zreader;
+       object_init_ex(&zreader, ce_Reader_Buffer_Reader);
+
+       php_ion_reader *obj = php_ion_obj(reader, Z_OBJ(zreader));
+       obj->opt = zo_opt;
+       obj->type = BUFFER_READER;
+       obj->buffer = zend_string_copy(zstr);
+
+       php_ion_reader_ctor(obj);
+       php_ion_unserialize(obj, NULL, return_value);
+       zval_ptr_dtor(&zreader);
+}
+
+PHP_RINIT_FUNCTION(ion)
+{
+#if defined(ZTS) && defined(COMPILE_DL_ION)
+       ZEND_TSRMLS_CACHE_UPDATE();
+#endif
+
+       php_ion_globals_serializer_init();
+       php_ion_globals_unserializer_init();
+       return SUCCESS;
+}
+
+PHP_RSHUTDOWN_FUNCTION(ion)
+{
+       php_ion_globals_serializer_dtor();
+       php_ion_globals_unserializer_dtor();
+       return SUCCESS;
+}
+
+php_ion_decl(type, Type);
+php_ion_decl(symbol, Symbol, php_ion_symbol_dtor(obj));
+php_ion_decl(symbol_iloc, Symbol_ImportLocation, php_ion_symbol_iloc_dtor(obj));
+php_ion_decl(symbol_table, Symbol_Table);
+php_ion_decl(decimal, Decimal, php_ion_decimal_dtor(obj));
+php_ion_decl(decimal_ctx, Decimal_Context);
+php_ion_decl(timestamp, Timestamp, php_ion_timestamp_dtor(obj));
+php_ion_decl(catalog, Catalog);
+php_ion_decl(reader_options, Reader_Options);
+php_ion_decl(reader, Reader_Reader, php_ion_reader_dtor(obj));
+php_ion_decl(writer_options, Writer_Options);
+php_ion_decl(writer, Writer_Writer, php_ion_writer_dtor(obj));
+
+PHP_MINIT_FUNCTION(ion)
+{
+       ce_Annotation = register_class_ion_Annotation();
+
+       php_ion_register(type, Type);
+       php_ion_register(symbol, Symbol);
+       php_ion_register(symbol_iloc, Symbol_ImportLocation);
+       php_ion_register(symbol_table, Symbol_Table);
+
+       ce_Symbol_System = register_class_ion_Symbol_System();
+       ce_Symbol_System_SID = register_class_ion_Symbol_System_SID();
+
+       ce_Collection = register_class_ion_Collection();
+
+       php_ion_register(decimal, Decimal);
+       oh_decimal.get_properties_for = php_ion_decimal_get_props_for;
+       php_ion_register(decimal_ctx, Decimal_Context);
+       php_ion_register(timestamp, Timestamp, php_date_get_date_ce());
+       php_ion_register(catalog, Catalog);
+
+       ce_Reader = register_class_ion_Reader(spl_ce_RecursiveIterator);
+
+       php_ion_register(reader_options, Reader_Options);
+       php_ion_register(reader, Reader_Reader, ce_Reader);
+
+       ce_Reader_Buffer = register_class_ion_Reader_Buffer(ce_Reader);
+       ce_Reader_Buffer_Reader = register_class_ion_Reader_Buffer_Reader(ce_Reader_Reader, ce_Reader_Buffer);
+       ce_Reader_Stream = register_class_ion_Reader_Stream(ce_Reader);
+       ce_Reader_Stream_Reader = register_class_ion_Reader_Stream_Reader(ce_Reader_Reader, ce_Reader_Stream);
+
+       ce_Writer = register_class_ion_Writer();
+
+       php_ion_register(writer_options, Writer_Options);
+       php_ion_register(writer, Writer_Writer, ce_Writer);
+
+       ce_Writer_Buffer = register_class_ion_Writer_Buffer(ce_Writer);
+       ce_Writer_Buffer_Writer = register_class_ion_Writer_Buffer_Writer(ce_Writer_Writer, ce_Writer_Buffer);
+       ce_Writer_Stream = register_class_ion_Writer_Stream(ce_Writer);
+       ce_Writer_Stream_Writer = register_class_ion_Writer_Stream_Writer(ce_Writer_Writer, ce_Writer_Stream);
+
+       ce_PHP_Serializer = register_class_ion_PHP_Serializer();
+       ce_PHP_Unserializer = register_class_ion_PHP_Unserializer();
+
+       return SUCCESS;
+}
+
+PHP_MINFO_FUNCTION(ion)
+{
+       php_info_print_table_start();
+       php_info_print_table_header(2, "ion support", "enabled");
+       php_info_print_table_end();
+}
+
+PHP_GINIT_FUNCTION(ion)
+{
+       memset(ion_globals, 0, sizeof(*ion_globals));
+}
+PHP_GSHUTDOWN_FUNCTION(ion)
+{
+}
+
+static zend_module_dep ion_module_deps[] = {
+       ZEND_MOD_REQUIRED("spl")
+       ZEND_MOD_END
+};
+
+zend_module_entry ion_module_entry = {
+       STANDARD_MODULE_HEADER_EX,
+       NULL,
+       ion_module_deps,
+       "ion",                                  /* Extension name */
+       ext_functions,                  /* zend_function_entry */
+       PHP_MINIT(ion),                 /* PHP_MINIT - Module initialization */
+       NULL,                                   /* PHP_MSHUTDOWN - Module shutdown */
+       PHP_RINIT(ion),                 /* PHP_RINIT - Request initialization */
+       PHP_RSHUTDOWN(ion),             /* PHP_RSHUTDOWN - Request shutdown */
+       PHP_MINFO(ion),                 /* PHP_MINFO - Module info */
+       PHP_ION_VERSION,                /* Version */
+       ZEND_MODULE_GLOBALS(ion),
+       PHP_GINIT(ion),                 /* PHP_GINIT */
+       PHP_GSHUTDOWN(ion),             /* PHP_GSHUTDOWN */
+       NULL,
+       STANDARD_MODULE_PROPERTIES_EX
+};
+
+#ifdef COMPILE_DL_ION
+# ifdef ZTS
+ZEND_TSRMLS_CACHE_DEFINE()
+# endif
+ZEND_GET_MODULE(ion)
+#endif
diff --git a/ion.stub.php b/ion.stub.php
new file mode 100644 (file)
index 0000000..8225a1b
--- /dev/null
@@ -0,0 +1,446 @@
+<?php
+
+/** @generate-class-entries */
+
+namespace ion;
+enum Type : int {
+    case Null       = 0x000;
+    case Bool       = 0x100;
+    case Int        = 0x200;
+    case Float      = 0x400;
+    case Decimal    = 0x500;
+    case Timestamp  = 0x600;
+    case Symbol     = 0x700;
+    case String     = 0x800;
+    case CLob       = 0x900;
+    case BLob       = 0xa00;
+    case AList      = 0xb00;
+    case SExp       = 0xc00;
+    case Struct     = 0xd00;
+    case Datagram   = 0xf00;
+
+    case EOF        =-0x100;
+    case NONE       =-0x200;
+}
+
+enum Annotation : string {
+    case PHP            = "PHP";
+
+    case REFERENCE      = "R";
+    case BACKREF        = "r";
+
+    case OBJECT         = "o";
+    case MAGIC_OBJ      = "O";
+    case CUSTOM_OBJ     = "C";
+    case SERIALIZABLE   = "S";
+    case ENUM           = "E";
+
+    case FIELD_NAME_INT = "i";
+}
+
+namespace ion\Symbol;
+class ImportLocation {
+    public function __construct(
+        public readonly string $name,
+        public readonly int $location,
+    ) {}
+}
+
+namespace ion\Symbol;
+enum System : string {
+    case Ion                = '$ion';
+    case Ivm_1_0            = '$ion_1_0';
+    case IonSymbolTable     = '$ion_symbol_table';
+    case Name               = 'name';
+    case Version            = 'version';
+    case Imports            = 'imports';
+    case Symbols            = 'symbols';
+    case MaxId              = 'max_id';
+    case SharedSymbolTable  = '$ion_shared_symbol_table';
+}
+
+namespace ion\Symbol\System;
+enum SID : int {
+    case Ion                = 1;
+    case Ivm_1_0            = 2;
+    case IonSymbolTable     = 3;
+    case Name               = 4;
+    case Version            = 5;
+    case Imports            = 6;
+    case Symbols            = 7;
+    case MaxId              = 8;
+    case SharedSymbolTable  = 9;
+}
+
+namespace ion;
+class Symbol {
+    public function __construct(
+        public readonly string $value,
+        public readonly int $sid = -1,
+        public readonly ?Symbol\ImportLocation $importLocation = null,
+    ) {}
+
+    public function equals(Symbol $symbol): bool { }
+}
+
+namespace ion\Symbol;
+class Table {
+
+}
+
+namespace ion;
+class Catalog {
+}
+
+namespace ion;
+class Collection {
+
+}
+
+namespace ion;
+class Decimal {
+    public function __construct(
+        string|int $number,
+        public readonly ?Decimal\Context $context = null,
+    ) {}
+
+    public function equals(Decimal $decimal) : bool {}
+    public function zero() : void {}
+
+    public function __toString() : string {}
+    /** @alias ion\Decimal::__toString */
+    public function toString() : string {}
+    public function toInt() : int {}
+}
+
+namespace ion\Decimal;
+class Context {
+
+}
+
+
+namespace ion;
+class Timestamp extends \DateTime {
+    public function __construct(
+        public readonly int $precision,
+        public readonly string $format = "c",
+        string $datetime = "now",
+        ?\DateTimeZone $timezone = null,
+    ) {}
+
+    public function __toString() : string {}
+}
+
+
+namespace ion;
+interface Reader extends \RecursiveIterator {
+    public function getType() : Type;
+    public function hasAnnotations() : bool;
+    public function hasAnnotation(string $annotation) : bool;
+    public function isNull() : bool;
+    public function isInStruct() : bool;
+    public function getFieldName() : string;
+    public function getFieldNameSymbol() : Symbol;
+    public function getAnnotations() : array;
+    public function getAnnotationSymbols() : array;
+    public function countAnnotations() : int;
+    public function getAnnotation(int $index) : string;
+    public function getAnnotationSymbol(int $index) : Symbol;
+
+    public function readNull() : Type;
+    public function readBool() : bool;
+    public function readInt() : int|string;
+    public function readFloat() : float;
+    public function readDecimal() : Decimal;
+    public function readTimestamp() : Timestamp;
+    public function readSymbol() : Symbol;
+    public function readString() : string;
+    /** @param ref $string */
+    public function readStringPart(&$string, int $length = 0x1000) : bool;
+    public function readLob() : string;
+    /** @param ref $string */
+    public function readLobPart(&$string, int $length = 0x1000) : bool;
+
+    public function getPosition() : int;
+    public function getDepth() : int;
+
+    public function seek(int $offset, int $length = -1) : void;
+    /*
+    public function getSymbolTable() : SymbolTable;
+    public function setSymbolTable(SymbolTable $table) : void;
+    */
+    public function getValueOffset() : int;
+    public function getValueLength() : int;
+}
+namespace ion\Reader;
+class Options {
+    public function __construct(
+        public readonly ?\ion\Catalog $catalog = null,
+        public readonly ?\ion\Decimal\Context $decimalContext = null,
+        public readonly ?\Closure $onContextChange = null,
+        public readonly bool $returnSystemValues = false,
+        public readonly int $newLine = 0xa,
+        public readonly int $maxContainerDepth = 10,
+        public readonly int $maxAnnotations = 10,
+        public readonly int $maxAnnotationBuffered = 512,
+        public readonly int $symbolThreshold = 4096,
+        public readonly int $userValueThreshold = 4096,
+        public readonly int $chunkThreshold = 4096,
+        public readonly int $allocationPageSize = 4096,
+        public readonly bool $skipCharacterValidation = false,
+    ) {}
+}
+
+namespace ion\Reader;
+abstract class Reader implements \ion\Reader {
+    public readonly ?Options $options;
+
+    public function hasChildren() : bool {}
+    public function getChildren() : \ion\Reader {}
+
+    public function rewind() : void {}
+    public function next() : void {}
+    public function valid() : bool {}
+    public function key() : mixed {}
+    public function current() : mixed {}
+
+    public function getType() : \ion\Type {}
+    public function hasAnnotations() : bool {}
+    public function hasAnnotation(string $annotation) : bool {}
+    public function isNull() : bool {}
+    public function isInStruct() : bool {}
+    public function getFieldName() : string {}
+    public function getFieldNameSymbol() : \ion\Symbol {}
+    public function getAnnotations() : array {}
+    public function getAnnotationSymbols() : array {}
+    public function countAnnotations() : int {}
+    public function getAnnotation(int $index) : string {}
+    public function getAnnotationSymbol(int $index) : \ion\Symbol {}
+
+    public function readNull() : \ion\Type {}
+    public function readBool() : bool {}
+    public function readInt() : int|string {}
+    public function readFloat() : float {}
+    public function readDecimal() : \ion\Decimal {}
+    public function readTimestamp() : \ion\Timestamp {}
+    public function readSymbol() : \ion\Symbol {}
+    public function readString() : string {}
+    /** @param ref $string */
+    public function readStringPart(&$string, int $length = 0x1000) : bool {}
+    public function readLob() : string {}
+    /** @param ref $string */
+    public function readLobPart(&$string, int $length = 0x1000) : bool {}
+
+    public function getPosition() : int {}
+    public function getDepth() : int{}
+
+    public function seek(int $offset, int $length = -1) : void {}
+    /*
+    public function getSymbolTable() : SymbolTable {}
+    public function setSymbolTable(SymbolTable $table) : void {}
+    */
+    public function getValueOffset() : int {}
+    public function getValueLength() : int {}
+}
+namespace ion\Reader;
+interface Buffer extends \ion\Reader {
+    public function getBuffer() : string;
+}
+
+namespace ion\Reader\Buffer;
+class Reader extends \ion\Reader\Reader implements \ion\Reader\Buffer {
+    public function __construct(
+        string $buffer,
+        ?\ion\Reader\Options $options = null,
+    ) {}
+
+    public function getBuffer() : string {}
+}
+
+namespace ion\Reader;
+interface Stream extends \ion\Reader {
+    /** @return resource */
+    public function getStream();
+    /** @param resource $stream */
+    public function resetStream($stream) : void;
+    /** @param resource $stream */
+    public function resetStreamWithLength($stream, int $position, int $length = -1) : void;
+}
+
+namespace ion\Reader\Stream;
+class Reader extends \ion\Reader\Reader implements \ion\Reader\Stream {
+    /** @param resource $stream */
+    public function __construct(
+        $stream,
+        ?\ion\Reader\Options $options = null,
+    ) {
+    }
+    /** @return resource */
+    public function getStream() {}
+    /** @param resource $stream */
+    public function resetStream($stream) : void {}
+    /** @param resource $stream */
+    public function resetStreamWithLength($stream, int $position, int $length = -1) : void {}
+}
+
+namespace ion\Writer;
+class Options {
+    public function __construct(
+        public readonly ?\ion\Catalog $catalog = null,
+        public readonly ?\ion\Decimal\Context $decimalContext = null,
+        ?\ion\Collection $encodingSymbolTable = null,
+        public readonly bool $outputBinary = false,
+        public readonly bool $compactFloats = false,
+        public readonly bool $escapeNonAscii = false,
+        public readonly bool $prettyPrint = false,
+        public readonly bool $indentTabs = true,
+        public readonly int $indentSize = 2,
+        public readonly bool $smallContainersInline = true,
+        public readonly bool $suppressSystemValues = false,
+        public readonly bool $flushEveryValue = false,
+        public readonly int $maxContainerDepth = 10,
+        public readonly int $maxAnnotations = 10,
+        public readonly int $tempBufferSize = 0x400,
+        public readonly int $allocationPageSize = 0x1000,
+    ) {}
+
+    // public function addSharedImports(\ion\Collection|\ion\Symbol\Table ...$imports) : void;
+}
+
+namespace ion;
+interface Writer {
+    public function writeNull() : void;
+    public function writeTypedNull(Type $type) : void;
+    public function writeBool(bool $value) : void;
+    public function writeInt(int|string $value) : void;
+    public function writeFloat(float $value) : void;
+    public function writeDecimal(Decimal|string $value) : void;
+    public function writeTimestamp(Timestamp|string $value) : void;
+    public function writeSymbol(Symbol|string $value) : void;
+    public function writeString(string $value) : void;
+    public function writeCLob(string $value) : void;
+    public function writeBLob(string $value) : void;
+
+    public function startLob(Type $type) : void;
+    public function appendLob(string $data) : void;
+    public function finishLob() : void;
+
+    public function startContainer(Type $type) : void;
+    public function finishContainer() : void;
+
+    public function writeFieldName(string $name) : void;
+
+    public function writeAnnotation(Symbol|string ...$annotation) : void;
+
+    public function getDepth() : int;
+    public function flush() : int;
+    public function finish() : int;
+
+    public function writeOne(Reader $reader) : void;
+    public function writeAll(Reader $reader) : void;
+
+    // public function getCatalog() : Catalog;
+    // public function setCatalog(Catalog $catalog) : void;
+
+    // public function getSymbolTable() : Symbol\Table;
+    // puvlic function setSymbolTable(Symbol\Table $table) : void;
+}
+
+namespace ion\Writer;
+abstract class Writer implements \ion\Writer {
+    public function writeNull() : void {}
+    public function writeTypedNull(\ion\Type $type) : void {}
+    public function writeBool(bool $value) : void {}
+    public function writeInt(int|string $value) : void {}
+    public function writeFloat(float $value) : void {}
+    public function writeDecimal(\ion\Decimal|string $value) : void {}
+    public function writeTimestamp(\ion\Timestamp|string $value) : void {}
+    public function writeSymbol(\ion\Symbol|string $value) : void {}
+    public function writeString(string $value) : void {}
+    public function writeCLob(string $value) : void {}
+    public function writeBLob(string $value) : void {}
+
+    public function startLob(\ion\Type $type) : void {}
+    public function appendLob(string $data) : void {}
+    public function finishLob() : void {}
+
+    public function startContainer(\ion\Type $type) : void {}
+    public function finishContainer() : void {}
+
+    public function writeFieldName(string $name) : void {}
+
+    public function writeAnnotation(\ion\Symbol|string ...$annotation) : void {}
+
+    public function getDepth() : int {}
+    public function flush() : int {}
+    public function finish() : int {}
+
+    public function writeOne(\ion\Reader $reader) : void {}
+    public function writeAll(\ion\Reader $reader) : void {}
+}
+
+namespace ion\Writer;
+interface Buffer extends \ion\Writer {
+    public function getBuffer() : string;
+}
+
+namespace ion\Writer\Buffer;
+class Writer extends \ion\Writer\Writer implements \ion\Writer\Buffer {
+    /** @param ref $buffer */
+    public function __construct(
+        ?string &$buffer,
+        ?\ion\Writer\Options $options = null,
+    ) {}
+
+    /**
+     * @return string a _copy_ of $buffer passed to the constructor
+     */
+    public function getBuffer() : string {}
+}
+
+namespace ion\Writer;
+interface Stream extends \ion\Writer {
+    /** @return resource */
+    public function getStream();
+}
+
+namespace ion\Writer\Stream;
+class Writer extends \ion\Writer\Writer implements \ion\Writer\Stream {
+    /** @param resource $stream */
+    public function __construct(
+        $stream,
+        ?\ion\Writer\Options $options = null,
+    ) {}
+    /** @return resource */
+    public function getStream() {}
+}
+
+namespace ion\PHP;
+class Serializer {
+    public function __construct(
+        public readonly \ion\Writer $writer,
+        public readonly bool $callMagicSerialize = true,
+        public readonly ?string $callCustomSerialize = null,
+    ) {}
+    public function __invoke(mixed $data) : void {}
+    protected function serialize(mixed $data) : void {}
+}
+
+namespace ion\PHP;
+class Unserializer {
+    public function __construct(
+        public readonly \ion\Reader $reader,
+        public readonly bool $callMagicUnserialize = true,
+        public readonly ?string $callCustomUnserialize = null,
+    ){}
+    public function __invoke() : mixed {}
+    protected function unserialize() : mixed {}
+}
+
+namespace ion;
+function serialize(mixed $data, Writer\Options $options = null) : string {}
+function unserialize(mixed $serialized, Reader\Options $options = null) : mixed {}
+
+
+
+
diff --git a/ion_arginfo.h b/ion_arginfo.h
new file mode 100644 (file)
index 0000000..72a4aab
--- /dev/null
@@ -0,0 +1,1548 @@
+/* This is a generated file, edit the .stub.php file instead.
+ * Stub hash: 5f1798e701fcd53837ee41a601cc70e8cb962316 */
+
+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)
+       ZEND_ARG_OBJ_INFO_WITH_DEFAULT_VALUE(0, options, ion\\Writer\\Options, 0, "null")
+ZEND_END_ARG_INFO()
+
+ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_ion_unserialize, 0, 1, IS_MIXED, 0)
+       ZEND_ARG_TYPE_INFO(0, serialized, IS_MIXED, 0)
+       ZEND_ARG_OBJ_INFO_WITH_DEFAULT_VALUE(0, options, ion\\Reader\\Options, 0, "null")
+ZEND_END_ARG_INFO()
+
+ZEND_BEGIN_ARG_INFO_EX(arginfo_class_ion_Symbol_ImportLocation___construct, 0, 0, 2)
+       ZEND_ARG_TYPE_INFO(0, name, IS_STRING, 0)
+       ZEND_ARG_TYPE_INFO(0, location, IS_LONG, 0)
+ZEND_END_ARG_INFO()
+
+ZEND_BEGIN_ARG_INFO_EX(arginfo_class_ion_Symbol___construct, 0, 0, 1)
+       ZEND_ARG_TYPE_INFO(0, value, IS_STRING, 0)
+       ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, sid, IS_LONG, 0, "-1")
+       ZEND_ARG_OBJ_INFO_WITH_DEFAULT_VALUE(0, importLocation, ion\\Symbol\\ImportLocation, 1, "null")
+ZEND_END_ARG_INFO()
+
+ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_ion_Symbol_equals, 0, 1, _IS_BOOL, 0)
+       ZEND_ARG_OBJ_INFO(0, symbol, ion\\Symbol, 0)
+ZEND_END_ARG_INFO()
+
+ZEND_BEGIN_ARG_INFO_EX(arginfo_class_ion_Decimal___construct, 0, 0, 1)
+       ZEND_ARG_TYPE_MASK(0, number, MAY_BE_STRING|MAY_BE_LONG, NULL)
+       ZEND_ARG_OBJ_INFO_WITH_DEFAULT_VALUE(0, context, ion\\Decimal\\Context, 1, "null")
+ZEND_END_ARG_INFO()
+
+ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_ion_Decimal_equals, 0, 1, _IS_BOOL, 0)
+       ZEND_ARG_OBJ_INFO(0, decimal, ion\\Decimal, 0)
+ZEND_END_ARG_INFO()
+
+ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_ion_Decimal_zero, 0, 0, IS_VOID, 0)
+ZEND_END_ARG_INFO()
+
+ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_ion_Decimal___toString, 0, 0, IS_STRING, 0)
+ZEND_END_ARG_INFO()
+
+#define arginfo_class_ion_Decimal_toString arginfo_class_ion_Decimal___toString
+
+ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_ion_Decimal_toInt, 0, 0, IS_LONG, 0)
+ZEND_END_ARG_INFO()
+
+ZEND_BEGIN_ARG_INFO_EX(arginfo_class_ion_Timestamp___construct, 0, 0, 1)
+       ZEND_ARG_TYPE_INFO(0, precision, IS_LONG, 0)
+       ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, format, IS_STRING, 0, "\"c\"")
+       ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, datetime, IS_STRING, 0, "\"now\"")
+       ZEND_ARG_OBJ_INFO_WITH_DEFAULT_VALUE(0, timezone, DateTimeZone, 1, "null")
+ZEND_END_ARG_INFO()
+
+#define arginfo_class_ion_Timestamp___toString arginfo_class_ion_Decimal___toString
+
+ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(arginfo_class_ion_Reader_getType, 0, 0, ion\\Type, 0)
+ZEND_END_ARG_INFO()
+
+ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_ion_Reader_hasAnnotations, 0, 0, _IS_BOOL, 0)
+ZEND_END_ARG_INFO()
+
+ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_ion_Reader_hasAnnotation, 0, 1, _IS_BOOL, 0)
+       ZEND_ARG_TYPE_INFO(0, annotation, IS_STRING, 0)
+ZEND_END_ARG_INFO()
+
+#define arginfo_class_ion_Reader_isNull arginfo_class_ion_Reader_hasAnnotations
+
+#define arginfo_class_ion_Reader_isInStruct arginfo_class_ion_Reader_hasAnnotations
+
+#define arginfo_class_ion_Reader_getFieldName arginfo_class_ion_Decimal___toString
+
+ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(arginfo_class_ion_Reader_getFieldNameSymbol, 0, 0, ion\\Symbol, 0)
+ZEND_END_ARG_INFO()
+
+ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_ion_Reader_getAnnotations, 0, 0, IS_ARRAY, 0)
+ZEND_END_ARG_INFO()
+
+#define arginfo_class_ion_Reader_getAnnotationSymbols arginfo_class_ion_Reader_getAnnotations
+
+#define arginfo_class_ion_Reader_countAnnotations arginfo_class_ion_Decimal_toInt
+
+ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_ion_Reader_getAnnotation, 0, 1, IS_STRING, 0)
+       ZEND_ARG_TYPE_INFO(0, index, IS_LONG, 0)
+ZEND_END_ARG_INFO()
+
+ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(arginfo_class_ion_Reader_getAnnotationSymbol, 0, 1, ion\\Symbol, 0)
+       ZEND_ARG_TYPE_INFO(0, index, IS_LONG, 0)
+ZEND_END_ARG_INFO()
+
+#define arginfo_class_ion_Reader_readNull arginfo_class_ion_Reader_getType
+
+#define arginfo_class_ion_Reader_readBool arginfo_class_ion_Reader_hasAnnotations
+
+ZEND_BEGIN_ARG_WITH_RETURN_TYPE_MASK_EX(arginfo_class_ion_Reader_readInt, 0, 0, MAY_BE_LONG|MAY_BE_STRING)
+ZEND_END_ARG_INFO()
+
+ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_ion_Reader_readFloat, 0, 0, IS_DOUBLE, 0)
+ZEND_END_ARG_INFO()
+
+ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(arginfo_class_ion_Reader_readDecimal, 0, 0, ion\\Decimal, 0)
+ZEND_END_ARG_INFO()
+
+ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(arginfo_class_ion_Reader_readTimestamp, 0, 0, ion\\Timestamp, 0)
+ZEND_END_ARG_INFO()
+
+#define arginfo_class_ion_Reader_readSymbol arginfo_class_ion_Reader_getFieldNameSymbol
+
+#define arginfo_class_ion_Reader_readString arginfo_class_ion_Decimal___toString
+
+ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_ion_Reader_readStringPart, 0, 1, _IS_BOOL, 0)
+       ZEND_ARG_INFO(1, string)
+       ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, length, IS_LONG, 0, "0x1000")
+ZEND_END_ARG_INFO()
+
+#define arginfo_class_ion_Reader_readLob arginfo_class_ion_Decimal___toString
+
+#define arginfo_class_ion_Reader_readLobPart arginfo_class_ion_Reader_readStringPart
+
+#define arginfo_class_ion_Reader_getPosition arginfo_class_ion_Decimal_toInt
+
+#define arginfo_class_ion_Reader_getDepth arginfo_class_ion_Decimal_toInt
+
+ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_ion_Reader_seek, 0, 1, IS_VOID, 0)
+       ZEND_ARG_TYPE_INFO(0, offset, IS_LONG, 0)
+       ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, length, IS_LONG, 0, "-1")
+ZEND_END_ARG_INFO()
+
+#define arginfo_class_ion_Reader_getValueOffset arginfo_class_ion_Decimal_toInt
+
+#define arginfo_class_ion_Reader_getValueLength arginfo_class_ion_Decimal_toInt
+
+ZEND_BEGIN_ARG_INFO_EX(arginfo_class_ion_Reader_Options___construct, 0, 0, 0)
+       ZEND_ARG_OBJ_INFO_WITH_DEFAULT_VALUE(0, catalog, ion\\Catalog, 1, "null")
+       ZEND_ARG_OBJ_INFO_WITH_DEFAULT_VALUE(0, decimalContext, ion\\Decimal\\Context, 1, "null")
+       ZEND_ARG_OBJ_INFO_WITH_DEFAULT_VALUE(0, onContextChange, Closure, 1, "null")
+       ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, returnSystemValues, _IS_BOOL, 0, "false")
+       ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, newLine, IS_LONG, 0, "0xa")
+       ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, maxContainerDepth, IS_LONG, 0, "10")
+       ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, maxAnnotations, IS_LONG, 0, "10")
+       ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, maxAnnotationBuffered, IS_LONG, 0, "512")
+       ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, symbolThreshold, IS_LONG, 0, "4096")
+       ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, userValueThreshold, IS_LONG, 0, "4096")
+       ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, chunkThreshold, IS_LONG, 0, "4096")
+       ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, allocationPageSize, IS_LONG, 0, "4096")
+       ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, skipCharacterValidation, _IS_BOOL, 0, "false")
+ZEND_END_ARG_INFO()
+
+#define arginfo_class_ion_Reader_Reader_hasChildren arginfo_class_ion_Reader_hasAnnotations
+
+ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(arginfo_class_ion_Reader_Reader_getChildren, 0, 0, ion\\Reader, 0)
+ZEND_END_ARG_INFO()
+
+#define arginfo_class_ion_Reader_Reader_rewind arginfo_class_ion_Decimal_zero
+
+#define arginfo_class_ion_Reader_Reader_next arginfo_class_ion_Decimal_zero
+
+#define arginfo_class_ion_Reader_Reader_valid arginfo_class_ion_Reader_hasAnnotations
+
+ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_ion_Reader_Reader_key, 0, 0, IS_MIXED, 0)
+ZEND_END_ARG_INFO()
+
+#define arginfo_class_ion_Reader_Reader_current arginfo_class_ion_Reader_Reader_key
+
+#define arginfo_class_ion_Reader_Reader_getType arginfo_class_ion_Reader_getType
+
+#define arginfo_class_ion_Reader_Reader_hasAnnotations arginfo_class_ion_Reader_hasAnnotations
+
+#define arginfo_class_ion_Reader_Reader_hasAnnotation arginfo_class_ion_Reader_hasAnnotation
+
+#define arginfo_class_ion_Reader_Reader_isNull arginfo_class_ion_Reader_hasAnnotations
+
+#define arginfo_class_ion_Reader_Reader_isInStruct arginfo_class_ion_Reader_hasAnnotations
+
+#define arginfo_class_ion_Reader_Reader_getFieldName arginfo_class_ion_Decimal___toString
+
+#define arginfo_class_ion_Reader_Reader_getFieldNameSymbol arginfo_class_ion_Reader_getFieldNameSymbol
+
+#define arginfo_class_ion_Reader_Reader_getAnnotations arginfo_class_ion_Reader_getAnnotations
+
+#define arginfo_class_ion_Reader_Reader_getAnnotationSymbols arginfo_class_ion_Reader_getAnnotations
+
+#define arginfo_class_ion_Reader_Reader_countAnnotations arginfo_class_ion_Decimal_toInt
+
+#define arginfo_class_ion_Reader_Reader_getAnnotation arginfo_class_ion_Reader_getAnnotation
+
+#define arginfo_class_ion_Reader_Reader_getAnnotationSymbol arginfo_class_ion_Reader_getAnnotationSymbol
+
+#define arginfo_class_ion_Reader_Reader_readNull arginfo_class_ion_Reader_getType
+
+#define arginfo_class_ion_Reader_Reader_readBool arginfo_class_ion_Reader_hasAnnotations
+
+#define arginfo_class_ion_Reader_Reader_readInt arginfo_class_ion_Reader_readInt
+
+#define arginfo_class_ion_Reader_Reader_readFloat arginfo_class_ion_Reader_readFloat
+
+#define arginfo_class_ion_Reader_Reader_readDecimal arginfo_class_ion_Reader_readDecimal
+
+#define arginfo_class_ion_Reader_Reader_readTimestamp arginfo_class_ion_Reader_readTimestamp
+
+#define arginfo_class_ion_Reader_Reader_readSymbol arginfo_class_ion_Reader_getFieldNameSymbol
+
+#define arginfo_class_ion_Reader_Reader_readString arginfo_class_ion_Decimal___toString
+
+#define arginfo_class_ion_Reader_Reader_readStringPart arginfo_class_ion_Reader_readStringPart
+
+#define arginfo_class_ion_Reader_Reader_readLob arginfo_class_ion_Decimal___toString
+
+#define arginfo_class_ion_Reader_Reader_readLobPart arginfo_class_ion_Reader_readStringPart
+
+#define arginfo_class_ion_Reader_Reader_getPosition arginfo_class_ion_Decimal_toInt
+
+#define arginfo_class_ion_Reader_Reader_getDepth arginfo_class_ion_Decimal_toInt
+
+#define arginfo_class_ion_Reader_Reader_seek arginfo_class_ion_Reader_seek
+
+#define arginfo_class_ion_Reader_Reader_getValueOffset arginfo_class_ion_Decimal_toInt
+
+#define arginfo_class_ion_Reader_Reader_getValueLength arginfo_class_ion_Decimal_toInt
+
+#define arginfo_class_ion_Reader_Buffer_getBuffer arginfo_class_ion_Decimal___toString
+
+ZEND_BEGIN_ARG_INFO_EX(arginfo_class_ion_Reader_Buffer_Reader___construct, 0, 0, 1)
+       ZEND_ARG_TYPE_INFO(0, buffer, IS_STRING, 0)
+       ZEND_ARG_OBJ_INFO_WITH_DEFAULT_VALUE(0, options, ion\\Reader\\Options, 1, "null")
+ZEND_END_ARG_INFO()
+
+#define arginfo_class_ion_Reader_Buffer_Reader_getBuffer arginfo_class_ion_Decimal___toString
+
+ZEND_BEGIN_ARG_INFO_EX(arginfo_class_ion_Reader_Stream_getStream, 0, 0, 0)
+ZEND_END_ARG_INFO()
+
+ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_ion_Reader_Stream_resetStream, 0, 1, IS_VOID, 0)
+       ZEND_ARG_INFO(0, stream)
+ZEND_END_ARG_INFO()
+
+ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_ion_Reader_Stream_resetStreamWithLength, 0, 2, IS_VOID, 0)
+       ZEND_ARG_INFO(0, stream)
+       ZEND_ARG_TYPE_INFO(0, position, IS_LONG, 0)
+       ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, length, IS_LONG, 0, "-1")
+ZEND_END_ARG_INFO()
+
+ZEND_BEGIN_ARG_INFO_EX(arginfo_class_ion_Reader_Stream_Reader___construct, 0, 0, 1)
+       ZEND_ARG_INFO(0, stream)
+       ZEND_ARG_OBJ_INFO_WITH_DEFAULT_VALUE(0, options, ion\\Reader\\Options, 1, "null")
+ZEND_END_ARG_INFO()
+
+#define arginfo_class_ion_Reader_Stream_Reader_getStream arginfo_class_ion_Reader_Stream_getStream
+
+#define arginfo_class_ion_Reader_Stream_Reader_resetStream arginfo_class_ion_Reader_Stream_resetStream
+
+#define arginfo_class_ion_Reader_Stream_Reader_resetStreamWithLength arginfo_class_ion_Reader_Stream_resetStreamWithLength
+
+ZEND_BEGIN_ARG_INFO_EX(arginfo_class_ion_Writer_Options___construct, 0, 0, 0)
+       ZEND_ARG_OBJ_INFO_WITH_DEFAULT_VALUE(0, catalog, ion\\Catalog, 1, "null")
+       ZEND_ARG_OBJ_INFO_WITH_DEFAULT_VALUE(0, decimalContext, ion\\Decimal\\Context, 1, "null")
+       ZEND_ARG_OBJ_INFO_WITH_DEFAULT_VALUE(0, encodingSymbolTable, ion\\Collection, 1, "null")
+       ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, outputBinary, _IS_BOOL, 0, "false")
+       ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, compactFloats, _IS_BOOL, 0, "false")
+       ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, escapeNonAscii, _IS_BOOL, 0, "false")
+       ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, prettyPrint, _IS_BOOL, 0, "false")
+       ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, indentTabs, _IS_BOOL, 0, "true")
+       ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, indentSize, IS_LONG, 0, "2")
+       ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, smallContainersInline, _IS_BOOL, 0, "true")
+       ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, suppressSystemValues, _IS_BOOL, 0, "false")
+       ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, flushEveryValue, _IS_BOOL, 0, "false")
+       ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, maxContainerDepth, IS_LONG, 0, "10")
+       ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, maxAnnotations, IS_LONG, 0, "10")
+       ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, tempBufferSize, IS_LONG, 0, "0x400")
+       ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, allocationPageSize, IS_LONG, 0, "0x1000")
+ZEND_END_ARG_INFO()
+
+#define arginfo_class_ion_Writer_writeNull arginfo_class_ion_Decimal_zero
+
+ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_ion_Writer_writeTypedNull, 0, 1, IS_VOID, 0)
+       ZEND_ARG_OBJ_INFO(0, type, ion\\Type, 0)
+ZEND_END_ARG_INFO()
+
+ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_ion_Writer_writeBool, 0, 1, IS_VOID, 0)
+       ZEND_ARG_TYPE_INFO(0, value, _IS_BOOL, 0)
+ZEND_END_ARG_INFO()
+
+ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_ion_Writer_writeInt, 0, 1, IS_VOID, 0)
+       ZEND_ARG_TYPE_MASK(0, value, MAY_BE_LONG|MAY_BE_STRING, NULL)
+ZEND_END_ARG_INFO()
+
+ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_ion_Writer_writeFloat, 0, 1, IS_VOID, 0)
+       ZEND_ARG_TYPE_INFO(0, value, IS_DOUBLE, 0)
+ZEND_END_ARG_INFO()
+
+ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_ion_Writer_writeDecimal, 0, 1, IS_VOID, 0)
+       ZEND_ARG_OBJ_TYPE_MASK(0, value, ion\\Decimal, MAY_BE_STRING, NULL)
+ZEND_END_ARG_INFO()
+
+ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_ion_Writer_writeTimestamp, 0, 1, IS_VOID, 0)
+       ZEND_ARG_OBJ_TYPE_MASK(0, value, ion\\Timestamp, MAY_BE_STRING, NULL)
+ZEND_END_ARG_INFO()
+
+ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_ion_Writer_writeSymbol, 0, 1, IS_VOID, 0)
+       ZEND_ARG_OBJ_TYPE_MASK(0, value, ion\\Symbol, MAY_BE_STRING, NULL)
+ZEND_END_ARG_INFO()
+
+ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_ion_Writer_writeString, 0, 1, IS_VOID, 0)
+       ZEND_ARG_TYPE_INFO(0, value, IS_STRING, 0)
+ZEND_END_ARG_INFO()
+
+#define arginfo_class_ion_Writer_writeCLob arginfo_class_ion_Writer_writeString
+
+#define arginfo_class_ion_Writer_writeBLob arginfo_class_ion_Writer_writeString
+
+#define arginfo_class_ion_Writer_startLob arginfo_class_ion_Writer_writeTypedNull
+
+ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_ion_Writer_appendLob, 0, 1, IS_VOID, 0)
+       ZEND_ARG_TYPE_INFO(0, data, IS_STRING, 0)
+ZEND_END_ARG_INFO()
+
+#define arginfo_class_ion_Writer_finishLob arginfo_class_ion_Decimal_zero
+
+#define arginfo_class_ion_Writer_startContainer arginfo_class_ion_Writer_writeTypedNull
+
+#define arginfo_class_ion_Writer_finishContainer arginfo_class_ion_Decimal_zero
+
+ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_ion_Writer_writeFieldName, 0, 1, IS_VOID, 0)
+       ZEND_ARG_TYPE_INFO(0, name, IS_STRING, 0)
+ZEND_END_ARG_INFO()
+
+ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_ion_Writer_writeAnnotation, 0, 0, IS_VOID, 0)
+       ZEND_ARG_VARIADIC_OBJ_TYPE_MASK(0, annotation, ion\\Symbol, MAY_BE_STRING, NULL)
+ZEND_END_ARG_INFO()
+
+#define arginfo_class_ion_Writer_getDepth arginfo_class_ion_Decimal_toInt
+
+#define arginfo_class_ion_Writer_flush arginfo_class_ion_Decimal_toInt
+
+#define arginfo_class_ion_Writer_finish arginfo_class_ion_Decimal_toInt
+
+ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_ion_Writer_writeOne, 0, 1, IS_VOID, 0)
+       ZEND_ARG_OBJ_INFO(0, reader, ion\\Reader, 0)
+ZEND_END_ARG_INFO()
+
+#define arginfo_class_ion_Writer_writeAll arginfo_class_ion_Writer_writeOne
+
+#define arginfo_class_ion_Writer_Writer_writeNull arginfo_class_ion_Decimal_zero
+
+#define arginfo_class_ion_Writer_Writer_writeTypedNull arginfo_class_ion_Writer_writeTypedNull
+
+#define arginfo_class_ion_Writer_Writer_writeBool arginfo_class_ion_Writer_writeBool
+
+#define arginfo_class_ion_Writer_Writer_writeInt arginfo_class_ion_Writer_writeInt
+
+#define arginfo_class_ion_Writer_Writer_writeFloat arginfo_class_ion_Writer_writeFloat
+
+#define arginfo_class_ion_Writer_Writer_writeDecimal arginfo_class_ion_Writer_writeDecimal
+
+#define arginfo_class_ion_Writer_Writer_writeTimestamp arginfo_class_ion_Writer_writeTimestamp
+
+#define arginfo_class_ion_Writer_Writer_writeSymbol arginfo_class_ion_Writer_writeSymbol
+
+#define arginfo_class_ion_Writer_Writer_writeString arginfo_class_ion_Writer_writeString
+
+#define arginfo_class_ion_Writer_Writer_writeCLob arginfo_class_ion_Writer_writeString
+
+#define arginfo_class_ion_Writer_Writer_writeBLob arginfo_class_ion_Writer_writeString
+
+#define arginfo_class_ion_Writer_Writer_startLob arginfo_class_ion_Writer_writeTypedNull
+
+#define arginfo_class_ion_Writer_Writer_appendLob arginfo_class_ion_Writer_appendLob
+
+#define arginfo_class_ion_Writer_Writer_finishLob arginfo_class_ion_Decimal_zero
+
+#define arginfo_class_ion_Writer_Writer_startContainer arginfo_class_ion_Writer_writeTypedNull
+
+#define arginfo_class_ion_Writer_Writer_finishContainer arginfo_class_ion_Decimal_zero
+
+#define arginfo_class_ion_Writer_Writer_writeFieldName arginfo_class_ion_Writer_writeFieldName
+
+#define arginfo_class_ion_Writer_Writer_writeAnnotation arginfo_class_ion_Writer_writeAnnotation
+
+#define arginfo_class_ion_Writer_Writer_getDepth arginfo_class_ion_Decimal_toInt
+
+#define arginfo_class_ion_Writer_Writer_flush arginfo_class_ion_Decimal_toInt
+
+#define arginfo_class_ion_Writer_Writer_finish arginfo_class_ion_Decimal_toInt
+
+#define arginfo_class_ion_Writer_Writer_writeOne arginfo_class_ion_Writer_writeOne
+
+#define arginfo_class_ion_Writer_Writer_writeAll arginfo_class_ion_Writer_writeOne
+
+#define arginfo_class_ion_Writer_Buffer_getBuffer arginfo_class_ion_Decimal___toString
+
+ZEND_BEGIN_ARG_INFO_EX(arginfo_class_ion_Writer_Buffer_Writer___construct, 0, 0, 1)
+       ZEND_ARG_TYPE_INFO(1, buffer, IS_STRING, 1)
+       ZEND_ARG_OBJ_INFO_WITH_DEFAULT_VALUE(0, options, ion\\Writer\\Options, 1, "null")
+ZEND_END_ARG_INFO()
+
+#define arginfo_class_ion_Writer_Buffer_Writer_getBuffer arginfo_class_ion_Decimal___toString
+
+#define arginfo_class_ion_Writer_Stream_getStream arginfo_class_ion_Reader_Stream_getStream
+
+ZEND_BEGIN_ARG_INFO_EX(arginfo_class_ion_Writer_Stream_Writer___construct, 0, 0, 1)
+       ZEND_ARG_INFO(0, stream)
+       ZEND_ARG_OBJ_INFO_WITH_DEFAULT_VALUE(0, options, ion\\Writer\\Options, 1, "null")
+ZEND_END_ARG_INFO()
+
+#define arginfo_class_ion_Writer_Stream_Writer_getStream arginfo_class_ion_Reader_Stream_getStream
+
+ZEND_BEGIN_ARG_INFO_EX(arginfo_class_ion_PHP_Serializer___construct, 0, 0, 1)
+       ZEND_ARG_OBJ_INFO(0, writer, ion\\Writer, 0)
+       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()
+
+ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_ion_PHP_Serializer___invoke, 0, 1, IS_VOID, 0)
+       ZEND_ARG_TYPE_INFO(0, data, IS_MIXED, 0)
+ZEND_END_ARG_INFO()
+
+#define arginfo_class_ion_PHP_Serializer_serialize arginfo_class_ion_PHP_Serializer___invoke
+
+ZEND_BEGIN_ARG_INFO_EX(arginfo_class_ion_PHP_Unserializer___construct, 0, 0, 1)
+       ZEND_ARG_OBJ_INFO(0, reader, ion\\Reader, 0)
+       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()
+
+#define arginfo_class_ion_PHP_Unserializer___invoke arginfo_class_ion_Reader_Reader_key
+
+#define arginfo_class_ion_PHP_Unserializer_unserialize arginfo_class_ion_Reader_Reader_key
+
+
+ZEND_FUNCTION(ion_serialize);
+ZEND_FUNCTION(ion_unserialize);
+ZEND_METHOD(ion_Symbol_ImportLocation, __construct);
+ZEND_METHOD(ion_Symbol, __construct);
+ZEND_METHOD(ion_Symbol, equals);
+ZEND_METHOD(ion_Decimal, __construct);
+ZEND_METHOD(ion_Decimal, equals);
+ZEND_METHOD(ion_Decimal, zero);
+ZEND_METHOD(ion_Decimal, __toString);
+ZEND_METHOD(ion_Decimal, toInt);
+ZEND_METHOD(ion_Timestamp, __construct);
+ZEND_METHOD(ion_Timestamp, __toString);
+ZEND_METHOD(ion_Reader_Options, __construct);
+ZEND_METHOD(ion_Reader_Reader, hasChildren);
+ZEND_METHOD(ion_Reader_Reader, getChildren);
+ZEND_METHOD(ion_Reader_Reader, rewind);
+ZEND_METHOD(ion_Reader_Reader, next);
+ZEND_METHOD(ion_Reader_Reader, valid);
+ZEND_METHOD(ion_Reader_Reader, key);
+ZEND_METHOD(ion_Reader_Reader, current);
+ZEND_METHOD(ion_Reader_Reader, getType);
+ZEND_METHOD(ion_Reader_Reader, hasAnnotations);
+ZEND_METHOD(ion_Reader_Reader, hasAnnotation);
+ZEND_METHOD(ion_Reader_Reader, isNull);
+ZEND_METHOD(ion_Reader_Reader, isInStruct);
+ZEND_METHOD(ion_Reader_Reader, getFieldName);
+ZEND_METHOD(ion_Reader_Reader, getFieldNameSymbol);
+ZEND_METHOD(ion_Reader_Reader, getAnnotations);
+ZEND_METHOD(ion_Reader_Reader, getAnnotationSymbols);
+ZEND_METHOD(ion_Reader_Reader, countAnnotations);
+ZEND_METHOD(ion_Reader_Reader, getAnnotation);
+ZEND_METHOD(ion_Reader_Reader, getAnnotationSymbol);
+ZEND_METHOD(ion_Reader_Reader, readNull);
+ZEND_METHOD(ion_Reader_Reader, readBool);
+ZEND_METHOD(ion_Reader_Reader, readInt);
+ZEND_METHOD(ion_Reader_Reader, readFloat);
+ZEND_METHOD(ion_Reader_Reader, readDecimal);
+ZEND_METHOD(ion_Reader_Reader, readTimestamp);
+ZEND_METHOD(ion_Reader_Reader, readSymbol);
+ZEND_METHOD(ion_Reader_Reader, readString);
+ZEND_METHOD(ion_Reader_Reader, readStringPart);
+ZEND_METHOD(ion_Reader_Reader, readLob);
+ZEND_METHOD(ion_Reader_Reader, readLobPart);
+ZEND_METHOD(ion_Reader_Reader, getPosition);
+ZEND_METHOD(ion_Reader_Reader, getDepth);
+ZEND_METHOD(ion_Reader_Reader, seek);
+ZEND_METHOD(ion_Reader_Reader, getValueOffset);
+ZEND_METHOD(ion_Reader_Reader, getValueLength);
+ZEND_METHOD(ion_Reader_Buffer_Reader, __construct);
+ZEND_METHOD(ion_Reader_Buffer_Reader, getBuffer);
+ZEND_METHOD(ion_Reader_Stream_Reader, __construct);
+ZEND_METHOD(ion_Reader_Stream_Reader, getStream);
+ZEND_METHOD(ion_Reader_Stream_Reader, resetStream);
+ZEND_METHOD(ion_Reader_Stream_Reader, resetStreamWithLength);
+ZEND_METHOD(ion_Writer_Options, __construct);
+ZEND_METHOD(ion_Writer_Writer, writeNull);
+ZEND_METHOD(ion_Writer_Writer, writeTypedNull);
+ZEND_METHOD(ion_Writer_Writer, writeBool);
+ZEND_METHOD(ion_Writer_Writer, writeInt);
+ZEND_METHOD(ion_Writer_Writer, writeFloat);
+ZEND_METHOD(ion_Writer_Writer, writeDecimal);
+ZEND_METHOD(ion_Writer_Writer, writeTimestamp);
+ZEND_METHOD(ion_Writer_Writer, writeSymbol);
+ZEND_METHOD(ion_Writer_Writer, writeString);
+ZEND_METHOD(ion_Writer_Writer, writeCLob);
+ZEND_METHOD(ion_Writer_Writer, writeBLob);
+ZEND_METHOD(ion_Writer_Writer, startLob);
+ZEND_METHOD(ion_Writer_Writer, appendLob);
+ZEND_METHOD(ion_Writer_Writer, finishLob);
+ZEND_METHOD(ion_Writer_Writer, startContainer);
+ZEND_METHOD(ion_Writer_Writer, finishContainer);
+ZEND_METHOD(ion_Writer_Writer, writeFieldName);
+ZEND_METHOD(ion_Writer_Writer, writeAnnotation);
+ZEND_METHOD(ion_Writer_Writer, getDepth);
+ZEND_METHOD(ion_Writer_Writer, flush);
+ZEND_METHOD(ion_Writer_Writer, finish);
+ZEND_METHOD(ion_Writer_Writer, writeOne);
+ZEND_METHOD(ion_Writer_Writer, writeAll);
+ZEND_METHOD(ion_Writer_Buffer_Writer, __construct);
+ZEND_METHOD(ion_Writer_Buffer_Writer, getBuffer);
+ZEND_METHOD(ion_Writer_Stream_Writer, __construct);
+ZEND_METHOD(ion_Writer_Stream_Writer, getStream);
+ZEND_METHOD(ion_PHP_Serializer, __construct);
+ZEND_METHOD(ion_PHP_Serializer, __invoke);
+ZEND_METHOD(ion_PHP_Serializer, serialize);
+ZEND_METHOD(ion_PHP_Unserializer, __construct);
+ZEND_METHOD(ion_PHP_Unserializer, __invoke);
+ZEND_METHOD(ion_PHP_Unserializer, unserialize);
+
+
+static const zend_function_entry ext_functions[] = {
+       ZEND_NS_RAW_FENTRY("ion", "serialize", ZEND_FN(ion_serialize), arginfo_ion_serialize, 0)
+       ZEND_NS_RAW_FENTRY("ion", "unserialize", ZEND_FN(ion_unserialize), arginfo_ion_unserialize, 0)
+       ZEND_FE_END
+};
+
+
+static const zend_function_entry class_ion_Type_methods[] = {
+       ZEND_FE_END
+};
+
+
+static const zend_function_entry class_ion_Annotation_methods[] = {
+       ZEND_FE_END
+};
+
+
+static const zend_function_entry class_ion_Symbol_ImportLocation_methods[] = {
+       ZEND_ME(ion_Symbol_ImportLocation, __construct, arginfo_class_ion_Symbol_ImportLocation___construct, ZEND_ACC_PUBLIC)
+       ZEND_FE_END
+};
+
+
+static const zend_function_entry class_ion_Symbol_System_methods[] = {
+       ZEND_FE_END
+};
+
+
+static const zend_function_entry class_ion_Symbol_System_SID_methods[] = {
+       ZEND_FE_END
+};
+
+
+static const zend_function_entry class_ion_Symbol_methods[] = {
+       ZEND_ME(ion_Symbol, __construct, arginfo_class_ion_Symbol___construct, ZEND_ACC_PUBLIC)
+       ZEND_ME(ion_Symbol, equals, arginfo_class_ion_Symbol_equals, ZEND_ACC_PUBLIC)
+       ZEND_FE_END
+};
+
+
+static const zend_function_entry class_ion_Symbol_Table_methods[] = {
+       ZEND_FE_END
+};
+
+
+static const zend_function_entry class_ion_Catalog_methods[] = {
+       ZEND_FE_END
+};
+
+
+static const zend_function_entry class_ion_Collection_methods[] = {
+       ZEND_FE_END
+};
+
+
+static const zend_function_entry class_ion_Decimal_methods[] = {
+       ZEND_ME(ion_Decimal, __construct, arginfo_class_ion_Decimal___construct, ZEND_ACC_PUBLIC)
+       ZEND_ME(ion_Decimal, equals, arginfo_class_ion_Decimal_equals, ZEND_ACC_PUBLIC)
+       ZEND_ME(ion_Decimal, zero, arginfo_class_ion_Decimal_zero, ZEND_ACC_PUBLIC)
+       ZEND_ME(ion_Decimal, __toString, arginfo_class_ion_Decimal___toString, ZEND_ACC_PUBLIC)
+       ZEND_MALIAS(ion_Decimal, toString, __toString, arginfo_class_ion_Decimal_toString, ZEND_ACC_PUBLIC)
+       ZEND_ME(ion_Decimal, toInt, arginfo_class_ion_Decimal_toInt, ZEND_ACC_PUBLIC)
+       ZEND_FE_END
+};
+
+
+static const zend_function_entry class_ion_Decimal_Context_methods[] = {
+       ZEND_FE_END
+};
+
+
+static const zend_function_entry class_ion_Timestamp_methods[] = {
+       ZEND_ME(ion_Timestamp, __construct, arginfo_class_ion_Timestamp___construct, ZEND_ACC_PUBLIC)
+       ZEND_ME(ion_Timestamp, __toString, arginfo_class_ion_Timestamp___toString, ZEND_ACC_PUBLIC)
+       ZEND_FE_END
+};
+
+
+static const zend_function_entry class_ion_Reader_methods[] = {
+       ZEND_ABSTRACT_ME_WITH_FLAGS(ion_Reader, getType, arginfo_class_ion_Reader_getType, ZEND_ACC_PUBLIC|ZEND_ACC_ABSTRACT)
+       ZEND_ABSTRACT_ME_WITH_FLAGS(ion_Reader, hasAnnotations, arginfo_class_ion_Reader_hasAnnotations, ZEND_ACC_PUBLIC|ZEND_ACC_ABSTRACT)
+       ZEND_ABSTRACT_ME_WITH_FLAGS(ion_Reader, hasAnnotation, arginfo_class_ion_Reader_hasAnnotation, ZEND_ACC_PUBLIC|ZEND_ACC_ABSTRACT)
+       ZEND_ABSTRACT_ME_WITH_FLAGS(ion_Reader, isNull, arginfo_class_ion_Reader_isNull, ZEND_ACC_PUBLIC|ZEND_ACC_ABSTRACT)
+       ZEND_ABSTRACT_ME_WITH_FLAGS(ion_Reader, isInStruct, arginfo_class_ion_Reader_isInStruct, ZEND_ACC_PUBLIC|ZEND_ACC_ABSTRACT)
+       ZEND_ABSTRACT_ME_WITH_FLAGS(ion_Reader, getFieldName, arginfo_class_ion_Reader_getFieldName, ZEND_ACC_PUBLIC|ZEND_ACC_ABSTRACT)
+       ZEND_ABSTRACT_ME_WITH_FLAGS(ion_Reader, getFieldNameSymbol, arginfo_class_ion_Reader_getFieldNameSymbol, ZEND_ACC_PUBLIC|ZEND_ACC_ABSTRACT)
+       ZEND_ABSTRACT_ME_WITH_FLAGS(ion_Reader, getAnnotations, arginfo_class_ion_Reader_getAnnotations, ZEND_ACC_PUBLIC|ZEND_ACC_ABSTRACT)
+       ZEND_ABSTRACT_ME_WITH_FLAGS(ion_Reader, getAnnotationSymbols, arginfo_class_ion_Reader_getAnnotationSymbols, ZEND_ACC_PUBLIC|ZEND_ACC_ABSTRACT)
+       ZEND_ABSTRACT_ME_WITH_FLAGS(ion_Reader, countAnnotations, arginfo_class_ion_Reader_countAnnotations, ZEND_ACC_PUBLIC|ZEND_ACC_ABSTRACT)
+       ZEND_ABSTRACT_ME_WITH_FLAGS(ion_Reader, getAnnotation, arginfo_class_ion_Reader_getAnnotation, ZEND_ACC_PUBLIC|ZEND_ACC_ABSTRACT)
+       ZEND_ABSTRACT_ME_WITH_FLAGS(ion_Reader, getAnnotationSymbol, arginfo_class_ion_Reader_getAnnotationSymbol, ZEND_ACC_PUBLIC|ZEND_ACC_ABSTRACT)
+       ZEND_ABSTRACT_ME_WITH_FLAGS(ion_Reader, readNull, arginfo_class_ion_Reader_readNull, ZEND_ACC_PUBLIC|ZEND_ACC_ABSTRACT)
+       ZEND_ABSTRACT_ME_WITH_FLAGS(ion_Reader, readBool, arginfo_class_ion_Reader_readBool, ZEND_ACC_PUBLIC|ZEND_ACC_ABSTRACT)
+       ZEND_ABSTRACT_ME_WITH_FLAGS(ion_Reader, readInt, arginfo_class_ion_Reader_readInt, ZEND_ACC_PUBLIC|ZEND_ACC_ABSTRACT)
+       ZEND_ABSTRACT_ME_WITH_FLAGS(ion_Reader, readFloat, arginfo_class_ion_Reader_readFloat, ZEND_ACC_PUBLIC|ZEND_ACC_ABSTRACT)
+       ZEND_ABSTRACT_ME_WITH_FLAGS(ion_Reader, readDecimal, arginfo_class_ion_Reader_readDecimal, ZEND_ACC_PUBLIC|ZEND_ACC_ABSTRACT)
+       ZEND_ABSTRACT_ME_WITH_FLAGS(ion_Reader, readTimestamp, arginfo_class_ion_Reader_readTimestamp, ZEND_ACC_PUBLIC|ZEND_ACC_ABSTRACT)
+       ZEND_ABSTRACT_ME_WITH_FLAGS(ion_Reader, readSymbol, arginfo_class_ion_Reader_readSymbol, ZEND_ACC_PUBLIC|ZEND_ACC_ABSTRACT)
+       ZEND_ABSTRACT_ME_WITH_FLAGS(ion_Reader, readString, arginfo_class_ion_Reader_readString, ZEND_ACC_PUBLIC|ZEND_ACC_ABSTRACT)
+       ZEND_ABSTRACT_ME_WITH_FLAGS(ion_Reader, readStringPart, arginfo_class_ion_Reader_readStringPart, ZEND_ACC_PUBLIC|ZEND_ACC_ABSTRACT)
+       ZEND_ABSTRACT_ME_WITH_FLAGS(ion_Reader, readLob, arginfo_class_ion_Reader_readLob, ZEND_ACC_PUBLIC|ZEND_ACC_ABSTRACT)
+       ZEND_ABSTRACT_ME_WITH_FLAGS(ion_Reader, readLobPart, arginfo_class_ion_Reader_readLobPart, ZEND_ACC_PUBLIC|ZEND_ACC_ABSTRACT)
+       ZEND_ABSTRACT_ME_WITH_FLAGS(ion_Reader, getPosition, arginfo_class_ion_Reader_getPosition, ZEND_ACC_PUBLIC|ZEND_ACC_ABSTRACT)
+       ZEND_ABSTRACT_ME_WITH_FLAGS(ion_Reader, getDepth, arginfo_class_ion_Reader_getDepth, ZEND_ACC_PUBLIC|ZEND_ACC_ABSTRACT)
+       ZEND_ABSTRACT_ME_WITH_FLAGS(ion_Reader, seek, arginfo_class_ion_Reader_seek, ZEND_ACC_PUBLIC|ZEND_ACC_ABSTRACT)
+       ZEND_ABSTRACT_ME_WITH_FLAGS(ion_Reader, getValueOffset, arginfo_class_ion_Reader_getValueOffset, ZEND_ACC_PUBLIC|ZEND_ACC_ABSTRACT)
+       ZEND_ABSTRACT_ME_WITH_FLAGS(ion_Reader, getValueLength, arginfo_class_ion_Reader_getValueLength, ZEND_ACC_PUBLIC|ZEND_ACC_ABSTRACT)
+       ZEND_FE_END
+};
+
+
+static const zend_function_entry class_ion_Reader_Options_methods[] = {
+       ZEND_ME(ion_Reader_Options, __construct, arginfo_class_ion_Reader_Options___construct, ZEND_ACC_PUBLIC)
+       ZEND_FE_END
+};
+
+
+static const zend_function_entry class_ion_Reader_Reader_methods[] = {
+       ZEND_ME(ion_Reader_Reader, hasChildren, arginfo_class_ion_Reader_Reader_hasChildren, ZEND_ACC_PUBLIC)
+       ZEND_ME(ion_Reader_Reader, getChildren, arginfo_class_ion_Reader_Reader_getChildren, ZEND_ACC_PUBLIC)
+       ZEND_ME(ion_Reader_Reader, rewind, arginfo_class_ion_Reader_Reader_rewind, ZEND_ACC_PUBLIC)
+       ZEND_ME(ion_Reader_Reader, next, arginfo_class_ion_Reader_Reader_next, ZEND_ACC_PUBLIC)
+       ZEND_ME(ion_Reader_Reader, valid, arginfo_class_ion_Reader_Reader_valid, ZEND_ACC_PUBLIC)
+       ZEND_ME(ion_Reader_Reader, key, arginfo_class_ion_Reader_Reader_key, ZEND_ACC_PUBLIC)
+       ZEND_ME(ion_Reader_Reader, current, arginfo_class_ion_Reader_Reader_current, ZEND_ACC_PUBLIC)
+       ZEND_ME(ion_Reader_Reader, getType, arginfo_class_ion_Reader_Reader_getType, ZEND_ACC_PUBLIC)
+       ZEND_ME(ion_Reader_Reader, hasAnnotations, arginfo_class_ion_Reader_Reader_hasAnnotations, ZEND_ACC_PUBLIC)
+       ZEND_ME(ion_Reader_Reader, hasAnnotation, arginfo_class_ion_Reader_Reader_hasAnnotation, ZEND_ACC_PUBLIC)
+       ZEND_ME(ion_Reader_Reader, isNull, arginfo_class_ion_Reader_Reader_isNull, ZEND_ACC_PUBLIC)
+       ZEND_ME(ion_Reader_Reader, isInStruct, arginfo_class_ion_Reader_Reader_isInStruct, ZEND_ACC_PUBLIC)
+       ZEND_ME(ion_Reader_Reader, getFieldName, arginfo_class_ion_Reader_Reader_getFieldName, ZEND_ACC_PUBLIC)
+       ZEND_ME(ion_Reader_Reader, getFieldNameSymbol, arginfo_class_ion_Reader_Reader_getFieldNameSymbol, ZEND_ACC_PUBLIC)
+       ZEND_ME(ion_Reader_Reader, getAnnotations, arginfo_class_ion_Reader_Reader_getAnnotations, ZEND_ACC_PUBLIC)
+       ZEND_ME(ion_Reader_Reader, getAnnotationSymbols, arginfo_class_ion_Reader_Reader_getAnnotationSymbols, ZEND_ACC_PUBLIC)
+       ZEND_ME(ion_Reader_Reader, countAnnotations, arginfo_class_ion_Reader_Reader_countAnnotations, ZEND_ACC_PUBLIC)
+       ZEND_ME(ion_Reader_Reader, getAnnotation, arginfo_class_ion_Reader_Reader_getAnnotation, ZEND_ACC_PUBLIC)
+       ZEND_ME(ion_Reader_Reader, getAnnotationSymbol, arginfo_class_ion_Reader_Reader_getAnnotationSymbol, ZEND_ACC_PUBLIC)
+       ZEND_ME(ion_Reader_Reader, readNull, arginfo_class_ion_Reader_Reader_readNull, ZEND_ACC_PUBLIC)
+       ZEND_ME(ion_Reader_Reader, readBool, arginfo_class_ion_Reader_Reader_readBool, ZEND_ACC_PUBLIC)
+       ZEND_ME(ion_Reader_Reader, readInt, arginfo_class_ion_Reader_Reader_readInt, ZEND_ACC_PUBLIC)
+       ZEND_ME(ion_Reader_Reader, readFloat, arginfo_class_ion_Reader_Reader_readFloat, ZEND_ACC_PUBLIC)
+       ZEND_ME(ion_Reader_Reader, readDecimal, arginfo_class_ion_Reader_Reader_readDecimal, ZEND_ACC_PUBLIC)
+       ZEND_ME(ion_Reader_Reader, readTimestamp, arginfo_class_ion_Reader_Reader_readTimestamp, ZEND_ACC_PUBLIC)
+       ZEND_ME(ion_Reader_Reader, readSymbol, arginfo_class_ion_Reader_Reader_readSymbol, ZEND_ACC_PUBLIC)
+       ZEND_ME(ion_Reader_Reader, readString, arginfo_class_ion_Reader_Reader_readString, ZEND_ACC_PUBLIC)
+       ZEND_ME(ion_Reader_Reader, readStringPart, arginfo_class_ion_Reader_Reader_readStringPart, ZEND_ACC_PUBLIC)
+       ZEND_ME(ion_Reader_Reader, readLob, arginfo_class_ion_Reader_Reader_readLob, ZEND_ACC_PUBLIC)
+       ZEND_ME(ion_Reader_Reader, readLobPart, arginfo_class_ion_Reader_Reader_readLobPart, ZEND_ACC_PUBLIC)
+       ZEND_ME(ion_Reader_Reader, getPosition, arginfo_class_ion_Reader_Reader_getPosition, ZEND_ACC_PUBLIC)
+       ZEND_ME(ion_Reader_Reader, getDepth, arginfo_class_ion_Reader_Reader_getDepth, ZEND_ACC_PUBLIC)
+       ZEND_ME(ion_Reader_Reader, seek, arginfo_class_ion_Reader_Reader_seek, ZEND_ACC_PUBLIC)
+       ZEND_ME(ion_Reader_Reader, getValueOffset, arginfo_class_ion_Reader_Reader_getValueOffset, ZEND_ACC_PUBLIC)
+       ZEND_ME(ion_Reader_Reader, getValueLength, arginfo_class_ion_Reader_Reader_getValueLength, ZEND_ACC_PUBLIC)
+       ZEND_FE_END
+};
+
+
+static const zend_function_entry class_ion_Reader_Buffer_methods[] = {
+       ZEND_ABSTRACT_ME_WITH_FLAGS(ion_Reader_Buffer, getBuffer, arginfo_class_ion_Reader_Buffer_getBuffer, ZEND_ACC_PUBLIC|ZEND_ACC_ABSTRACT)
+       ZEND_FE_END
+};
+
+
+static const zend_function_entry class_ion_Reader_Buffer_Reader_methods[] = {
+       ZEND_ME(ion_Reader_Buffer_Reader, __construct, arginfo_class_ion_Reader_Buffer_Reader___construct, ZEND_ACC_PUBLIC)
+       ZEND_ME(ion_Reader_Buffer_Reader, getBuffer, arginfo_class_ion_Reader_Buffer_Reader_getBuffer, ZEND_ACC_PUBLIC)
+       ZEND_FE_END
+};
+
+
+static const zend_function_entry class_ion_Reader_Stream_methods[] = {
+       ZEND_ABSTRACT_ME_WITH_FLAGS(ion_Reader_Stream, getStream, arginfo_class_ion_Reader_Stream_getStream, ZEND_ACC_PUBLIC|ZEND_ACC_ABSTRACT)
+       ZEND_ABSTRACT_ME_WITH_FLAGS(ion_Reader_Stream, resetStream, arginfo_class_ion_Reader_Stream_resetStream, ZEND_ACC_PUBLIC|ZEND_ACC_ABSTRACT)
+       ZEND_ABSTRACT_ME_WITH_FLAGS(ion_Reader_Stream, resetStreamWithLength, arginfo_class_ion_Reader_Stream_resetStreamWithLength, ZEND_ACC_PUBLIC|ZEND_ACC_ABSTRACT)
+       ZEND_FE_END
+};
+
+
+static const zend_function_entry class_ion_Reader_Stream_Reader_methods[] = {
+       ZEND_ME(ion_Reader_Stream_Reader, __construct, arginfo_class_ion_Reader_Stream_Reader___construct, ZEND_ACC_PUBLIC)
+       ZEND_ME(ion_Reader_Stream_Reader, getStream, arginfo_class_ion_Reader_Stream_Reader_getStream, ZEND_ACC_PUBLIC)
+       ZEND_ME(ion_Reader_Stream_Reader, resetStream, arginfo_class_ion_Reader_Stream_Reader_resetStream, ZEND_ACC_PUBLIC)
+       ZEND_ME(ion_Reader_Stream_Reader, resetStreamWithLength, arginfo_class_ion_Reader_Stream_Reader_resetStreamWithLength, ZEND_ACC_PUBLIC)
+       ZEND_FE_END
+};
+
+
+static const zend_function_entry class_ion_Writer_Options_methods[] = {
+       ZEND_ME(ion_Writer_Options, __construct, arginfo_class_ion_Writer_Options___construct, ZEND_ACC_PUBLIC)
+       ZEND_FE_END
+};
+
+
+static const zend_function_entry class_ion_Writer_methods[] = {
+       ZEND_ABSTRACT_ME_WITH_FLAGS(ion_Writer, writeNull, arginfo_class_ion_Writer_writeNull, ZEND_ACC_PUBLIC|ZEND_ACC_ABSTRACT)
+       ZEND_ABSTRACT_ME_WITH_FLAGS(ion_Writer, writeTypedNull, arginfo_class_ion_Writer_writeTypedNull, ZEND_ACC_PUBLIC|ZEND_ACC_ABSTRACT)
+       ZEND_ABSTRACT_ME_WITH_FLAGS(ion_Writer, writeBool, arginfo_class_ion_Writer_writeBool, ZEND_ACC_PUBLIC|ZEND_ACC_ABSTRACT)
+       ZEND_ABSTRACT_ME_WITH_FLAGS(ion_Writer, writeInt, arginfo_class_ion_Writer_writeInt, ZEND_ACC_PUBLIC|ZEND_ACC_ABSTRACT)
+       ZEND_ABSTRACT_ME_WITH_FLAGS(ion_Writer, writeFloat, arginfo_class_ion_Writer_writeFloat, ZEND_ACC_PUBLIC|ZEND_ACC_ABSTRACT)
+       ZEND_ABSTRACT_ME_WITH_FLAGS(ion_Writer, writeDecimal, arginfo_class_ion_Writer_writeDecimal, ZEND_ACC_PUBLIC|ZEND_ACC_ABSTRACT)
+       ZEND_ABSTRACT_ME_WITH_FLAGS(ion_Writer, writeTimestamp, arginfo_class_ion_Writer_writeTimestamp, ZEND_ACC_PUBLIC|ZEND_ACC_ABSTRACT)
+       ZEND_ABSTRACT_ME_WITH_FLAGS(ion_Writer, writeSymbol, arginfo_class_ion_Writer_writeSymbol, ZEND_ACC_PUBLIC|ZEND_ACC_ABSTRACT)
+       ZEND_ABSTRACT_ME_WITH_FLAGS(ion_Writer, writeString, arginfo_class_ion_Writer_writeString, ZEND_ACC_PUBLIC|ZEND_ACC_ABSTRACT)
+       ZEND_ABSTRACT_ME_WITH_FLAGS(ion_Writer, writeCLob, arginfo_class_ion_Writer_writeCLob, ZEND_ACC_PUBLIC|ZEND_ACC_ABSTRACT)
+       ZEND_ABSTRACT_ME_WITH_FLAGS(ion_Writer, writeBLob, arginfo_class_ion_Writer_writeBLob, ZEND_ACC_PUBLIC|ZEND_ACC_ABSTRACT)
+       ZEND_ABSTRACT_ME_WITH_FLAGS(ion_Writer, startLob, arginfo_class_ion_Writer_startLob, ZEND_ACC_PUBLIC|ZEND_ACC_ABSTRACT)
+       ZEND_ABSTRACT_ME_WITH_FLAGS(ion_Writer, appendLob, arginfo_class_ion_Writer_appendLob, ZEND_ACC_PUBLIC|ZEND_ACC_ABSTRACT)
+       ZEND_ABSTRACT_ME_WITH_FLAGS(ion_Writer, finishLob, arginfo_class_ion_Writer_finishLob, ZEND_ACC_PUBLIC|ZEND_ACC_ABSTRACT)
+       ZEND_ABSTRACT_ME_WITH_FLAGS(ion_Writer, startContainer, arginfo_class_ion_Writer_startContainer, ZEND_ACC_PUBLIC|ZEND_ACC_ABSTRACT)
+       ZEND_ABSTRACT_ME_WITH_FLAGS(ion_Writer, finishContainer, arginfo_class_ion_Writer_finishContainer, ZEND_ACC_PUBLIC|ZEND_ACC_ABSTRACT)
+       ZEND_ABSTRACT_ME_WITH_FLAGS(ion_Writer, writeFieldName, arginfo_class_ion_Writer_writeFieldName, ZEND_ACC_PUBLIC|ZEND_ACC_ABSTRACT)
+       ZEND_ABSTRACT_ME_WITH_FLAGS(ion_Writer, writeAnnotation, arginfo_class_ion_Writer_writeAnnotation, ZEND_ACC_PUBLIC|ZEND_ACC_ABSTRACT)
+       ZEND_ABSTRACT_ME_WITH_FLAGS(ion_Writer, getDepth, arginfo_class_ion_Writer_getDepth, ZEND_ACC_PUBLIC|ZEND_ACC_ABSTRACT)
+       ZEND_ABSTRACT_ME_WITH_FLAGS(ion_Writer, flush, arginfo_class_ion_Writer_flush, ZEND_ACC_PUBLIC|ZEND_ACC_ABSTRACT)
+       ZEND_ABSTRACT_ME_WITH_FLAGS(ion_Writer, finish, arginfo_class_ion_Writer_finish, ZEND_ACC_PUBLIC|ZEND_ACC_ABSTRACT)
+       ZEND_ABSTRACT_ME_WITH_FLAGS(ion_Writer, writeOne, arginfo_class_ion_Writer_writeOne, ZEND_ACC_PUBLIC|ZEND_ACC_ABSTRACT)
+       ZEND_ABSTRACT_ME_WITH_FLAGS(ion_Writer, writeAll, arginfo_class_ion_Writer_writeAll, ZEND_ACC_PUBLIC|ZEND_ACC_ABSTRACT)
+       ZEND_FE_END
+};
+
+
+static const zend_function_entry class_ion_Writer_Writer_methods[] = {
+       ZEND_ME(ion_Writer_Writer, writeNull, arginfo_class_ion_Writer_Writer_writeNull, ZEND_ACC_PUBLIC)
+       ZEND_ME(ion_Writer_Writer, writeTypedNull, arginfo_class_ion_Writer_Writer_writeTypedNull, ZEND_ACC_PUBLIC)
+       ZEND_ME(ion_Writer_Writer, writeBool, arginfo_class_ion_Writer_Writer_writeBool, ZEND_ACC_PUBLIC)
+       ZEND_ME(ion_Writer_Writer, writeInt, arginfo_class_ion_Writer_Writer_writeInt, ZEND_ACC_PUBLIC)
+       ZEND_ME(ion_Writer_Writer, writeFloat, arginfo_class_ion_Writer_Writer_writeFloat, ZEND_ACC_PUBLIC)
+       ZEND_ME(ion_Writer_Writer, writeDecimal, arginfo_class_ion_Writer_Writer_writeDecimal, ZEND_ACC_PUBLIC)
+       ZEND_ME(ion_Writer_Writer, writeTimestamp, arginfo_class_ion_Writer_Writer_writeTimestamp, ZEND_ACC_PUBLIC)
+       ZEND_ME(ion_Writer_Writer, writeSymbol, arginfo_class_ion_Writer_Writer_writeSymbol, ZEND_ACC_PUBLIC)
+       ZEND_ME(ion_Writer_Writer, writeString, arginfo_class_ion_Writer_Writer_writeString, ZEND_ACC_PUBLIC)
+       ZEND_ME(ion_Writer_Writer, writeCLob, arginfo_class_ion_Writer_Writer_writeCLob, ZEND_ACC_PUBLIC)
+       ZEND_ME(ion_Writer_Writer, writeBLob, arginfo_class_ion_Writer_Writer_writeBLob, ZEND_ACC_PUBLIC)
+       ZEND_ME(ion_Writer_Writer, startLob, arginfo_class_ion_Writer_Writer_startLob, ZEND_ACC_PUBLIC)
+       ZEND_ME(ion_Writer_Writer, appendLob, arginfo_class_ion_Writer_Writer_appendLob, ZEND_ACC_PUBLIC)
+       ZEND_ME(ion_Writer_Writer, finishLob, arginfo_class_ion_Writer_Writer_finishLob, ZEND_ACC_PUBLIC)
+       ZEND_ME(ion_Writer_Writer, startContainer, arginfo_class_ion_Writer_Writer_startContainer, ZEND_ACC_PUBLIC)
+       ZEND_ME(ion_Writer_Writer, finishContainer, arginfo_class_ion_Writer_Writer_finishContainer, ZEND_ACC_PUBLIC)
+       ZEND_ME(ion_Writer_Writer, writeFieldName, arginfo_class_ion_Writer_Writer_writeFieldName, ZEND_ACC_PUBLIC)
+       ZEND_ME(ion_Writer_Writer, writeAnnotation, arginfo_class_ion_Writer_Writer_writeAnnotation, ZEND_ACC_PUBLIC)
+       ZEND_ME(ion_Writer_Writer, getDepth, arginfo_class_ion_Writer_Writer_getDepth, ZEND_ACC_PUBLIC)
+       ZEND_ME(ion_Writer_Writer, flush, arginfo_class_ion_Writer_Writer_flush, ZEND_ACC_PUBLIC)
+       ZEND_ME(ion_Writer_Writer, finish, arginfo_class_ion_Writer_Writer_finish, ZEND_ACC_PUBLIC)
+       ZEND_ME(ion_Writer_Writer, writeOne, arginfo_class_ion_Writer_Writer_writeOne, ZEND_ACC_PUBLIC)
+       ZEND_ME(ion_Writer_Writer, writeAll, arginfo_class_ion_Writer_Writer_writeAll, ZEND_ACC_PUBLIC)
+       ZEND_FE_END
+};
+
+
+static const zend_function_entry class_ion_Writer_Buffer_methods[] = {
+       ZEND_ABSTRACT_ME_WITH_FLAGS(ion_Writer_Buffer, getBuffer, arginfo_class_ion_Writer_Buffer_getBuffer, ZEND_ACC_PUBLIC|ZEND_ACC_ABSTRACT)
+       ZEND_FE_END
+};
+
+
+static const zend_function_entry class_ion_Writer_Buffer_Writer_methods[] = {
+       ZEND_ME(ion_Writer_Buffer_Writer, __construct, arginfo_class_ion_Writer_Buffer_Writer___construct, ZEND_ACC_PUBLIC)
+       ZEND_ME(ion_Writer_Buffer_Writer, getBuffer, arginfo_class_ion_Writer_Buffer_Writer_getBuffer, ZEND_ACC_PUBLIC)
+       ZEND_FE_END
+};
+
+
+static const zend_function_entry class_ion_Writer_Stream_methods[] = {
+       ZEND_ABSTRACT_ME_WITH_FLAGS(ion_Writer_Stream, getStream, arginfo_class_ion_Writer_Stream_getStream, ZEND_ACC_PUBLIC|ZEND_ACC_ABSTRACT)
+       ZEND_FE_END
+};
+
+
+static const zend_function_entry class_ion_Writer_Stream_Writer_methods[] = {
+       ZEND_ME(ion_Writer_Stream_Writer, __construct, arginfo_class_ion_Writer_Stream_Writer___construct, ZEND_ACC_PUBLIC)
+       ZEND_ME(ion_Writer_Stream_Writer, getStream, arginfo_class_ion_Writer_Stream_Writer_getStream, ZEND_ACC_PUBLIC)
+       ZEND_FE_END
+};
+
+
+static const zend_function_entry class_ion_PHP_Serializer_methods[] = {
+       ZEND_ME(ion_PHP_Serializer, __construct, arginfo_class_ion_PHP_Serializer___construct, ZEND_ACC_PUBLIC)
+       ZEND_ME(ion_PHP_Serializer, __invoke, arginfo_class_ion_PHP_Serializer___invoke, ZEND_ACC_PUBLIC)
+       ZEND_ME(ion_PHP_Serializer, serialize, arginfo_class_ion_PHP_Serializer_serialize, ZEND_ACC_PROTECTED)
+       ZEND_FE_END
+};
+
+
+static const zend_function_entry class_ion_PHP_Unserializer_methods[] = {
+       ZEND_ME(ion_PHP_Unserializer, __construct, arginfo_class_ion_PHP_Unserializer___construct, ZEND_ACC_PUBLIC)
+       ZEND_ME(ion_PHP_Unserializer, __invoke, arginfo_class_ion_PHP_Unserializer___invoke, ZEND_ACC_PUBLIC)
+       ZEND_ME(ion_PHP_Unserializer, unserialize, arginfo_class_ion_PHP_Unserializer_unserialize, ZEND_ACC_PROTECTED)
+       ZEND_FE_END
+};
+
+static zend_class_entry *register_class_ion_Type(void)
+{
+       zend_class_entry *class_entry = zend_register_internal_enum("ion\\Type", IS_LONG, class_ion_Type_methods);
+
+       zval enum_case_Null_value;
+       ZVAL_LONG(&enum_case_Null_value, 0);
+       zend_enum_add_case_cstr(class_entry, "Null", &enum_case_Null_value);
+
+       zval enum_case_Bool_value;
+       ZVAL_LONG(&enum_case_Bool_value, 256);
+       zend_enum_add_case_cstr(class_entry, "Bool", &enum_case_Bool_value);
+
+       zval enum_case_Int_value;
+       ZVAL_LONG(&enum_case_Int_value, 512);
+       zend_enum_add_case_cstr(class_entry, "Int", &enum_case_Int_value);
+
+       zval enum_case_Float_value;
+       ZVAL_LONG(&enum_case_Float_value, 1024);
+       zend_enum_add_case_cstr(class_entry, "Float", &enum_case_Float_value);
+
+       zval enum_case_Decimal_value;
+       ZVAL_LONG(&enum_case_Decimal_value, 1280);
+       zend_enum_add_case_cstr(class_entry, "Decimal", &enum_case_Decimal_value);
+
+       zval enum_case_Timestamp_value;
+       ZVAL_LONG(&enum_case_Timestamp_value, 1536);
+       zend_enum_add_case_cstr(class_entry, "Timestamp", &enum_case_Timestamp_value);
+
+       zval enum_case_Symbol_value;
+       ZVAL_LONG(&enum_case_Symbol_value, 1792);
+       zend_enum_add_case_cstr(class_entry, "Symbol", &enum_case_Symbol_value);
+
+       zval enum_case_String_value;
+       ZVAL_LONG(&enum_case_String_value, 2048);
+       zend_enum_add_case_cstr(class_entry, "String", &enum_case_String_value);
+
+       zval enum_case_CLob_value;
+       ZVAL_LONG(&enum_case_CLob_value, 2304);
+       zend_enum_add_case_cstr(class_entry, "CLob", &enum_case_CLob_value);
+
+       zval enum_case_BLob_value;
+       ZVAL_LONG(&enum_case_BLob_value, 2560);
+       zend_enum_add_case_cstr(class_entry, "BLob", &enum_case_BLob_value);
+
+       zval enum_case_AList_value;
+       ZVAL_LONG(&enum_case_AList_value, 2816);
+       zend_enum_add_case_cstr(class_entry, "AList", &enum_case_AList_value);
+
+       zval enum_case_SExp_value;
+       ZVAL_LONG(&enum_case_SExp_value, 3072);
+       zend_enum_add_case_cstr(class_entry, "SExp", &enum_case_SExp_value);
+
+       zval enum_case_Struct_value;
+       ZVAL_LONG(&enum_case_Struct_value, 3328);
+       zend_enum_add_case_cstr(class_entry, "Struct", &enum_case_Struct_value);
+
+       zval enum_case_Datagram_value;
+       ZVAL_LONG(&enum_case_Datagram_value, 3840);
+       zend_enum_add_case_cstr(class_entry, "Datagram", &enum_case_Datagram_value);
+
+       zval enum_case_EOF_value;
+       ZVAL_LONG(&enum_case_EOF_value, -256);
+       zend_enum_add_case_cstr(class_entry, "EOF", &enum_case_EOF_value);
+
+       zval enum_case_NONE_value;
+       ZVAL_LONG(&enum_case_NONE_value, -512);
+       zend_enum_add_case_cstr(class_entry, "NONE", &enum_case_NONE_value);
+
+       return class_entry;
+}
+
+static zend_class_entry *register_class_ion_Annotation(void)
+{
+       zend_class_entry *class_entry = zend_register_internal_enum("ion\\Annotation", IS_STRING, class_ion_Annotation_methods);
+
+       zval enum_case_PHP_value;
+       zend_string *enum_case_PHP_value_str = zend_string_init("PHP", sizeof("PHP") - 1, 1);
+       ZVAL_STR(&enum_case_PHP_value, enum_case_PHP_value_str);
+       zend_enum_add_case_cstr(class_entry, "PHP", &enum_case_PHP_value);
+
+       zval enum_case_REFERENCE_value;
+       zend_string *enum_case_REFERENCE_value_str = zend_string_init("R", sizeof("R") - 1, 1);
+       ZVAL_STR(&enum_case_REFERENCE_value, enum_case_REFERENCE_value_str);
+       zend_enum_add_case_cstr(class_entry, "REFERENCE", &enum_case_REFERENCE_value);
+
+       zval enum_case_BACKREF_value;
+       zend_string *enum_case_BACKREF_value_str = zend_string_init("r", sizeof("r") - 1, 1);
+       ZVAL_STR(&enum_case_BACKREF_value, enum_case_BACKREF_value_str);
+       zend_enum_add_case_cstr(class_entry, "BACKREF", &enum_case_BACKREF_value);
+
+       zval enum_case_OBJECT_value;
+       zend_string *enum_case_OBJECT_value_str = zend_string_init("o", sizeof("o") - 1, 1);
+       ZVAL_STR(&enum_case_OBJECT_value, enum_case_OBJECT_value_str);
+       zend_enum_add_case_cstr(class_entry, "OBJECT", &enum_case_OBJECT_value);
+
+       zval enum_case_MAGIC_OBJ_value;
+       zend_string *enum_case_MAGIC_OBJ_value_str = zend_string_init("O", sizeof("O") - 1, 1);
+       ZVAL_STR(&enum_case_MAGIC_OBJ_value, enum_case_MAGIC_OBJ_value_str);
+       zend_enum_add_case_cstr(class_entry, "MAGIC_OBJ", &enum_case_MAGIC_OBJ_value);
+
+       zval enum_case_CUSTOM_OBJ_value;
+       zend_string *enum_case_CUSTOM_OBJ_value_str = zend_string_init("C", sizeof("C") - 1, 1);
+       ZVAL_STR(&enum_case_CUSTOM_OBJ_value, enum_case_CUSTOM_OBJ_value_str);
+       zend_enum_add_case_cstr(class_entry, "CUSTOM_OBJ", &enum_case_CUSTOM_OBJ_value);
+
+       zval enum_case_SERIALIZABLE_value;
+       zend_string *enum_case_SERIALIZABLE_value_str = zend_string_init("S", sizeof("S") - 1, 1);
+       ZVAL_STR(&enum_case_SERIALIZABLE_value, enum_case_SERIALIZABLE_value_str);
+       zend_enum_add_case_cstr(class_entry, "SERIALIZABLE", &enum_case_SERIALIZABLE_value);
+
+       zval enum_case_ENUM_value;
+       zend_string *enum_case_ENUM_value_str = zend_string_init("E", sizeof("E") - 1, 1);
+       ZVAL_STR(&enum_case_ENUM_value, enum_case_ENUM_value_str);
+       zend_enum_add_case_cstr(class_entry, "ENUM", &enum_case_ENUM_value);
+
+       zval enum_case_FIELD_NAME_INT_value;
+       zend_string *enum_case_FIELD_NAME_INT_value_str = zend_string_init("i", sizeof("i") - 1, 1);
+       ZVAL_STR(&enum_case_FIELD_NAME_INT_value, enum_case_FIELD_NAME_INT_value_str);
+       zend_enum_add_case_cstr(class_entry, "FIELD_NAME_INT", &enum_case_FIELD_NAME_INT_value);
+
+       return class_entry;
+}
+
+static zend_class_entry *register_class_ion_Symbol_ImportLocation(void)
+{
+       zend_class_entry ce, *class_entry;
+
+       INIT_NS_CLASS_ENTRY(ce, "ion\\Symbol", "ImportLocation", class_ion_Symbol_ImportLocation_methods);
+       class_entry = zend_register_internal_class_ex(&ce, NULL);
+
+       zval property_name_default_value;
+       ZVAL_UNDEF(&property_name_default_value);
+       zend_string *property_name_name = zend_string_init("name", sizeof("name") - 1, 1);
+       zend_declare_typed_property(class_entry, property_name_name, &property_name_default_value, ZEND_ACC_PUBLIC|ZEND_ACC_READONLY, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_STRING));
+       zend_string_release(property_name_name);
+
+       zval property_location_default_value;
+       ZVAL_UNDEF(&property_location_default_value);
+       zend_string *property_location_name = zend_string_init("location", sizeof("location") - 1, 1);
+       zend_declare_typed_property(class_entry, property_location_name, &property_location_default_value, ZEND_ACC_PUBLIC|ZEND_ACC_READONLY, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG));
+       zend_string_release(property_location_name);
+
+       return class_entry;
+}
+
+static zend_class_entry *register_class_ion_Symbol_System(void)
+{
+       zend_class_entry *class_entry = zend_register_internal_enum("ion\\Symbol\\System", IS_STRING, class_ion_Symbol_System_methods);
+
+       zval enum_case_Ion_value;
+       zend_string *enum_case_Ion_value_str = zend_string_init("$ion", sizeof("$ion") - 1, 1);
+       ZVAL_STR(&enum_case_Ion_value, enum_case_Ion_value_str);
+       zend_enum_add_case_cstr(class_entry, "Ion", &enum_case_Ion_value);
+
+       zval enum_case_Ivm_1_0_value;
+       zend_string *enum_case_Ivm_1_0_value_str = zend_string_init("$ion_1_0", sizeof("$ion_1_0") - 1, 1);
+       ZVAL_STR(&enum_case_Ivm_1_0_value, enum_case_Ivm_1_0_value_str);
+       zend_enum_add_case_cstr(class_entry, "Ivm_1_0", &enum_case_Ivm_1_0_value);
+
+       zval enum_case_IonSymbolTable_value;
+       zend_string *enum_case_IonSymbolTable_value_str = zend_string_init("$ion_symbol_table", sizeof("$ion_symbol_table") - 1, 1);
+       ZVAL_STR(&enum_case_IonSymbolTable_value, enum_case_IonSymbolTable_value_str);
+       zend_enum_add_case_cstr(class_entry, "IonSymbolTable", &enum_case_IonSymbolTable_value);
+
+       zval enum_case_Name_value;
+       zend_string *enum_case_Name_value_str = zend_string_init("name", sizeof("name") - 1, 1);
+       ZVAL_STR(&enum_case_Name_value, enum_case_Name_value_str);
+       zend_enum_add_case_cstr(class_entry, "Name", &enum_case_Name_value);
+
+       zval enum_case_Version_value;
+       zend_string *enum_case_Version_value_str = zend_string_init("version", sizeof("version") - 1, 1);
+       ZVAL_STR(&enum_case_Version_value, enum_case_Version_value_str);
+       zend_enum_add_case_cstr(class_entry, "Version", &enum_case_Version_value);
+
+       zval enum_case_Imports_value;
+       zend_string *enum_case_Imports_value_str = zend_string_init("imports", sizeof("imports") - 1, 1);
+       ZVAL_STR(&enum_case_Imports_value, enum_case_Imports_value_str);
+       zend_enum_add_case_cstr(class_entry, "Imports", &enum_case_Imports_value);
+
+       zval enum_case_Symbols_value;
+       zend_string *enum_case_Symbols_value_str = zend_string_init("symbols", sizeof("symbols") - 1, 1);
+       ZVAL_STR(&enum_case_Symbols_value, enum_case_Symbols_value_str);
+       zend_enum_add_case_cstr(class_entry, "Symbols", &enum_case_Symbols_value);
+
+       zval enum_case_MaxId_value;
+       zend_string *enum_case_MaxId_value_str = zend_string_init("max_id", sizeof("max_id") - 1, 1);
+       ZVAL_STR(&enum_case_MaxId_value, enum_case_MaxId_value_str);
+       zend_enum_add_case_cstr(class_entry, "MaxId", &enum_case_MaxId_value);
+
+       zval enum_case_SharedSymbolTable_value;
+       zend_string *enum_case_SharedSymbolTable_value_str = zend_string_init("$ion_shared_symbol_table", sizeof("$ion_shared_symbol_table") - 1, 1);
+       ZVAL_STR(&enum_case_SharedSymbolTable_value, enum_case_SharedSymbolTable_value_str);
+       zend_enum_add_case_cstr(class_entry, "SharedSymbolTable", &enum_case_SharedSymbolTable_value);
+
+       return class_entry;
+}
+
+static zend_class_entry *register_class_ion_Symbol_System_SID(void)
+{
+       zend_class_entry *class_entry = zend_register_internal_enum("ion\\Symbol\\System\\SID", IS_LONG, class_ion_Symbol_System_SID_methods);
+
+       zval enum_case_Ion_value;
+       ZVAL_LONG(&enum_case_Ion_value, 1);
+       zend_enum_add_case_cstr(class_entry, "Ion", &enum_case_Ion_value);
+
+       zval enum_case_Ivm_1_0_value;
+       ZVAL_LONG(&enum_case_Ivm_1_0_value, 2);
+       zend_enum_add_case_cstr(class_entry, "Ivm_1_0", &enum_case_Ivm_1_0_value);
+
+       zval enum_case_IonSymbolTable_value;
+       ZVAL_LONG(&enum_case_IonSymbolTable_value, 3);
+       zend_enum_add_case_cstr(class_entry, "IonSymbolTable", &enum_case_IonSymbolTable_value);
+
+       zval enum_case_Name_value;
+       ZVAL_LONG(&enum_case_Name_value, 4);
+       zend_enum_add_case_cstr(class_entry, "Name", &enum_case_Name_value);
+
+       zval enum_case_Version_value;
+       ZVAL_LONG(&enum_case_Version_value, 5);
+       zend_enum_add_case_cstr(class_entry, "Version", &enum_case_Version_value);
+
+       zval enum_case_Imports_value;
+       ZVAL_LONG(&enum_case_Imports_value, 6);
+       zend_enum_add_case_cstr(class_entry, "Imports", &enum_case_Imports_value);
+
+       zval enum_case_Symbols_value;
+       ZVAL_LONG(&enum_case_Symbols_value, 7);
+       zend_enum_add_case_cstr(class_entry, "Symbols", &enum_case_Symbols_value);
+
+       zval enum_case_MaxId_value;
+       ZVAL_LONG(&enum_case_MaxId_value, 8);
+       zend_enum_add_case_cstr(class_entry, "MaxId", &enum_case_MaxId_value);
+
+       zval enum_case_SharedSymbolTable_value;
+       ZVAL_LONG(&enum_case_SharedSymbolTable_value, 9);
+       zend_enum_add_case_cstr(class_entry, "SharedSymbolTable", &enum_case_SharedSymbolTable_value);
+
+       return class_entry;
+}
+
+static zend_class_entry *register_class_ion_Symbol(void)
+{
+       zend_class_entry ce, *class_entry;
+
+       INIT_NS_CLASS_ENTRY(ce, "ion", "Symbol", class_ion_Symbol_methods);
+       class_entry = zend_register_internal_class_ex(&ce, NULL);
+
+       zval property_value_default_value;
+       ZVAL_UNDEF(&property_value_default_value);
+       zend_string *property_value_name = zend_string_init("value", sizeof("value") - 1, 1);
+       zend_declare_typed_property(class_entry, property_value_name, &property_value_default_value, ZEND_ACC_PUBLIC|ZEND_ACC_READONLY, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_STRING));
+       zend_string_release(property_value_name);
+
+       zval property_sid_default_value;
+       ZVAL_UNDEF(&property_sid_default_value);
+       zend_string *property_sid_name = zend_string_init("sid", sizeof("sid") - 1, 1);
+       zend_declare_typed_property(class_entry, property_sid_name, &property_sid_default_value, ZEND_ACC_PUBLIC|ZEND_ACC_READONLY, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG));
+       zend_string_release(property_sid_name);
+
+       zend_string *property_importLocation_class_ion_Symbol_ImportLocation = zend_string_init("ion\\Symbol\\ImportLocation", sizeof("ion\\Symbol\\ImportLocation")-1, 1);
+       zval property_importLocation_default_value;
+       ZVAL_UNDEF(&property_importLocation_default_value);
+       zend_string *property_importLocation_name = zend_string_init("importLocation", sizeof("importLocation") - 1, 1);
+       zend_declare_typed_property(class_entry, property_importLocation_name, &property_importLocation_default_value, ZEND_ACC_PUBLIC|ZEND_ACC_READONLY, NULL, (zend_type) ZEND_TYPE_INIT_CLASS(property_importLocation_class_ion_Symbol_ImportLocation, 0, MAY_BE_NULL));
+       zend_string_release(property_importLocation_name);
+
+       return class_entry;
+}
+
+static zend_class_entry *register_class_ion_Symbol_Table(void)
+{
+       zend_class_entry ce, *class_entry;
+
+       INIT_NS_CLASS_ENTRY(ce, "ion\\Symbol", "Table", class_ion_Symbol_Table_methods);
+       class_entry = zend_register_internal_class_ex(&ce, NULL);
+
+       return class_entry;
+}
+
+static zend_class_entry *register_class_ion_Catalog(void)
+{
+       zend_class_entry ce, *class_entry;
+
+       INIT_NS_CLASS_ENTRY(ce, "ion", "Catalog", class_ion_Catalog_methods);
+       class_entry = zend_register_internal_class_ex(&ce, NULL);
+
+       return class_entry;
+}
+
+static zend_class_entry *register_class_ion_Collection(void)
+{
+       zend_class_entry ce, *class_entry;
+
+       INIT_NS_CLASS_ENTRY(ce, "ion", "Collection", class_ion_Collection_methods);
+       class_entry = zend_register_internal_class_ex(&ce, NULL);
+
+       return class_entry;
+}
+
+static zend_class_entry *register_class_ion_Decimal(void)
+{
+       zend_class_entry ce, *class_entry;
+
+       INIT_NS_CLASS_ENTRY(ce, "ion", "Decimal", class_ion_Decimal_methods);
+       class_entry = zend_register_internal_class_ex(&ce, NULL);
+
+       zend_string *property_context_class_ion_Decimal_Context = zend_string_init("ion\\Decimal\\Context", sizeof("ion\\Decimal\\Context")-1, 1);
+       zval property_context_default_value;
+       ZVAL_UNDEF(&property_context_default_value);
+       zend_string *property_context_name = zend_string_init("context", sizeof("context") - 1, 1);
+       zend_declare_typed_property(class_entry, property_context_name, &property_context_default_value, ZEND_ACC_PUBLIC|ZEND_ACC_READONLY, NULL, (zend_type) ZEND_TYPE_INIT_CLASS(property_context_class_ion_Decimal_Context, 0, MAY_BE_NULL));
+       zend_string_release(property_context_name);
+
+       return class_entry;
+}
+
+static zend_class_entry *register_class_ion_Decimal_Context(void)
+{
+       zend_class_entry ce, *class_entry;
+
+       INIT_NS_CLASS_ENTRY(ce, "ion\\Decimal", "Context", class_ion_Decimal_Context_methods);
+       class_entry = zend_register_internal_class_ex(&ce, NULL);
+
+       return class_entry;
+}
+
+static zend_class_entry *register_class_ion_Timestamp(zend_class_entry *class_entry_DateTime)
+{
+       zend_class_entry ce, *class_entry;
+
+       INIT_NS_CLASS_ENTRY(ce, "ion", "Timestamp", class_ion_Timestamp_methods);
+       class_entry = zend_register_internal_class_ex(&ce, class_entry_DateTime);
+
+       zval property_precision_default_value;
+       ZVAL_UNDEF(&property_precision_default_value);
+       zend_string *property_precision_name = zend_string_init("precision", sizeof("precision") - 1, 1);
+       zend_declare_typed_property(class_entry, property_precision_name, &property_precision_default_value, ZEND_ACC_PUBLIC|ZEND_ACC_READONLY, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG));
+       zend_string_release(property_precision_name);
+
+       zval property_format_default_value;
+       ZVAL_UNDEF(&property_format_default_value);
+       zend_string *property_format_name = zend_string_init("format", sizeof("format") - 1, 1);
+       zend_declare_typed_property(class_entry, property_format_name, &property_format_default_value, ZEND_ACC_PUBLIC|ZEND_ACC_READONLY, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_STRING));
+       zend_string_release(property_format_name);
+
+       return class_entry;
+}
+
+static zend_class_entry *register_class_ion_Reader(zend_class_entry *class_entry_RecursiveIterator)
+{
+       zend_class_entry ce, *class_entry;
+
+       INIT_NS_CLASS_ENTRY(ce, "ion", "Reader", class_ion_Reader_methods);
+       class_entry = zend_register_internal_interface(&ce);
+       zend_class_implements(class_entry, 1, class_entry_RecursiveIterator);
+
+       return class_entry;
+}
+
+static zend_class_entry *register_class_ion_Reader_Options(void)
+{
+       zend_class_entry ce, *class_entry;
+
+       INIT_NS_CLASS_ENTRY(ce, "ion\\Reader", "Options", class_ion_Reader_Options_methods);
+       class_entry = zend_register_internal_class_ex(&ce, NULL);
+
+       zend_string *property_catalog_class_ion_Catalog = zend_string_init("ion\\Catalog", sizeof("ion\\Catalog")-1, 1);
+       zval property_catalog_default_value;
+       ZVAL_UNDEF(&property_catalog_default_value);
+       zend_string *property_catalog_name = zend_string_init("catalog", sizeof("catalog") - 1, 1);
+       zend_declare_typed_property(class_entry, property_catalog_name, &property_catalog_default_value, ZEND_ACC_PUBLIC|ZEND_ACC_READONLY, NULL, (zend_type) ZEND_TYPE_INIT_CLASS(property_catalog_class_ion_Catalog, 0, MAY_BE_NULL));
+       zend_string_release(property_catalog_name);
+
+       zend_string *property_decimalContext_class_ion_Decimal_Context = zend_string_init("ion\\Decimal\\Context", sizeof("ion\\Decimal\\Context")-1, 1);
+       zval property_decimalContext_default_value;
+       ZVAL_UNDEF(&property_decimalContext_default_value);
+       zend_string *property_decimalContext_name = zend_string_init("decimalContext", sizeof("decimalContext") - 1, 1);
+       zend_declare_typed_property(class_entry, property_decimalContext_name, &property_decimalContext_default_value, ZEND_ACC_PUBLIC|ZEND_ACC_READONLY, NULL, (zend_type) ZEND_TYPE_INIT_CLASS(property_decimalContext_class_ion_Decimal_Context, 0, MAY_BE_NULL));
+       zend_string_release(property_decimalContext_name);
+
+       zend_string *property_onContextChange_class_Closure = zend_string_init("Closure", sizeof("Closure")-1, 1);
+       zval property_onContextChange_default_value;
+       ZVAL_UNDEF(&property_onContextChange_default_value);
+       zend_string *property_onContextChange_name = zend_string_init("onContextChange", sizeof("onContextChange") - 1, 1);
+       zend_declare_typed_property(class_entry, property_onContextChange_name, &property_onContextChange_default_value, ZEND_ACC_PUBLIC|ZEND_ACC_READONLY, NULL, (zend_type) ZEND_TYPE_INIT_CLASS(property_onContextChange_class_Closure, 0, MAY_BE_NULL));
+       zend_string_release(property_onContextChange_name);
+
+       zval property_returnSystemValues_default_value;
+       ZVAL_UNDEF(&property_returnSystemValues_default_value);
+       zend_string *property_returnSystemValues_name = zend_string_init("returnSystemValues", sizeof("returnSystemValues") - 1, 1);
+       zend_declare_typed_property(class_entry, property_returnSystemValues_name, &property_returnSystemValues_default_value, ZEND_ACC_PUBLIC|ZEND_ACC_READONLY, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_BOOL));
+       zend_string_release(property_returnSystemValues_name);
+
+       zval property_newLine_default_value;
+       ZVAL_UNDEF(&property_newLine_default_value);
+       zend_string *property_newLine_name = zend_string_init("newLine", sizeof("newLine") - 1, 1);
+       zend_declare_typed_property(class_entry, property_newLine_name, &property_newLine_default_value, ZEND_ACC_PUBLIC|ZEND_ACC_READONLY, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG));
+       zend_string_release(property_newLine_name);
+
+       zval property_maxContainerDepth_default_value;
+       ZVAL_UNDEF(&property_maxContainerDepth_default_value);
+       zend_string *property_maxContainerDepth_name = zend_string_init("maxContainerDepth", sizeof("maxContainerDepth") - 1, 1);
+       zend_declare_typed_property(class_entry, property_maxContainerDepth_name, &property_maxContainerDepth_default_value, ZEND_ACC_PUBLIC|ZEND_ACC_READONLY, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG));
+       zend_string_release(property_maxContainerDepth_name);
+
+       zval property_maxAnnotations_default_value;
+       ZVAL_UNDEF(&property_maxAnnotations_default_value);
+       zend_string *property_maxAnnotations_name = zend_string_init("maxAnnotations", sizeof("maxAnnotations") - 1, 1);
+       zend_declare_typed_property(class_entry, property_maxAnnotations_name, &property_maxAnnotations_default_value, ZEND_ACC_PUBLIC|ZEND_ACC_READONLY, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG));
+       zend_string_release(property_maxAnnotations_name);
+
+       zval property_maxAnnotationBuffered_default_value;
+       ZVAL_UNDEF(&property_maxAnnotationBuffered_default_value);
+       zend_string *property_maxAnnotationBuffered_name = zend_string_init("maxAnnotationBuffered", sizeof("maxAnnotationBuffered") - 1, 1);
+       zend_declare_typed_property(class_entry, property_maxAnnotationBuffered_name, &property_maxAnnotationBuffered_default_value, ZEND_ACC_PUBLIC|ZEND_ACC_READONLY, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG));
+       zend_string_release(property_maxAnnotationBuffered_name);
+
+       zval property_symbolThreshold_default_value;
+       ZVAL_UNDEF(&property_symbolThreshold_default_value);
+       zend_string *property_symbolThreshold_name = zend_string_init("symbolThreshold", sizeof("symbolThreshold") - 1, 1);
+       zend_declare_typed_property(class_entry, property_symbolThreshold_name, &property_symbolThreshold_default_value, ZEND_ACC_PUBLIC|ZEND_ACC_READONLY, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG));
+       zend_string_release(property_symbolThreshold_name);
+
+       zval property_userValueThreshold_default_value;
+       ZVAL_UNDEF(&property_userValueThreshold_default_value);
+       zend_string *property_userValueThreshold_name = zend_string_init("userValueThreshold", sizeof("userValueThreshold") - 1, 1);
+       zend_declare_typed_property(class_entry, property_userValueThreshold_name, &property_userValueThreshold_default_value, ZEND_ACC_PUBLIC|ZEND_ACC_READONLY, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG));
+       zend_string_release(property_userValueThreshold_name);
+
+       zval property_chunkThreshold_default_value;
+       ZVAL_UNDEF(&property_chunkThreshold_default_value);
+       zend_string *property_chunkThreshold_name = zend_string_init("chunkThreshold", sizeof("chunkThreshold") - 1, 1);
+       zend_declare_typed_property(class_entry, property_chunkThreshold_name, &property_chunkThreshold_default_value, ZEND_ACC_PUBLIC|ZEND_ACC_READONLY, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG));
+       zend_string_release(property_chunkThreshold_name);
+
+       zval property_allocationPageSize_default_value;
+       ZVAL_UNDEF(&property_allocationPageSize_default_value);
+       zend_string *property_allocationPageSize_name = zend_string_init("allocationPageSize", sizeof("allocationPageSize") - 1, 1);
+       zend_declare_typed_property(class_entry, property_allocationPageSize_name, &property_allocationPageSize_default_value, ZEND_ACC_PUBLIC|ZEND_ACC_READONLY, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG));
+       zend_string_release(property_allocationPageSize_name);
+
+       zval property_skipCharacterValidation_default_value;
+       ZVAL_UNDEF(&property_skipCharacterValidation_default_value);
+       zend_string *property_skipCharacterValidation_name = zend_string_init("skipCharacterValidation", sizeof("skipCharacterValidation") - 1, 1);
+       zend_declare_typed_property(class_entry, property_skipCharacterValidation_name, &property_skipCharacterValidation_default_value, ZEND_ACC_PUBLIC|ZEND_ACC_READONLY, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_BOOL));
+       zend_string_release(property_skipCharacterValidation_name);
+
+       return class_entry;
+}
+
+static zend_class_entry *register_class_ion_Reader_Reader(zend_class_entry *class_entry_ion_Reader)
+{
+       zend_class_entry ce, *class_entry;
+
+       INIT_NS_CLASS_ENTRY(ce, "ion\\Reader", "Reader", class_ion_Reader_Reader_methods);
+       class_entry = zend_register_internal_class_ex(&ce, NULL);
+       class_entry->ce_flags |= ZEND_ACC_ABSTRACT;
+       zend_class_implements(class_entry, 1, class_entry_ion_Reader);
+
+       zend_string *property_options_class_ion_Reader_Options = zend_string_init("ion\\Reader\\Options", sizeof("ion\\Reader\\Options")-1, 1);
+       zval property_options_default_value;
+       ZVAL_UNDEF(&property_options_default_value);
+       zend_string *property_options_name = zend_string_init("options", sizeof("options") - 1, 1);
+       zend_declare_typed_property(class_entry, property_options_name, &property_options_default_value, ZEND_ACC_PUBLIC|ZEND_ACC_READONLY, NULL, (zend_type) ZEND_TYPE_INIT_CLASS(property_options_class_ion_Reader_Options, 0, MAY_BE_NULL));
+       zend_string_release(property_options_name);
+
+       return class_entry;
+}
+
+static zend_class_entry *register_class_ion_Reader_Buffer(zend_class_entry *class_entry_ion_Reader)
+{
+       zend_class_entry ce, *class_entry;
+
+       INIT_NS_CLASS_ENTRY(ce, "ion\\Reader", "Buffer", class_ion_Reader_Buffer_methods);
+       class_entry = zend_register_internal_interface(&ce);
+       zend_class_implements(class_entry, 1, class_entry_ion_Reader);
+
+       return class_entry;
+}
+
+static zend_class_entry *register_class_ion_Reader_Buffer_Reader(zend_class_entry *class_entry_ion_Reader_Reader, zend_class_entry *class_entry_ion_Reader_Buffer)
+{
+       zend_class_entry ce, *class_entry;
+
+       INIT_NS_CLASS_ENTRY(ce, "ion\\Reader\\Buffer", "Reader", class_ion_Reader_Buffer_Reader_methods);
+       class_entry = zend_register_internal_class_ex(&ce, class_entry_ion_Reader_Reader);
+       zend_class_implements(class_entry, 1, class_entry_ion_Reader_Buffer);
+
+       return class_entry;
+}
+
+static zend_class_entry *register_class_ion_Reader_Stream(zend_class_entry *class_entry_ion_Reader)
+{
+       zend_class_entry ce, *class_entry;
+
+       INIT_NS_CLASS_ENTRY(ce, "ion\\Reader", "Stream", class_ion_Reader_Stream_methods);
+       class_entry = zend_register_internal_interface(&ce);
+       zend_class_implements(class_entry, 1, class_entry_ion_Reader);
+
+       return class_entry;
+}
+
+static zend_class_entry *register_class_ion_Reader_Stream_Reader(zend_class_entry *class_entry_ion_Reader_Reader, zend_class_entry *class_entry_ion_Reader_Stream)
+{
+       zend_class_entry ce, *class_entry;
+
+       INIT_NS_CLASS_ENTRY(ce, "ion\\Reader\\Stream", "Reader", class_ion_Reader_Stream_Reader_methods);
+       class_entry = zend_register_internal_class_ex(&ce, class_entry_ion_Reader_Reader);
+       zend_class_implements(class_entry, 1, class_entry_ion_Reader_Stream);
+
+       return class_entry;
+}
+
+static zend_class_entry *register_class_ion_Writer_Options(void)
+{
+       zend_class_entry ce, *class_entry;
+
+       INIT_NS_CLASS_ENTRY(ce, "ion\\Writer", "Options", class_ion_Writer_Options_methods);
+       class_entry = zend_register_internal_class_ex(&ce, NULL);
+
+       zend_string *property_catalog_class_ion_Catalog = zend_string_init("ion\\Catalog", sizeof("ion\\Catalog")-1, 1);
+       zval property_catalog_default_value;
+       ZVAL_UNDEF(&property_catalog_default_value);
+       zend_string *property_catalog_name = zend_string_init("catalog", sizeof("catalog") - 1, 1);
+       zend_declare_typed_property(class_entry, property_catalog_name, &property_catalog_default_value, ZEND_ACC_PUBLIC|ZEND_ACC_READONLY, NULL, (zend_type) ZEND_TYPE_INIT_CLASS(property_catalog_class_ion_Catalog, 0, MAY_BE_NULL));
+       zend_string_release(property_catalog_name);
+
+       zend_string *property_decimalContext_class_ion_Decimal_Context = zend_string_init("ion\\Decimal\\Context", sizeof("ion\\Decimal\\Context")-1, 1);
+       zval property_decimalContext_default_value;
+       ZVAL_UNDEF(&property_decimalContext_default_value);
+       zend_string *property_decimalContext_name = zend_string_init("decimalContext", sizeof("decimalContext") - 1, 1);
+       zend_declare_typed_property(class_entry, property_decimalContext_name, &property_decimalContext_default_value, ZEND_ACC_PUBLIC|ZEND_ACC_READONLY, NULL, (zend_type) ZEND_TYPE_INIT_CLASS(property_decimalContext_class_ion_Decimal_Context, 0, MAY_BE_NULL));
+       zend_string_release(property_decimalContext_name);
+
+       zval property_outputBinary_default_value;
+       ZVAL_UNDEF(&property_outputBinary_default_value);
+       zend_string *property_outputBinary_name = zend_string_init("outputBinary", sizeof("outputBinary") - 1, 1);
+       zend_declare_typed_property(class_entry, property_outputBinary_name, &property_outputBinary_default_value, ZEND_ACC_PUBLIC|ZEND_ACC_READONLY, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_BOOL));
+       zend_string_release(property_outputBinary_name);
+
+       zval property_compactFloats_default_value;
+       ZVAL_UNDEF(&property_compactFloats_default_value);
+       zend_string *property_compactFloats_name = zend_string_init("compactFloats", sizeof("compactFloats") - 1, 1);
+       zend_declare_typed_property(class_entry, property_compactFloats_name, &property_compactFloats_default_value, ZEND_ACC_PUBLIC|ZEND_ACC_READONLY, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_BOOL));
+       zend_string_release(property_compactFloats_name);
+
+       zval property_escapeNonAscii_default_value;
+       ZVAL_UNDEF(&property_escapeNonAscii_default_value);
+       zend_string *property_escapeNonAscii_name = zend_string_init("escapeNonAscii", sizeof("escapeNonAscii") - 1, 1);
+       zend_declare_typed_property(class_entry, property_escapeNonAscii_name, &property_escapeNonAscii_default_value, ZEND_ACC_PUBLIC|ZEND_ACC_READONLY, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_BOOL));
+       zend_string_release(property_escapeNonAscii_name);
+
+       zval property_prettyPrint_default_value;
+       ZVAL_UNDEF(&property_prettyPrint_default_value);
+       zend_string *property_prettyPrint_name = zend_string_init("prettyPrint", sizeof("prettyPrint") - 1, 1);
+       zend_declare_typed_property(class_entry, property_prettyPrint_name, &property_prettyPrint_default_value, ZEND_ACC_PUBLIC|ZEND_ACC_READONLY, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_BOOL));
+       zend_string_release(property_prettyPrint_name);
+
+       zval property_indentTabs_default_value;
+       ZVAL_UNDEF(&property_indentTabs_default_value);
+       zend_string *property_indentTabs_name = zend_string_init("indentTabs", sizeof("indentTabs") - 1, 1);
+       zend_declare_typed_property(class_entry, property_indentTabs_name, &property_indentTabs_default_value, ZEND_ACC_PUBLIC|ZEND_ACC_READONLY, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_BOOL));
+       zend_string_release(property_indentTabs_name);
+
+       zval property_indentSize_default_value;
+       ZVAL_UNDEF(&property_indentSize_default_value);
+       zend_string *property_indentSize_name = zend_string_init("indentSize", sizeof("indentSize") - 1, 1);
+       zend_declare_typed_property(class_entry, property_indentSize_name, &property_indentSize_default_value, ZEND_ACC_PUBLIC|ZEND_ACC_READONLY, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG));
+       zend_string_release(property_indentSize_name);
+
+       zval property_smallContainersInline_default_value;
+       ZVAL_UNDEF(&property_smallContainersInline_default_value);
+       zend_string *property_smallContainersInline_name = zend_string_init("smallContainersInline", sizeof("smallContainersInline") - 1, 1);
+       zend_declare_typed_property(class_entry, property_smallContainersInline_name, &property_smallContainersInline_default_value, ZEND_ACC_PUBLIC|ZEND_ACC_READONLY, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_BOOL));
+       zend_string_release(property_smallContainersInline_name);
+
+       zval property_suppressSystemValues_default_value;
+       ZVAL_UNDEF(&property_suppressSystemValues_default_value);
+       zend_string *property_suppressSystemValues_name = zend_string_init("suppressSystemValues", sizeof("suppressSystemValues") - 1, 1);
+       zend_declare_typed_property(class_entry, property_suppressSystemValues_name, &property_suppressSystemValues_default_value, ZEND_ACC_PUBLIC|ZEND_ACC_READONLY, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_BOOL));
+       zend_string_release(property_suppressSystemValues_name);
+
+       zval property_flushEveryValue_default_value;
+       ZVAL_UNDEF(&property_flushEveryValue_default_value);
+       zend_string *property_flushEveryValue_name = zend_string_init("flushEveryValue", sizeof("flushEveryValue") - 1, 1);
+       zend_declare_typed_property(class_entry, property_flushEveryValue_name, &property_flushEveryValue_default_value, ZEND_ACC_PUBLIC|ZEND_ACC_READONLY, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_BOOL));
+       zend_string_release(property_flushEveryValue_name);
+
+       zval property_maxContainerDepth_default_value;
+       ZVAL_UNDEF(&property_maxContainerDepth_default_value);
+       zend_string *property_maxContainerDepth_name = zend_string_init("maxContainerDepth", sizeof("maxContainerDepth") - 1, 1);
+       zend_declare_typed_property(class_entry, property_maxContainerDepth_name, &property_maxContainerDepth_default_value, ZEND_ACC_PUBLIC|ZEND_ACC_READONLY, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG));
+       zend_string_release(property_maxContainerDepth_name);
+
+       zval property_maxAnnotations_default_value;
+       ZVAL_UNDEF(&property_maxAnnotations_default_value);
+       zend_string *property_maxAnnotations_name = zend_string_init("maxAnnotations", sizeof("maxAnnotations") - 1, 1);
+       zend_declare_typed_property(class_entry, property_maxAnnotations_name, &property_maxAnnotations_default_value, ZEND_ACC_PUBLIC|ZEND_ACC_READONLY, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG));
+       zend_string_release(property_maxAnnotations_name);
+
+       zval property_tempBufferSize_default_value;
+       ZVAL_UNDEF(&property_tempBufferSize_default_value);
+       zend_string *property_tempBufferSize_name = zend_string_init("tempBufferSize", sizeof("tempBufferSize") - 1, 1);
+       zend_declare_typed_property(class_entry, property_tempBufferSize_name, &property_tempBufferSize_default_value, ZEND_ACC_PUBLIC|ZEND_ACC_READONLY, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG));
+       zend_string_release(property_tempBufferSize_name);
+
+       zval property_allocationPageSize_default_value;
+       ZVAL_UNDEF(&property_allocationPageSize_default_value);
+       zend_string *property_allocationPageSize_name = zend_string_init("allocationPageSize", sizeof("allocationPageSize") - 1, 1);
+       zend_declare_typed_property(class_entry, property_allocationPageSize_name, &property_allocationPageSize_default_value, ZEND_ACC_PUBLIC|ZEND_ACC_READONLY, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG));
+       zend_string_release(property_allocationPageSize_name);
+
+       return class_entry;
+}
+
+static zend_class_entry *register_class_ion_Writer(void)
+{
+       zend_class_entry ce, *class_entry;
+
+       INIT_NS_CLASS_ENTRY(ce, "ion", "Writer", class_ion_Writer_methods);
+       class_entry = zend_register_internal_interface(&ce);
+
+       return class_entry;
+}
+
+static zend_class_entry *register_class_ion_Writer_Writer(zend_class_entry *class_entry_ion_Writer)
+{
+       zend_class_entry ce, *class_entry;
+
+       INIT_NS_CLASS_ENTRY(ce, "ion\\Writer", "Writer", class_ion_Writer_Writer_methods);
+       class_entry = zend_register_internal_class_ex(&ce, NULL);
+       class_entry->ce_flags |= ZEND_ACC_ABSTRACT;
+       zend_class_implements(class_entry, 1, class_entry_ion_Writer);
+
+       return class_entry;
+}
+
+static zend_class_entry *register_class_ion_Writer_Buffer(zend_class_entry *class_entry_ion_Writer)
+{
+       zend_class_entry ce, *class_entry;
+
+       INIT_NS_CLASS_ENTRY(ce, "ion\\Writer", "Buffer", class_ion_Writer_Buffer_methods);
+       class_entry = zend_register_internal_interface(&ce);
+       zend_class_implements(class_entry, 1, class_entry_ion_Writer);
+
+       return class_entry;
+}
+
+static zend_class_entry *register_class_ion_Writer_Buffer_Writer(zend_class_entry *class_entry_ion_Writer_Writer, zend_class_entry *class_entry_ion_Writer_Buffer)
+{
+       zend_class_entry ce, *class_entry;
+
+       INIT_NS_CLASS_ENTRY(ce, "ion\\Writer\\Buffer", "Writer", class_ion_Writer_Buffer_Writer_methods);
+       class_entry = zend_register_internal_class_ex(&ce, class_entry_ion_Writer_Writer);
+       zend_class_implements(class_entry, 1, class_entry_ion_Writer_Buffer);
+
+       return class_entry;
+}
+
+static zend_class_entry *register_class_ion_Writer_Stream(zend_class_entry *class_entry_ion_Writer)
+{
+       zend_class_entry ce, *class_entry;
+
+       INIT_NS_CLASS_ENTRY(ce, "ion\\Writer", "Stream", class_ion_Writer_Stream_methods);
+       class_entry = zend_register_internal_interface(&ce);
+       zend_class_implements(class_entry, 1, class_entry_ion_Writer);
+
+       return class_entry;
+}
+
+static zend_class_entry *register_class_ion_Writer_Stream_Writer(zend_class_entry *class_entry_ion_Writer_Writer, zend_class_entry *class_entry_ion_Writer_Stream)
+{
+       zend_class_entry ce, *class_entry;
+
+       INIT_NS_CLASS_ENTRY(ce, "ion\\Writer\\Stream", "Writer", class_ion_Writer_Stream_Writer_methods);
+       class_entry = zend_register_internal_class_ex(&ce, class_entry_ion_Writer_Writer);
+       zend_class_implements(class_entry, 1, class_entry_ion_Writer_Stream);
+
+       return class_entry;
+}
+
+static zend_class_entry *register_class_ion_PHP_Serializer(void)
+{
+       zend_class_entry ce, *class_entry;
+
+       INIT_NS_CLASS_ENTRY(ce, "ion\\PHP", "Serializer", class_ion_PHP_Serializer_methods);
+       class_entry = zend_register_internal_class_ex(&ce, NULL);
+
+       zend_string *property_writer_class_ion_Writer = zend_string_init("ion\\Writer", sizeof("ion\\Writer")-1, 1);
+       zval property_writer_default_value;
+       ZVAL_UNDEF(&property_writer_default_value);
+       zend_string *property_writer_name = zend_string_init("writer", sizeof("writer") - 1, 1);
+       zend_declare_typed_property(class_entry, property_writer_name, &property_writer_default_value, ZEND_ACC_PUBLIC|ZEND_ACC_READONLY, NULL, (zend_type) ZEND_TYPE_INIT_CLASS(property_writer_class_ion_Writer, 0, 0));
+       zend_string_release(property_writer_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);
+       zend_declare_typed_property(class_entry, property_callMagicSerialize_name, &property_callMagicSerialize_default_value, ZEND_ACC_PUBLIC|ZEND_ACC_READONLY, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_BOOL));
+       zend_string_release(property_callMagicSerialize_name);
+
+       zval property_callCustomSerialize_default_value;
+       ZVAL_UNDEF(&property_callCustomSerialize_default_value);
+       zend_string *property_callCustomSerialize_name = zend_string_init("callCustomSerialize", sizeof("callCustomSerialize") - 1, 1);
+       zend_declare_typed_property(class_entry, property_callCustomSerialize_name, &property_callCustomSerialize_default_value, ZEND_ACC_PUBLIC|ZEND_ACC_READONLY, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_STRING|MAY_BE_NULL));
+       zend_string_release(property_callCustomSerialize_name);
+
+       return class_entry;
+}
+
+static zend_class_entry *register_class_ion_PHP_Unserializer(void)
+{
+       zend_class_entry ce, *class_entry;
+
+       INIT_NS_CLASS_ENTRY(ce, "ion\\PHP", "Unserializer", class_ion_PHP_Unserializer_methods);
+       class_entry = zend_register_internal_class_ex(&ce, NULL);
+
+       zend_string *property_reader_class_ion_Reader = zend_string_init("ion\\Reader", sizeof("ion\\Reader")-1, 1);
+       zval property_reader_default_value;
+       ZVAL_UNDEF(&property_reader_default_value);
+       zend_string *property_reader_name = zend_string_init("reader", sizeof("reader") - 1, 1);
+       zend_declare_typed_property(class_entry, property_reader_name, &property_reader_default_value, ZEND_ACC_PUBLIC|ZEND_ACC_READONLY, NULL, (zend_type) ZEND_TYPE_INIT_CLASS(property_reader_class_ion_Reader, 0, 0));
+       zend_string_release(property_reader_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);
+       zend_declare_typed_property(class_entry, property_callMagicUnserialize_name, &property_callMagicUnserialize_default_value, ZEND_ACC_PUBLIC|ZEND_ACC_READONLY, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_BOOL));
+       zend_string_release(property_callMagicUnserialize_name);
+
+       zval property_callCustomUnserialize_default_value;
+       ZVAL_UNDEF(&property_callCustomUnserialize_default_value);
+       zend_string *property_callCustomUnserialize_name = zend_string_init("callCustomUnserialize", sizeof("callCustomUnserialize") - 1, 1);
+       zend_declare_typed_property(class_entry, property_callCustomUnserialize_name, &property_callCustomUnserialize_default_value, ZEND_ACC_PUBLIC|ZEND_ACC_READONLY, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_STRING|MAY_BE_NULL));
+       zend_string_release(property_callCustomUnserialize_name);
+
+       return class_entry;
+}
diff --git a/ion_private.h b/ion_private.h
new file mode 100644 (file)
index 0000000..0192e14
--- /dev/null
@@ -0,0 +1,1486 @@
+/*
+    +--------------------------------------------------------------------+
+    | PECL :: ion                                                        |
+    +--------------------------------------------------------------------+
+    | Redistribution and use in source and binary forms, with or without |
+    | modification, are permitted provided that the conditions mentioned |
+    | in the accompanying LICENSE file are met.                          |
+    +--------------------------------------------------------------------+
+    | Copyright (c) 2021, Michael Wallner <mike@php.net>                 |
+    +--------------------------------------------------------------------+
+*/
+
+#include "ionc/ion.h"
+
+#include "php.h"
+#include "ext/date/php_date.h"
+
+typedef struct php_ion_global_serializer php_ion_global_serializer;
+typedef struct php_ion_global_unserializer php_ion_global_unserializer;
+
+ZEND_BEGIN_MODULE_GLOBALS(ion)
+
+       struct php_ion_global_serializer {
+               HashTable ids;
+               HashTable tmp;
+               uint64_t level;
+       } serializer;
+
+       struct php_ion_global_unserializer {
+               HashTable ids;
+               HashTable tmp;
+               uint64_t level;
+       } unserializer;
+
+ZEND_END_MODULE_GLOBALS(ion);
+
+#ifdef ZTS
+#      define php_ion_globals (*((zend_ion_globals *) (*((void ***) tsrm_get_ls_cache()))[TSRM_UNSHUFFLE_RSRC_ID(ion_globals_id)]))
+#else
+#      define php_ion_globals ion_globals
+#endif
+
+ZEND_DECLARE_MODULE_GLOBALS(ion);
+
+static inline void php_ion_globals_serializer_init(void)
+{
+       php_ion_global_serializer *s = &php_ion_globals.serializer;
+
+       zend_hash_init(&s->tmp, 0, NULL, ZVAL_PTR_DTOR, 0);
+       zend_hash_init(&s->ids, 0, NULL, NULL, 0);
+}
+
+static inline void php_ion_globals_serializer_step(void)
+{
+       php_ion_global_serializer *s = &php_ion_globals.serializer;
+
+       if (!s->level++) {
+               zend_hash_clean(&s->ids);
+               zend_hash_clean(&s->tmp);
+       }
+}
+
+static inline void php_ion_globals_serializer_exit(void)
+{
+       php_ion_global_serializer *s = &php_ion_globals.serializer;
+
+       ZEND_ASSERT(s->level);
+       if (!--s->level) {
+               zend_hash_clean(&s->ids);
+               zend_hash_clean(&s->tmp);
+       }
+}
+
+static inline void php_ion_globals_serializer_dtor(void)
+{
+       php_ion_global_serializer *s = &php_ion_globals.serializer;
+
+       zend_hash_destroy(&s->tmp);
+       zend_hash_destroy(&s->ids);
+}
+
+static inline void php_ion_globals_unserializer_init(void)
+{
+       php_ion_global_unserializer *s = &php_ion_globals.unserializer;
+
+       zend_hash_init(&s->tmp, 0, NULL, ZVAL_PTR_DTOR, 0);
+       zend_hash_init(&s->ids, 0, NULL, NULL, 0);
+}
+
+static inline void php_ion_globals_unserializer_step(void)
+{
+       php_ion_global_unserializer *s = &php_ion_globals.unserializer;
+
+       if (!s->level++) {
+               zend_hash_clean(&s->ids);
+               zend_hash_clean(&s->tmp);
+       }
+}
+
+static inline void php_ion_globals_unserializer_exit(void)
+{
+       php_ion_global_unserializer *s = &php_ion_globals.unserializer;
+
+       ZEND_ASSERT(s->level);
+       if (!--s->level) {
+               zend_hash_clean(&s->ids);
+               zend_hash_clean(&s->tmp);
+       }
+}
+
+static inline void php_ion_globals_unserializer_dtor(void)
+{
+       php_ion_global_unserializer *s = &php_ion_globals.unserializer;
+
+       zend_hash_destroy(&s->tmp);
+       zend_hash_destroy(&s->ids);
+}
+
+static zend_class_entry
+       *ce_Annotation,
+       *ce_Catalog,
+       *ce_Collection,
+       *ce_Decimal,
+       *ce_Decimal_Context,
+       *ce_PHP_Serializer,
+       *ce_PHP_Unserializer,
+       *ce_Reader,
+       *ce_Reader_Options,
+       *ce_Reader_Reader,
+       *ce_Reader_Buffer,
+       *ce_Reader_Stream,
+       *ce_Reader_Buffer_Reader,
+       *ce_Reader_Stream_Reader,
+       *ce_Symbol,
+       *ce_Symbol_ImportLocation,
+       *ce_Symbol_System,
+       *ce_Symbol_System_SID,
+       *ce_Symbol_Table,
+       *ce_Timestamp,
+       *ce_Type,
+       *ce_Writer,
+       *ce_Writer_Options,
+       *ce_Writer_Buffer,
+       *ce_Writer_Buffer_Writer,
+       *ce_Writer_Stream,
+       *ce_Writer_Stream_Writer,
+       *ce_Writer_Writer
+       ;
+static zend_object_handlers
+       oh_catalog,
+       oh_decimal,
+       oh_decimal_ctx,
+       oh_reader_options,
+       oh_reader,
+       oh_symbol,
+       oh_symbol_iloc,
+       oh_symbol_table,
+       oh_timestamp,
+       oh_type,
+       oh_writer_options,
+       oh_writer
+       ;
+
+#define php_ion_decl(type, name, ...) \
+       static zend_object *create_ion_ ## name(zend_class_entry *ce) \
+       { \
+               if (!ce) ce = ce_ ## name; \
+               php_ion_ ## type *o = ecalloc(1, sizeof(*o) + zend_object_properties_size(ce)); \
+               zend_object_std_init(&o->std, ce); \
+               object_properties_init(&o->std, ce); \
+               o->std.handlers = &oh_ ## type; \
+               return &o->std; \
+       } \
+       static void free_ion_ ## name(zend_object *std) \
+       { \
+               php_ion_ ## type *obj = php_ion_obj(type, std); \
+               __VA_ARGS__; \
+               zend_object_std_dtor(std); \
+               (void) obj; \
+       }
+#define php_ion_register(type, name, ...) do { \
+       ce_ ## name = register_class_ion_ ## name(__VA_ARGS__); \
+       ce_ ## name ->create_object = create_ion_ ## name; \
+       memcpy(&oh_ ## type, zend_get_std_object_handlers(), sizeof(zend_object_handlers)); \
+       oh_ ## type .offset = offsetof(php_ion_ ## type, std); \
+       oh_ ## type .free_obj = free_ion_ ## name; \
+} while (0)
+
+#define php_ion_obj(type, obj) \
+       ((php_ion_ ## type *) (obj ? ((char *)(obj) - XtOffsetOf(php_ion_ ## type, std)) : NULL))
+
+#define ION_CHECK(err, ...) do { \
+       iERR __err = err; \
+       if (__err) { \
+               zend_throw_exception_ex(spl_ce_RuntimeException, __err, "%s: %s", ion_error_to_str(__err), #err); \
+               __VA_ARGS__; \
+               return; \
+       } \
+} while (0)
+
+#define ION_CATCH(...) do { \
+       if (EG(exception)) { \
+               __VA_ARGS__; \
+               return; \
+       } \
+} while (0)
+
+#define PTR_CHECK(ptr, ...) do { \
+       if (!(ptr)) { \
+               zend_throw_error(NULL, "Uninitialized object"); \
+               __VA_ARGS__; \
+               return; \
+       } \
+} while (0)
+
+#define OBJ_CHECK(obj) do { \
+       PTR_CHECK(obj); \
+       PTR_CHECK(*((void **)obj)); \
+} while (0)
+
+static inline ION_STRING *ion_string_from_cstr(ION_STRING *is, const char *s, size_t l)
+{
+       is->length = l;
+       is->value = (BYTE *) s;
+       return is;
+}
+
+static inline ION_STRING *ion_string_from_zend(ION_STRING *is, const zend_string *zs)
+{
+       is->length = ZSTR_LEN(zs);
+       is->value = (BYTE *) ZSTR_VAL(zs);
+       return is;
+}
+
+static inline zend_string *zend_string_from_ion(const ION_STRING *s)
+{
+       return zend_string_init((const char *) s->value, s->length, 0);
+}
+
+static inline void update_property_obj(zend_object *obj, const char *n, size_t l, zend_object *p)
+{
+       zval zobj;
+       ZVAL_OBJ(&zobj, p);
+       zend_update_property(obj->ce, obj, n, l, &zobj);
+}
+
+typedef struct php_ion_type {
+       ION_TYPE typ;
+       zend_object std;
+} php_ion_type;
+
+#define RETURN_IONTYPE(typ) do { \
+       zend_object *__zo = php_ion_type_fetch(typ); \
+       if (UNEXPECTED(!__zo)) { \
+               RETURN_THROWS(); \
+       } \
+       RETURN_OBJ_COPY(__zo); \
+} while(0)
+
+static inline zend_object *php_ion_type_fetch(ION_TYPE typ)
+{
+       zend_long index = ION_TYPE_INT(typ);
+       zval *ztype = zend_hash_index_find(ce_Type->backed_enum_table, index);
+
+       if (UNEXPECTED(!ztype || Z_TYPE_P(ztype) != IS_STRING)) {
+               zend_value_error(ZEND_LONG_FMT " is not a valid backing value for enum \"%s\"", index, ZSTR_VAL(ce_Type->name));
+               return NULL;
+       }
+       return zend_enum_get_case(ce_Type, Z_STR_P(ztype));
+}
+
+typedef struct php_ion_symbol_iloc {
+       ION_SYMBOL_IMPORT_LOCATION loc;
+       zend_string *name;
+       zend_object std;
+} php_ion_symbol_iloc;
+
+static inline void php_ion_symbol_iloc_ctor(php_ion_symbol_iloc *obj)
+{
+       zend_update_property_long(obj->std.ce, &obj->std, ZEND_STRL("location"), obj->loc.location);
+       zend_update_property_str(obj->std.ce, &obj->std, ZEND_STRL("name"), obj->name);
+       ion_string_from_zend(&obj->loc.name, obj->name);
+}
+
+static inline void php_ion_symbol_iloc_dtor(php_ion_symbol_iloc *obj)
+{
+       zend_string_release(obj->name);
+}
+
+typedef struct php_ion_symbol {
+       ION_SYMBOL sym;
+       zend_string *value;
+       zend_object *iloc, std;
+} php_ion_symbol;
+
+static inline void php_ion_symbol_ctor(php_ion_symbol *obj)
+{
+       zend_update_property_long(obj->std.ce, &obj->std, ZEND_STRL("sid"),
+               obj->sym.sid);
+       zend_update_property_str(obj->std.ce, &obj->std, ZEND_STRL("value"), obj->value);
+       ion_string_from_zend(&obj->sym.value, obj->value);
+       if (obj->iloc) {
+               update_property_obj(&obj->std, ZEND_STRL("importLocation"), obj->iloc);
+               obj->sym.import_location = php_ion_obj(symbol_iloc, obj->iloc)->loc;
+       } else {
+               zend_update_property_null(obj->std.ce, &obj->std, ZEND_STRL("importLocation"));
+       }
+}
+
+static inline void php_ion_symbol_dtor(php_ion_symbol *obj)
+{
+       zend_string_release(obj->value);
+}
+
+static inline void php_ion_symbol_zval(ION_SYMBOL *sym_ptr, zval *return_value)
+{
+       object_init_ex(return_value, ce_Symbol);
+       php_ion_symbol *sym = php_ion_obj(symbol, Z_OBJ_P(return_value));
+
+       sym->sym.sid = sym_ptr->sid;
+       sym->value = zend_string_from_ion(&sym_ptr->value);
+       if (!ION_SYMBOL_IMPORT_LOCATION_IS_NULL(sym_ptr)) {
+               zval ziloc;
+               object_init_ex(&ziloc, ce_Symbol_ImportLocation);
+               sym->iloc = Z_OBJ(ziloc);
+
+               php_ion_symbol_iloc *iloc = php_ion_obj(symbol_iloc, sym->iloc);
+               iloc->loc.location = sym_ptr->import_location.location;
+               iloc->name = zend_string_from_ion(&sym_ptr->import_location.name);
+
+               php_ion_symbol_iloc_ctor(iloc);
+       }
+
+       php_ion_symbol_ctor(sym);
+}
+
+typedef struct php_ion_symbol_table {
+       zend_object std;
+} php_ion_symbol_table;
+
+typedef struct php_ion_decimal_ctx {
+       decContext ctx;
+       zend_object std;
+} php_ion_decimal_ctx;
+
+typedef struct php_ion_decimal {
+       ION_DECIMAL dec;
+       zend_object *ctx, std;
+} php_ion_decimal;
+
+static inline void php_ion_decimal_ctor(php_ion_decimal *obj)
+{
+       if (obj->ctx) {
+               update_property_obj(&obj->std, ZEND_STRL("context"), obj->ctx);
+       } else {
+               zend_update_property_null(obj->std.ce, &obj->std, ZEND_STRL("context"));
+       }
+}
+
+static inline void php_ion_decimal_dtor(php_ion_decimal *obj)
+{
+       ion_decimal_free(&obj->dec);
+}
+
+static inline zend_string *php_ion_decimal_to_string(ION_DECIMAL *dec)
+{
+       zend_string *zstr = zend_string_alloc(ION_DECIMAL_STRLEN(dec), 0);
+       (void) ion_decimal_to_string(dec, zstr->val);
+       return zend_string_truncate(zstr, strlen(zstr->val), 0);
+}
+
+static zend_array *php_ion_decimal_get_props_for(zend_object *object, zend_prop_purpose purpose)
+{
+       php_ion_decimal *obj = php_ion_obj(decimal, object);
+
+       switch (purpose) {
+               case ZEND_PROP_PURPOSE_DEBUG:
+                       zend_array *arr = zend_new_array(1);
+                       zval *zv = zend_hash_str_add_empty_element(arr, ZEND_STRL("value"));
+                       ZVAL_STR(zv, php_ion_decimal_to_string(&obj->dec));
+                       return arr;
+
+               default:
+                       return zend_std_get_properties_for(object, purpose);
+       }
+}
+
+typedef php_date_obj php_ion_timestamp;
+
+static inline void php_ion_timestamp_ctor(php_ion_timestamp *obj, zend_long precision, zend_string *fmt, zend_string *dt, zval *tz)
+{
+       if (!obj->time) {
+               php_date_initialize(obj, dt ? dt->val : "now", dt ? dt->len : 3, fmt ? fmt->val : NULL, tz, PHP_DATE_INIT_CTOR);
+       }
+       zend_update_property_long(obj->std.ce, &obj->std, ZEND_STRL("precision"), precision);
+       if (fmt) {
+               zend_update_property_str(obj->std.ce, &obj->std, ZEND_STRL("format"), fmt);
+       } else {
+               zend_update_property_stringl(obj->std.ce, &obj->std, ZEND_STRL("format"), ZEND_STRL("c"));
+       }
+}
+
+static inline void php_ion_timestamp_dtor(php_ion_timestamp *obj)
+{
+       if (obj->time) {
+               timelib_time_dtor(obj->time);
+       }
+}
+
+static inline zend_long php_usec_from_ion(const decQuad *frac, decContext *ctx)
+{
+       decQuad microsecs, result;
+       decQuadMultiply(&result, decQuadFromInt32(&microsecs, 1000000), frac, ctx);
+       return (zend_long) decQuadToUInt32(&result, ctx, DEC_ROUND_HALF_EVEN);
+}
+
+static inline decQuad *ion_ts_frac_from_usec(decQuad *frac, zend_long usec, decContext *ctx)
+{
+       decQuad microsecs, us;
+       return decQuadDivide(frac, decQuadFromInt32(&us, usec), decQuadFromInt32(&microsecs, 1000000), ctx);
+}
+
+static inline timelib_time* php_time_from_ion(const ION_TIMESTAMP *ts, decContext *ctx, zend_string **fmt)
+{
+       timelib_time *time = timelib_time_ctor();
+
+       switch (ts->precision) {
+       case ION_TS_FRAC:
+               time->us = php_usec_from_ion(&ts->fraction, ctx);
+               if (fmt) *fmt = zend_string_init(ZEND_STRL("c"), 0);
+               /* fallthrough */
+       case ION_TS_SEC:
+               time->s = ts->seconds;
+               if (fmt && !*fmt) *fmt = zend_string_init(ZEND_STRL("Y-m-d\\TH:i:sP"), 0);
+               /* fallthrough */
+       case ION_TS_MIN:
+               time->i = ts->minutes;
+               time->h = ts->hours;
+               if (fmt && !*fmt) *fmt = zend_string_init(ZEND_STRL("Y-m-d\\TH:iP"), 0);
+               /* fallthrough */
+       case ION_TS_DAY:
+               time->d = ts->day;
+               if (fmt && !*fmt) *fmt = zend_string_init(ZEND_STRL("Y-m-d\\T"), 0);
+               /* fallthrough */
+       case ION_TS_MONTH:
+               time->m = ts->month;
+               if (fmt && !*fmt) *fmt = zend_string_init(ZEND_STRL("Y-m\\T"), 0);
+               /* fallthrough */
+       case ION_TS_YEAR:
+               time->y = ts->year;
+               if (fmt && !*fmt) *fmt = zend_string_init(ZEND_STRL("Y\\T"), 0);
+               /* fallthrough */
+       default:
+               if (fmt && !*fmt) *fmt = zend_string_init(ZEND_STRL("c"), 0);
+               time->z = ts->tz_offset * 60;
+       }
+
+       return time;
+}
+
+static inline ION_TIMESTAMP *ion_timestamp_from_php(ION_TIMESTAMP *buf, php_ion_timestamp *ts, decContext *ctx)
+{
+       memset(buf, 0, sizeof(*buf));
+
+       zval tmp;
+       uint8_t precision = Z_LVAL_P(zend_read_property(ts->std.ce, &ts->std, ZEND_STRL("precision"), 0, &tmp));
+
+       if (!precision || precision > ION_TS_FRAC) {
+               zend_throw_exception_ex(spl_ce_InvalidArgumentException, IERR_INVALID_ARG,
+                               "Invalid precision (%u) of ion\\Timestamp", (unsigned) precision);
+       } else switch ((buf->precision = precision)) {
+       case ION_TS_FRAC:
+               ion_ts_frac_from_usec(&buf->fraction, ts->time->us, ctx);
+               /* fallthrough */
+       case ION_TS_SEC:
+               buf->seconds = ts->time->s;
+               /* fallthrough */
+       case ION_TS_MIN:
+               buf->minutes = ts->time->i;
+               /* fallthrough */
+       case ION_TS_DAY:
+               buf->hours = ts->time->h;
+               buf->day = ts->time->d;
+               /* fallthrough */
+       case ION_TS_MONTH:
+               buf->month = ts->time->m;
+               /* fallthrough */
+       case ION_TS_YEAR:
+               buf->year = ts->time->y;
+               /* fallthrough */
+       default:
+               buf->tz_offset = ts->time->z / 60;
+       }
+
+       return buf;
+}
+
+typedef struct php_ion_catalog {
+       ION_CATALOG *cat;
+       zend_object std;
+} php_ion_catalog;
+
+typedef struct php_ion_reader_options {
+       ION_READER_OPTIONS opt;
+       zend_object *cat, *dec_ctx, *cb, std;
+} php_ion_reader_options;
+
+typedef struct php_ion_reader {
+       ION_READER *reader;
+       ION_TYPE state;
+       enum {
+               BUFFER_READER,
+               STREAM_READER,
+       } type;
+       union {
+               zend_string *buffer;
+               struct {
+                       php_stream *ptr;
+                       ION_STRING buf;
+               } stream;
+       };
+       struct {
+               zend_bool call_magic_unserialize;
+               zend_string *custom_unserialize;
+       } php;
+       zend_object *opt, std;
+} php_ion_reader;
+
+static iERR php_ion_reader_stream_handler(struct _ion_user_stream *user)
+{
+       php_ion_reader *reader = (php_ion_reader *) user->handler_state;
+       size_t remaining = 0, spare = reader->stream.buf.length;
+
+       if (user->curr && user->limit && (remaining = user->limit - user->curr)) {
+               memmove(reader->stream.buf.value, user->curr, remaining);
+               user->limit -= remaining;
+               spare -= remaining;
+       } else {
+               user->curr = user->limit = reader->stream.buf.value;
+       }
+
+       ssize_t read = php_stream_read(reader->stream.ptr, (char *) user->limit, spare);
+       if (EXPECTED(read > 0)) {
+               user->limit += read;
+               return IERR_OK;
+       }
+
+       if (EXPECTED(read == 0)) {
+               return IERR_EOF;
+       }
+
+       return IERR_READ_ERROR;
+}
+
+static iERR on_context_change(void *context, ION_COLLECTION *imports)
+{
+       if (context) {
+               php_ion_reader *obj = php_ion_obj(reader, context);
+               (void) obj;
+       }
+       return IERR_OK;
+}
+
+static ION_READER_CONTEXT_CHANGE_NOTIFIER EMPTY_READER_CHANGE_NOTIFIER = {
+       on_context_change,
+       NULL
+};
+
+static inline void php_ion_reader_ctor(php_ion_reader *obj)
+{
+       iERR err;
+       php_ion_reader_options *opt = php_ion_obj(reader_options, obj->opt);
+
+       if (opt) {
+               opt->opt.context_change_notifier.context = obj;
+       }
+       if (obj->type == STREAM_READER) {
+               PTR_CHECK(obj->stream.ptr);
+               GC_ADDREF(obj->stream.ptr->res);
+
+               php_ion_reader_options *opt = php_ion_obj(reader_options, obj->opt);
+               obj->stream.buf.length = opt ? opt->opt.allocation_page_size : 0x1000;
+               obj->stream.buf.value = emalloc(obj->stream.buf.length);
+               err = ion_reader_open_stream(&obj->reader, obj, php_ion_reader_stream_handler, opt ? &opt->opt : NULL);
+
+       } else {
+               err = ion_reader_open_buffer(&obj->reader,
+                               (BYTE *) obj->buffer->val, obj->buffer->len,
+                               opt ? &opt->opt : NULL);
+       }
+       if (opt) {
+               opt->opt.context_change_notifier.context = NULL;
+       }
+
+       ION_CHECK(err);
+       OBJ_CHECK(obj);
+}
+static inline void php_ion_reader_dtor(php_ion_reader *obj)
+{
+       if (obj->reader) {
+               ion_reader_close(obj->reader);
+       }
+       if (obj->type == STREAM_READER) {
+               if (obj->stream.buf.value) {
+                       efree(obj->stream.buf.value);
+               }
+               if (obj->stream.ptr) {
+                       zend_list_delete(obj->stream.ptr->res);
+               }
+       } else {
+               if (obj->buffer) {
+                       zend_string_release(obj->buffer);
+               }
+       }
+}
+
+typedef struct php_ion_writer_options {
+       ION_WRITER_OPTIONS opt;
+       zend_object *cat, *dec_ctx, *col, std;
+} php_ion_writer_options;
+
+typedef struct php_ion_writer {
+       ION_WRITER *writer;
+       enum {
+               BUFFER_WRITER,
+               STREAM_WRITER,
+       } type;
+       union {
+               struct {
+                       zval val;
+                       smart_str str;
+               } buffer;
+               struct {
+                       ION_STRING buf;
+                       php_stream *ptr;
+               } stream;
+       };
+       struct {
+               zend_bool call_magic_serialize;
+               zend_string *custom_serialize;
+       } php;
+       zend_object *opt, std;
+
+} php_ion_writer;
+
+static iERR php_ion_writer_stream_handler(struct _ion_user_stream *user)
+{
+       php_ion_writer *writer = (php_ion_writer *) user->handler_state;
+
+       if (EXPECTED(user->limit && user->curr)) {
+               ptrdiff_t len = user->curr - writer->stream.buf.value;
+               if (len != php_stream_write(writer->stream.ptr, (char *) writer->stream.buf.value, len)) {
+                       return IERR_WRITE_ERROR;
+               }
+       }
+       user->curr = writer->stream.buf.value;
+       user->limit = writer->stream.buf.value + writer->stream.buf.length;
+       return IERR_OK;
+}
+
+#define REF_STR() do { \
+       ZVAL_NEW_STR(ref, obj->buffer.str.s); \
+       GC_ADDREF(obj->buffer.str.s); \
+} while (0)
+
+#define NEW_REF_STR() do {\
+       if (Z_STR_P(ref) != obj->buffer.str.s) { \
+               zval_ptr_dtor(ref); \
+               REF_STR(); \
+       } \
+} while(0)
+
+static inline void php_ion_writer_stream_init(php_ion_writer *obj, php_ion_writer_options *opt)
+{
+       PTR_CHECK(obj->stream.ptr);
+       GC_ADDREF(obj->stream.ptr->res);
+
+       obj->stream.buf.length = opt ? opt->opt.allocation_page_size : 0x1000;
+       obj->stream.buf.value = emalloc(obj->stream.buf.length);
+}
+static inline void php_ion_writer_buffer_init(php_ion_writer *obj)
+{
+       zval *ref = &obj->buffer.val;
+       ZVAL_DEREF(ref);
+
+       smart_str_alloc(&obj->buffer.str, 0, 0);
+       smart_str_0(&obj->buffer.str);
+       REF_STR();
+}
+
+static inline void php_ion_writer_buffer_grow(php_ion_writer *obj)
+{
+       zval *ref = &obj->buffer.val;
+       ZVAL_DEREF(ref);
+
+       switch (GC_REFCOUNT(obj->buffer.str.s)) {
+       case 2:
+               // nothing to do
+               break;
+       case 1:
+               // we've been separated
+               GC_ADDREF(obj->buffer.str.s);
+               break;
+       default:
+               // we have to separate
+               fprintf(stderr, "SEPARATE\n");
+               obj->buffer.str.s = zend_string_dup(obj->buffer.str.s, 0);
+               break;
+       }
+
+       zend_string *old = obj->buffer.str.s;
+       GC_DELREF(old);
+       smart_str_erealloc(&obj->buffer.str, obj->buffer.str.a << 1);
+       if (old == obj->buffer.str.s) {
+               GC_ADDREF(old);
+       } else if(old == Z_STR_P(ref)) {
+               ZVAL_NULL(ref);
+       }
+
+       NEW_REF_STR();
+}
+
+static iERR php_ion_writer_buffer_handler(struct _ion_user_stream *user)
+{
+       php_ion_writer *writer = (php_ion_writer *) user->handler_state;
+
+       if (user->curr) {
+               writer->buffer.str.s->len += user->curr - (BYTE *) &writer->buffer.str.s->val[writer->buffer.str.s->len];
+               smart_str_0(&writer->buffer.str);
+               if (user->limit == user->curr) {
+                       php_ion_writer_buffer_grow(writer);
+               }
+       }
+       user->curr = (BYTE *) &writer->buffer.str.s->val[writer->buffer.str.s->len];
+       user->limit = user->curr + writer->buffer.str.a - writer->buffer.str.s->len;
+
+       return IERR_OK;
+}
+
+static inline void php_ion_writer_ctor(php_ion_writer *obj)
+{
+       if (obj->opt) {
+               update_property_obj(&obj->std, ZEND_STRL("options"), obj->opt);
+       }
+
+       php_ion_writer_options *opt = php_ion_obj(writer_options, obj->opt);
+       ION_STREAM_HANDLER h;
+       if (obj->type == STREAM_WRITER) {
+               h = php_ion_writer_stream_handler;
+               php_ion_writer_stream_init(obj, opt);
+       } else {
+               h = php_ion_writer_buffer_handler;
+               php_ion_writer_buffer_init(obj);
+       }
+
+       ION_CHECK(ion_writer_open_stream(&obj->writer, h, obj, opt ? &opt->opt : NULL));
+       OBJ_CHECK(obj);
+}
+
+static inline void php_ion_writer_dtor(php_ion_writer *obj)
+{
+       if (obj->writer) {
+               ion_writer_close(obj->writer);
+       }
+       if (obj->type == STREAM_WRITER) {
+               if (obj->stream.buf.value) {
+                       efree(obj->stream.buf.value);
+               }
+               if (obj->stream.ptr) {
+                       zend_list_delete(obj->stream.ptr->res);
+               }
+       } else {
+               smart_str_0(&obj->buffer.str);
+               zend_string_release(obj->buffer.str.s);
+               zval_ptr_dtor(&obj->buffer.val);
+       }
+       if (obj->php.custom_serialize) {
+               zend_string_release(obj->php.custom_serialize);
+       }
+}
+
+static inline void php_ion_serialize_zval(php_ion_writer *, zval *);
+
+static inline void php_ion_serialize_struct(php_ion_writer *obj, zend_array *arr)
+{
+       ION_CHECK(ion_writer_start_container(obj->writer, tid_STRUCT));
+
+       zval *v;
+       zend_ulong h;
+       zend_string *k = NULL;
+       if (arr) ZEND_HASH_FOREACH_KEY_VAL_IND(arr, h, k, v)
+               ION_STRING is;
+               if (k) {
+                       ION_CHECK(ion_writer_write_field_name(obj->writer, ion_string_from_zend(&is, k)));
+               } else {
+                       char buf[MAX_LENGTH_OF_LONG + 1], *ptr = zend_print_ulong_to_buf(buf + sizeof(buf), h);
+                       ION_CHECK(ion_writer_add_annotation(obj->writer, ion_string_from_cstr(&is, ZEND_STRL("i"))));
+                       ION_CHECK(ion_writer_write_field_name(obj->writer, ion_string_from_cstr(&is, ptr, buf - ptr)));
+               }
+
+               php_ion_serialize_zval(obj, v);
+               ION_CATCH();
+       ZEND_HASH_FOREACH_END();
+
+       ION_CHECK(ion_writer_finish_container(obj->writer));
+}
+
+static inline void php_ion_serialize_list(php_ion_writer *obj, zend_array *arr)
+{
+       ION_CHECK(ion_writer_start_container(obj->writer, tid_LIST));
+
+       zval *v;
+       ZEND_HASH_FOREACH_VAL_IND(arr, v)
+               php_ion_serialize_zval(obj, v);
+               ION_CATCH();
+       ZEND_HASH_FOREACH_END();
+
+       ION_CHECK(ion_writer_finish_container(obj->writer));
+}
+
+static inline void php_ion_serialize_array(php_ion_writer *obj, zend_array *arr)
+{
+       if (zend_array_is_list(arr)) {
+               php_ion_serialize_list(obj, arr);
+       } else {
+               php_ion_serialize_struct(obj, arr);
+       }
+}
+
+static inline void php_ion_serialize_object_iface(php_ion_writer *obj, zend_object *zobject)
+{
+       uint8_t *buf;
+       size_t len;
+       zval tmp;
+
+       ZVAL_OBJ(&tmp, zobject);
+       if (SUCCESS == zobject->ce->serialize(&tmp, &buf, &len, NULL)) {
+               ION_STRING is;
+               ION_CHECK(ion_writer_add_annotation(obj->writer, ion_string_from_cstr(&is, ZEND_STRL("S"))));
+               ION_CHECK(ion_writer_add_annotation(obj->writer, ion_string_from_zend(&is, zobject->ce->name)));
+               ION_CHECK(ion_writer_write_string(obj->writer, ion_string_from_cstr(&is, (char *) buf, len)));
+               efree(buf);
+       } else if (!EG(exception)){
+               zend_throw_exception_ex(spl_ce_UnexpectedValueException, IERR_INTERNAL_ERROR,
+                               "Failed to serialize class %s", zobject->ce->name->val);
+       }
+}
+
+static inline void php_ion_serialize_object_magic(php_ion_writer *obj, zend_object *zobject, zend_function *fn)
+{
+       zval rv;
+
+       ZVAL_NULL(&rv);
+       zend_call_method_with_0_params(zobject, zobject->ce, fn ? &fn : &zobject->ce->__serialize, "", &rv);
+       ION_CATCH();
+
+       if (IS_ARRAY == Z_TYPE(rv)) {
+               ION_STRING is;
+               ION_CHECK(ion_writer_add_annotation(obj->writer, ion_string_from_cstr(&is, ZEND_STRL(fn ? "C" : "O"))));
+               ION_CHECK(ion_writer_add_annotation(obj->writer, ion_string_from_zend(&is, zobject->ce->name)));
+               php_ion_serialize_zval(obj, &rv);
+               zval_ptr_dtor(&rv);
+       } else {
+               zend_throw_exception_ex(spl_ce_UnexpectedValueException, IERR_INTERNAL_ERROR,
+                               "%s serializer %s::%s did not return an array",
+                               fn ? "Custom" : "Magic", zobject->ce->name->val,
+                               fn ? fn->common.function_name->val : "__serialize");
+       }
+}
+
+static inline zend_string *fq_enum_case(zend_object *zobject)
+{
+       zval *cn = zend_enum_fetch_case_name(zobject);
+       zend_string *en = zend_string_alloc(zobject->ce->name->len + Z_STRLEN_P(cn) + strlen("\\"), 0);
+       memcpy(en->val, zobject->ce->name->val, zobject->ce->name->len);
+       en->val[zobject->ce->name->len] = '\\';
+       memcpy(&en->val[zobject->ce->name->len + 1], Z_STRVAL_P(cn), Z_STRLEN_P(cn));
+       en->val[en->len] = 0;
+       return en;
+}
+
+static inline void php_ion_serialize_object_enum(php_ion_writer *obj, zend_object *zobject)
+{
+       ION_STRING is;
+       ION_CHECK(ion_writer_add_annotation(obj->writer, ion_string_from_cstr(&is, ZEND_STRL("E"))));
+
+       zend_string *en = fq_enum_case(zobject);
+       ION_CHECK(ion_writer_write_string(obj->writer, ion_string_from_zend(&is, en)));
+       zend_string_release(en);
+}
+
+static inline void php_ion_serialize_object_std(php_ion_writer *obj, zend_object *zobject)
+{
+       ION_STRING is;
+       ION_CHECK(ion_writer_add_annotation(obj->writer, ion_string_from_cstr(&is, ZEND_STRL("o"))));
+
+       if (zobject->ce != zend_standard_class_def) {
+               ION_CHECK(ion_writer_add_annotation(obj->writer, ion_string_from_zend(&is, zobject->ce->name)));
+       }
+
+       zval zobj;
+       ZVAL_OBJ(&zobj, zobject);
+       HashTable *props = zend_get_properties_for(&zobj, ZEND_PROP_PURPOSE_SERIALIZE);
+       if (props) {
+               php_ion_serialize_struct(obj, props);
+               zend_release_properties(props);
+       } else {
+               zend_throw_exception_ex(spl_ce_UnexpectedValueException, IERR_INTERNAL_ERROR,
+                               "Could not get properties for serialization of class %s",
+                               zobject->ce->name->val);
+       }
+}
+
+static inline bool can_call_magic_serialize(php_ion_writer *obj, zend_class_entry *ce)
+{
+       if (ce->__serialize && obj->php.call_magic_serialize) {
+               return true;
+       }
+       return false;
+}
+
+static inline bool can_call_iface_serialize(php_ion_writer *obj, zend_class_entry *ce)
+{
+       return !!ce->serialize;
+}
+
+static inline bool can_call_custom_serialize(php_ion_writer *obj, zend_object *zobject, zend_function **fn)
+{
+       if (obj->php.custom_serialize) {
+               return !!((*fn = zend_hash_find_ptr(&zobject->ce->function_table, obj->php.custom_serialize)));
+       }
+       return false;
+}
+
+static inline void php_ion_serialize_object(php_ion_writer *obj, zend_object *zobject)
+{
+       zend_function *fn;
+       zend_class_entry *ce = zobject->ce;
+       ZEND_ASSERT(ce);
+
+       if (ce->ce_flags & ZEND_ACC_NOT_SERIALIZABLE) {
+               zend_throw_exception_ex(spl_ce_InvalidArgumentException, IERR_INVALID_ARG,
+                               "Serializing %s is not allowed", ce->name->val);
+               return;
+       }
+
+       if (can_call_magic_serialize(obj, ce)) {
+               php_ion_serialize_object_magic(obj, zobject, NULL);
+       } else if (can_call_iface_serialize(obj, ce)) {
+               php_ion_serialize_object_iface(obj, zobject);
+       } else if (can_call_custom_serialize(obj, zobject, &fn)) {
+               php_ion_serialize_object_magic(obj, zobject, fn);
+       } else if (zobject->ce->ce_flags & ZEND_ACC_ENUM) {
+               php_ion_serialize_object_enum(obj, zobject);
+       } else if (ce == ce_Symbol) {
+               ION_CHECK(ion_writer_write_ion_symbol(obj->writer, &php_ion_obj(symbol, zobject)->sym));
+       } else if (ce == ce_Decimal) {
+               ION_CHECK(ion_writer_write_ion_decimal(obj->writer, &php_ion_obj(decimal, zobject)->dec));
+       } else if (ce == ce_Timestamp) {
+               ION_TIMESTAMP its;
+               php_ion_timestamp *pts = php_ion_obj(timestamp, zobject);
+               php_ion_writer_options *opt = php_ion_obj(writer_options, obj->opt);
+               decContext *ctx = opt ? opt->opt.decimal_context : NULL;
+               ION_CHECK(ion_writer_write_timestamp(obj->writer, ion_timestamp_from_php(&its, pts, ctx)));
+       } else {
+               php_ion_serialize_object_std(obj, zobject);
+       }
+}
+
+static inline void php_ion_serialize_refcounted(php_ion_writer *obj, zval *zv)
+{
+       zend_ulong idx = (zend_ulong) (uintptr_t) Z_COUNTED_P(zv);
+
+       ION_STRING is;
+       if (zend_hash_index_exists(&php_ion_globals.serializer.ids, idx)) {
+               zval *num = zend_hash_index_find(&php_ion_globals.serializer.ids, idx);
+
+               ION_CHECK(ion_writer_add_annotation(obj->writer, ion_string_from_cstr(&is, ZEND_STRL("r"))));
+               ION_CHECK(ion_writer_write_int64(obj->writer, Z_LVAL_P(num)));
+       } else {
+               zval num;
+
+               ZVAL_LONG(&num, zend_hash_num_elements(&php_ion_globals.serializer.ids));
+               zend_hash_index_add(&php_ion_globals.serializer.ids, idx, &num);
+
+               Z_TRY_ADDREF_P(zv);
+               zend_hash_next_index_insert(&php_ion_globals.serializer.tmp, zv);
+
+               switch (Z_TYPE_P(zv)) {
+               case IS_STRING:
+                       ION_CHECK(ion_writer_write_string(obj->writer, ion_string_from_zend(&is, Z_STR_P(zv))));
+                       break;
+
+               case IS_ARRAY:
+                       php_ion_serialize_array(obj, Z_ARRVAL_P(zv));
+                       break;
+
+               case IS_OBJECT:
+                       php_ion_serialize_object(obj, Z_OBJ_P(zv));
+                       break;
+
+               case IS_REFERENCE:
+                       ION_CHECK(ion_writer_add_annotation(obj->writer, ion_string_from_cstr(&is, ZEND_STRL("R"))));
+                       php_ion_serialize_zval(obj, Z_REFVAL_P(zv));
+                       break;
+               }
+       }
+}
+
+static inline void php_ion_serialize_zval(php_ion_writer *obj, zval *zv)
+{
+       OBJ_CHECK(obj);
+
+       switch (Z_TYPE_P(zv)) {
+       case IS_NULL:
+               ION_CHECK(ion_writer_write_null(obj->writer));
+               break;
+       case IS_TRUE:
+               ION_CHECK(ion_writer_write_bool(obj->writer, TRUE));
+               break;
+       case IS_FALSE:
+               ION_CHECK(ion_writer_write_bool(obj->writer, FALSE));
+               break;
+       case IS_LONG:
+               ION_CHECK(ion_writer_write_int64(obj->writer, Z_LVAL_P(zv)));
+               break;
+       case IS_DOUBLE:
+               ION_CHECK(ion_writer_write_double(obj->writer, Z_DVAL_P(zv)));
+               break;
+       case IS_STRING:
+       case IS_ARRAY:
+       case IS_OBJECT:
+       case IS_REFERENCE:
+               php_ion_serialize_refcounted(obj, zv);
+               break;
+       default:
+               zend_throw_exception_ex(spl_ce_InvalidArgumentException, IERR_INVALID_ARG,
+                               "Failed to serialize value of type %s", zend_zval_get_legacy_type(zv)->val);
+       }
+}
+
+void php_ion_serialize(php_ion_writer *obj, zval *zv, zval *return_value)
+{
+       zval zwriter;
+
+       if (obj) {
+               ZVAL_OBJ_COPY(&zwriter, &obj->std);
+       } else {
+               object_init_ex(&zwriter, ce_Writer_Buffer_Writer);
+               obj = php_ion_obj(writer, Z_OBJ(zwriter));
+               obj->type = BUFFER_WRITER;
+               php_ion_writer_ctor(obj);
+       }
+
+       php_ion_globals_serializer_step();
+
+       /* start off with a global PHP annotation instead of repeating it all over the place */
+       ION_STRING is;
+       ION_CHECK(ion_writer_add_annotation(obj->writer, ion_string_from_cstr(&is, ZEND_STRL("PHP"))));
+
+       php_ion_serialize_zval(obj, zv);
+
+       /* make sure to flush when done, else str.s might not contain everything until the writer is closed */
+       ion_writer_flush(obj->writer, NULL);
+       RETVAL_STR_COPY(obj->buffer.str.s);
+
+       php_ion_globals_serializer_exit();
+
+       zval_ptr_dtor(&zwriter);
+}
+
+static inline void php_ion_unserialize_zval(php_ion_reader *obj, zval *return_value);
+
+static inline bool can_call_magic_unserialize(php_ion_reader *obj, zend_class_entry *ce)
+{
+       if (ce->__unserialize && obj->php.call_magic_unserialize) {
+               return true;
+       }
+       return false;
+}
+
+static inline bool can_call_iface_unserialize(php_ion_reader *obj, zend_class_entry *ce)
+{
+       return !!ce->unserialize;
+}
+
+static inline bool can_call_custom_unserialize(php_ion_reader *obj, zend_object *zobject, zend_function **fn)
+{
+       if (obj->php.custom_unserialize) {
+               return !!((*fn = zend_hash_find_ptr(&zobject->ce->function_table, obj->php.custom_unserialize)));
+       }
+       return false;
+}
+
+static inline zval *php_ion_unserialize_class(php_ion_reader *obj, zend_string *class_name, zval *return_value)
+{
+       zend_class_entry *ce = zend_lookup_class(class_name);
+
+       if (ce) {
+               object_init_ex(return_value, ce);
+               return zend_hash_next_index_insert(&php_ion_globals.unserializer.ids, return_value);
+       }
+
+       zend_throw_exception_ex(spl_ce_RuntimeException, IERR_IMPORT_NOT_FOUND,
+                       "Could not find class %s", class_name->val);
+       return NULL;
+}
+
+static inline void php_ion_unserialize_object_iface(php_ion_reader *obj, zend_string *class_name, zval *return_value)
+{
+       ZEND_ASSERT(Z_TYPE_P(return_value) == IS_STRING);
+       zend_string *s = Z_STR_P(return_value);
+
+       zval *backref = php_ion_unserialize_class(obj, class_name, return_value);
+       ION_CATCH();
+
+       zend_class_entry *ce = Z_OBJCE_P(return_value);
+       if (can_call_iface_unserialize(obj, ce)) {
+               if (SUCCESS == ce->unserialize(backref, ce, (BYTE *) s->val, s->len, NULL)) {
+                       // remove all this Serializable crap in PHP-9
+                       zval_ptr_dtor(return_value);
+                       ZVAL_COPY_VALUE(return_value, backref);
+               } else if (!EG(exception)) {
+                       zend_throw_exception_ex(spl_ce_UnexpectedValueException, IERR_INTERNAL_ERROR,
+                                       "Failed to unserialize class %s", ce->name->val);
+               }
+       } else {
+               zend_throw_exception_ex(spl_ce_RuntimeException, IERR_INVALID_TOKEN,
+                               "Class %s does not implement Serializable", class_name->val);
+       }
+
+       zend_string_release(s);
+}
+
+static inline void php_ion_unserialize_hash(php_ion_reader *obj, zval *return_value)
+{
+       ION_CHECK(ion_reader_step_in(obj->reader));
+
+       ION_TYPE typ;
+       while (true) {
+               ION_CHECK(ion_reader_next(obj->reader, &typ));
+
+               if (typ == tid_EOF) {
+                       break;
+               }
+
+               ION_STRING name;
+               ION_CHECK(ion_reader_get_field_name(obj->reader, &name));
+
+               zend_string *zkey = zend_string_from_ion(&name);
+               zval *zvalue = zend_hash_add_empty_element(HASH_OF(return_value), zkey);
+               php_ion_unserialize_zval(obj, zvalue);
+               zend_string_release(zkey);
+               ION_CATCH();
+       }
+
+       ION_CHECK(ion_reader_step_out(obj->reader));
+}
+
+static inline void php_ion_unserialize_object_magic(php_ion_reader *obj, zend_string *class_name, bool custom, zval *return_value)
+{
+       php_ion_unserialize_class(obj, class_name, return_value);
+       ION_CATCH();
+
+       zend_object *zobject = Z_OBJ_P(return_value);
+       zend_function *fn = NULL;
+       if (custom) {
+               if (!can_call_custom_unserialize(obj, Z_OBJ_P(return_value), &fn)) {
+                       zend_throw_exception_ex(spl_ce_RuntimeException, IERR_INVALID_TOKEN,
+                                       "Could not find custom serializer method of %s", class_name->val);
+                       return;
+               }
+       } else {
+               if (!can_call_magic_unserialize(obj, zobject->ce)) {
+                       zend_throw_exception_ex(spl_ce_RuntimeException, IERR_INVALID_TOKEN,
+                                       "Could not find method %s::__serialize()", class_name->val);
+               }
+       }
+
+       zval sv;
+       array_init(&sv);
+       php_ion_unserialize_hash(obj, &sv);
+       ION_CATCH(zval_ptr_dtor(&sv));
+
+       zval rv;
+       ZVAL_NULL(&rv);
+       zend_call_method_with_1_params(zobject, zobject->ce, fn ? &fn : &zobject->ce->__serialize, "", &rv, &sv);
+       zval_ptr_dtor(&rv);
+       zval_ptr_dtor(&sv);
+}
+
+static inline void php_ion_unserialize_object_of_class(php_ion_reader *obj, uint8_t object_type, zend_string *class_name, zval *return_value)
+{
+       switch (object_type) {
+       case 'S':
+               php_ion_unserialize_object_iface(obj, class_name, return_value);
+               break;
+
+       case 'C':
+               php_ion_unserialize_object_magic(obj, class_name, true, return_value);
+               break;
+
+       case 'O':
+               php_ion_unserialize_object_magic(obj, class_name, false, return_value);
+               break;
+
+       default:
+               zend_throw_exception_ex(spl_ce_RuntimeException, IERR_INVALID_TOKEN,
+                               "Invalid object type %c", object_type);
+       }
+}
+
+static inline void php_ion_unserialize_struct(php_ion_reader *obj, uint8_t object_type, zend_string *class_name, zval *return_value)
+{
+       if (class_name) {
+               php_ion_unserialize_object_of_class(obj, object_type, class_name, return_value);
+       } else if (!object_type) {
+               array_init(return_value);
+               zend_hash_next_index_insert(&php_ion_globals.unserializer.ids, return_value);
+               php_ion_unserialize_hash(obj, return_value);
+       } else if (object_type == 'o') {
+               object_init(return_value);
+               zend_hash_next_index_insert(&php_ion_globals.unserializer.ids, return_value);
+               php_ion_unserialize_hash(obj, return_value);
+       } else {
+               zend_throw_exception_ex(spl_ce_RuntimeException, IERR_INVALID_TOKEN,
+                               "Invalid object type %c", object_type);
+       }
+}
+
+static inline void php_ion_unserialize_list(php_ion_reader *obj, zval *return_value)
+{
+       ION_CHECK(ion_reader_step_in(obj->reader));
+       array_init(return_value);
+       zend_hash_next_index_insert(&php_ion_globals.unserializer.ids, return_value);
+
+       ION_TYPE typ;
+       HashTable *ht = Z_ARRVAL_P(return_value);
+       while (true) {
+               zval next;
+               php_ion_unserialize_zval(obj, &next);
+               ION_CATCH();
+
+               ION_CHECK(ion_reader_get_type(obj->reader, &typ));
+               if (typ == tid_EOF) {
+                       break;
+               }
+
+               zend_hash_next_index_insert(ht, &next);
+       }
+
+       ION_CHECK(ion_reader_step_out(obj->reader));
+}
+
+static inline void php_ion_unserialize_lob(php_ion_reader *obj, zval *return_value)
+{
+       zend_string *zstr = zend_string_alloc(0x1000, 0);
+again:
+       SIZE read = 0;
+       iERR err = ion_reader_read_lob_bytes(obj->reader, (BYTE *) zstr->val, zstr->len, &read);
+       if (err == IERR_BUFFER_TOO_SMALL) {
+               zstr = zend_string_extend(zstr, zstr->len << 2, 0);
+               goto again;
+       }
+       ION_CHECK(err, zend_string_release(zstr));
+       if (zstr->len > read) {
+               zstr = zend_string_truncate(zstr, read, 0);
+       }
+       RETURN_STR(zstr);
+}
+
+static inline void php_ion_unserialize_timestamp(php_ion_reader *obj, zval *return_value)
+{
+       ION_TIMESTAMP ts;
+       ION_CHECK(ion_reader_read_timestamp(obj->reader, &ts));
+
+       decContext *ctx = NULL;
+       if (obj->opt) {
+               ctx = php_ion_obj(reader_options, obj->opt)->opt.decimal_context;
+       }
+
+       object_init_ex(return_value, ce_Timestamp);
+       php_ion_timestamp *ts_obj = php_ion_obj(timestamp, Z_OBJ_P(return_value));
+
+       zend_string *fmt = NULL;
+       ts_obj->time = php_time_from_ion(&ts, ctx, &fmt);
+       php_ion_timestamp_ctor(ts_obj, ts.precision, fmt, NULL, NULL);
+       zend_string_release(fmt);
+
+       OBJ_CHECK(ts_obj);
+}
+
+static inline void php_ion_unserialize_int(php_ion_reader *obj, zval *return_value)
+{
+       ION_INT *num = NULL;
+       ION_CHECK(ion_int_alloc(obj->reader, &num));
+       ION_CHECK(ion_reader_read_ion_int(obj->reader, num));
+
+       // TODO: SIZEOF_ZEND_LONG == 4
+       int64_t i64;
+       iERR err = ion_int_to_int64(num, &i64);
+       switch (err) {
+       case IERR_OK:
+               RETVAL_LONG(i64);
+               goto done;
+
+       case IERR_NUMERIC_OVERFLOW:
+               SIZE max, len;
+               ION_CHECK(ion_int_char_length(num, &max));
+               zend_string *zs = zend_string_alloc(max-1, 0);
+
+               err = ion_int_to_char(num, (BYTE *) zs->val, max, &len);
+               ZEND_ASSERT(len == zs->len);
+               RETVAL_STR(zs);
+               /* fall through */
+
+       default:
+       done:
+               ion_int_free(num);
+               ION_CHECK(err);
+       }
+}
+
+static inline void php_ion_unserialize_backref(php_ion_reader *obj, zval *return_value)
+{
+       php_ion_global_unserializer *u = &php_ion_globals.unserializer;
+       zval *backref = zend_hash_index_find(&u->ids, Z_LVAL_P(return_value));
+
+       if (backref) {
+               ZVAL_COPY(return_value, backref);
+       } else {
+               zend_throw_exception_ex(spl_ce_RuntimeException, IERR_INTERNAL_ERROR,
+                               "Could not find backref %ld", Z_LVAL_P(return_value));
+       }
+}
+
+static inline void php_ion_unserialize_zval(php_ion_reader *obj, zval *return_value)
+{
+       ION_TYPE typ;
+       ION_CHECK(ion_reader_next(obj->reader, &typ));
+
+#define next_annotation() do { \
+       if (ann_count) { \
+               --ann_count; \
+               ION_CHECK(ion_reader_get_an_annotation(obj->reader, ann_index++, &annotation)); \
+       } \
+} while (0)
+#define has_annotation(a) (has_annotations && annotation.length == 1 && annotation.value[0] == a)
+
+       BOOL has_annotations;
+       int32_t ann_index = 0, ann_count = 0;
+       ION_STRING annotation = {0};
+       ION_CHECK(ion_reader_has_any_annotations(obj->reader, &has_annotations));
+       if (has_annotations) {
+               ION_CHECK(ion_reader_get_annotation_count(obj->reader, &ann_count));
+               next_annotation();
+       }
+
+       if (has_annotation('r')) {
+               // BACKREF
+               php_ion_unserialize_int(obj, return_value);
+               ION_CATCH();
+               php_ion_unserialize_backref(obj, return_value);
+               ION_CATCH();
+               return;
+       }
+
+       if (has_annotation('R')) {
+               // REFERENCE
+               ZVAL_MAKE_REF(return_value);
+               ZVAL_DEREF(return_value);
+               next_annotation();
+       }
+
+       BOOL bval;
+       ION_CHECK(ion_reader_is_null(obj->reader, &bval));
+       if (bval) {
+               goto read_null;
+       }
+
+       switch (ION_TYPE_INT(typ)) {
+       case tid_NULL_INT:
+       read_null: ;
+               ION_CHECK(ion_reader_read_null(obj->reader, &typ));
+               RETURN_NULL();
+
+       case tid_BOOL_INT:
+               ION_CHECK(ion_reader_read_bool(obj->reader, &bval));
+               RETURN_BOOL(bval);
+
+       case tid_INT_INT:
+               php_ion_unserialize_int(obj, return_value);
+               return;
+
+       case tid_FLOAT_INT:
+               ION_CHECK(ion_reader_read_double(obj->reader, &Z_DVAL_P(return_value)));
+               return;
+
+       case tid_DECIMAL_INT:
+               object_init_ex(return_value, ce_Decimal);
+               php_ion_decimal *dec = php_ion_obj(decimal, Z_OBJ_P(return_value));
+               ION_CHECK(ion_reader_read_ion_decimal(obj->reader, &dec->dec));
+               php_ion_decimal_ctor(dec);
+               zend_hash_next_index_insert(&php_ion_globals.unserializer.ids, return_value);
+               return;
+
+       case tid_TIMESTAMP_INT:
+               php_ion_unserialize_timestamp(obj, return_value);
+               zend_hash_next_index_insert(&php_ion_globals.unserializer.ids, return_value);
+               return;
+
+       case tid_SYMBOL_INT:
+               ION_SYMBOL sym;
+               ION_CHECK(ion_reader_read_ion_symbol(obj->reader, &sym));
+               php_ion_symbol_zval(&sym, return_value);
+               zend_hash_next_index_insert(&php_ion_globals.unserializer.ids, return_value);
+               return;
+
+       case tid_STRING_INT:
+               ION_STRING str;
+               ION_CHECK(ion_reader_read_string(obj->reader, &str));
+               RETVAL_STRINGL((char *) str.value, str.length);
+               if (has_annotation('S')) {
+                       goto serializable;
+               }
+               zend_hash_next_index_insert(&php_ion_globals.unserializer.ids, return_value);
+               return;
+
+       case tid_CLOB_INT:
+       case tid_BLOB_INT:
+               php_ion_unserialize_lob(obj, return_value);
+               if (has_annotation('S')) {
+                       goto serializable;
+               }
+               zend_hash_next_index_insert(&php_ion_globals.unserializer.ids, return_value);
+               return;
+
+       case tid_LIST_INT:
+       case tid_SEXP_INT: // FIXME
+               php_ion_unserialize_list(obj, return_value);
+               return;
+
+       case tid_STRUCT_INT:
+       serializable: ;
+               zend_string *class_name = NULL;
+               uint8_t object_type = annotation.length == 1 ? annotation.value[0] : 0;
+               if (object_type && object_type != 'o') {
+                       next_annotation();
+                       class_name = zend_string_from_ion(&annotation);
+               }
+               php_ion_unserialize_struct(obj, object_type, class_name, return_value);
+               if (class_name) {
+                       zend_string_release(class_name);
+               }
+               return;
+
+       case tid_none_INT:
+               ZEND_ASSERT(0);
+               break;
+
+       case tid_DATAGRAM_INT:
+       case tid_EOF_INT:
+               return;
+       }
+}
+
+void php_ion_unserialize(php_ion_reader *obj, zend_string *zstr, zval *return_value)
+{
+       zval zreader;
+
+       if (obj) {
+               ZVAL_OBJ_COPY(&zreader, &obj->std);
+       } else {
+               object_init_ex(&zreader, ce_Reader_Buffer_Reader);
+               obj = php_ion_obj(reader, Z_OBJ(zreader));
+               obj->type = BUFFER_READER;
+               obj->buffer = zend_string_copy(zstr);
+               php_ion_reader_ctor(obj);
+       }
+
+       php_ion_globals_serializer_step();
+       php_ion_unserialize_zval(obj, return_value);
+       php_ion_globals_serializer_exit();
+
+       zval_ptr_dtor(&zreader);
+}
diff --git a/php_ion.h b/php_ion.h
new file mode 100644 (file)
index 0000000..e1e158e
--- /dev/null
+++ b/php_ion.h
@@ -0,0 +1,27 @@
+/*
+    +--------------------------------------------------------------------+
+    | PECL :: ion                                                        |
+    +--------------------------------------------------------------------+
+    | Redistribution and use in source and binary forms, with or without |
+    | modification, are permitted provided that the conditions mentioned |
+    | in the accompanying LICENSE file are met.                          |
+    +--------------------------------------------------------------------+
+    | Copyright (c) 2021, Michael Wallner <mike@php.net>                 |
+    +--------------------------------------------------------------------+
+*/
+
+#ifndef PHP_ION_H
+# define PHP_ION_H
+
+extern zend_module_entry ion_module_entry;
+# define phpext_ion_ptr &ion_module_entry
+
+# define PHP_ION_VERSION "0.1.0"
+
+# if defined(ZTS) && defined(COMPILE_DL_ION)
+ZEND_TSRMLS_CACHE_EXTERN()
+# endif
+
+#define SUCCESS 0
+
+#endif /* PHP_ION_H */