+} lt_op_padxv_info;
+
+STATIC const char lt_type_desc_scalar[] = "scalar";
+STATIC const char lt_type_desc_array[] = "array";
+STATIC const char lt_type_desc_hash[] = "hash";
+
+STATIC void lt_op_padxv_info_call(pTHX_ const lt_op_padxv_info *oi, SV *sv) {
+#define lt_op_padxv_info_call(O, S) lt_op_padxv_info_call(aTHX_ (O), (S))
+ SV *orig_pkg, *type_pkg, *type_meth;
+ svtype var_type;
+ int items;
+ dSP;
+
+ ENTER;
+ SAVETMPS;
+
+#ifdef MULTIPLICITY
+ {
+ STRLEN op_len = oi->orig_pkg_len, tp_len = oi->type_pkg_len;
+ char *buf = oi->buf;
+ orig_pkg = sv_2mortal(newSVpvn(buf, op_len));
+ SvREADONLY_on(orig_pkg);
+ buf += op_len;
+ type_pkg = sv_2mortal(newSVpvn(buf, tp_len));
+ SvREADONLY_on(type_pkg);
+ buf += tp_len;
+ type_meth = sv_2mortal(newSVpvn(buf, oi->type_meth_len));
+ SvREADONLY_on(type_meth);
+ }
+#else /* MULTIPLICITY */
+ orig_pkg = oi->orig_pkg;
+ type_pkg = oi->type_pkg;
+ type_meth = oi->type_meth;
+#endif /* !MULTIPLICITY */
+
+ PUSHMARK(SP);
+ EXTEND(SP, 3);
+ PUSHs(type_pkg);
+ var_type = SvTYPE(sv);
+ switch (var_type) {
+ case SVt_PVAV:
+ case SVt_PVHV:
+ PUSHs(sv_2mortal(newRV_inc(sv)));
+ break;
+ default:
+ PUSHs(sv);
+ break;
+ }
+ PUSHs(orig_pkg);
+ PUTBACK;
+
+ items = call_sv(type_meth, G_ARRAY | G_METHOD);
+
+ SPAGAIN;
+ switch (items) {
+ case 0:
+ break;
+ case 1: {
+ SV *rsv = POPs;
+ switch (var_type) {
+ case SVt_PVAV:
+ if (SvROK(rsv) && SvTYPE(SvRV(rsv)) == var_type) {
+ AV *av = (AV *) SvRV(rsv);
+ SV **src, **dst;
+ I32 len = av_len(av);
+ I32 i;
+ av_fill((AV *) sv, len);
+ src = AvARRAY(av);
+ dst = AvARRAY(sv);
+ for (i = 0; i <= len; ++i, ++src, ++dst) {
+ SvREFCNT_dec(*dst);
+ *dst = SvREFCNT_inc(*src);
+ }
+ } else {
+ goto type_mismatch;
+ }
+ break;
+ case SVt_PVHV:
+ if (SvROK(rsv) && SvTYPE(SvRV(rsv)) == var_type) {
+ HV *hv = (HV *) SvRV(rsv);
+ HE *he;
+ hv_iterinit(hv);
+ hv_clear((HV *) sv);
+ while ((he = hv_iternext(hv)) != NULL) {
+ SV *val = SvREFCNT_inc(HeVAL(he));
+ if (!hv_store((HV *) sv, HeKEY(he), HeKLEN(he), val, HeHASH(he)))
+ SvREFCNT_dec(val);
+ }
+ } else {
+ goto type_mismatch;
+ }
+ break;
+ default:
+ sv_setsv(sv, rsv);
+ break;
+ }
+ break;
+type_mismatch:
+ croak("Type mismatch");
+ }
+ default: {
+ const char *type_desc;
+ switch (var_type) {
+ case SVt_PVAV:
+ type_desc = lt_type_desc_array;
+ break;
+ case SVt_PVHV:
+ type_desc = lt_type_desc_hash;
+ break;
+ default:
+ type_desc = lt_type_desc_scalar;
+ break;
+ }
+ croak("Typed %s initializer method should return zero or one scalar, but got %d", type_desc, items);
+ }
+ }
+ PUTBACK;
+
+ FREETMPS;
+ LEAVE;
+
+ return;
+}