TYPEMAP
const unsigned char*	T_PV
hash_type	T_MAP_POINTER_TYPE
curve_type	T_MAP_INT_TYPE
ssl_version_type	T_MAP_INT_TYPE
br_error_type	T_MAP_INT_TYPE
usage_type	T_MAP_INT_TYPE
hash_oid_type	T_MAP_POINTER_TYPE
key_kind_type	T_MAP_INT_TYPE
Crypt::Bear::Hash	T_MAGICBUF
Crypt::Bear::HMAC::Key	T_OPAQUEOBJ
Crypt::Bear::HMAC	T_MAGICBUF
Crypt::Bear::PRNG	T_MAGICBUF
Crypt::Bear::HMAC::DRBG	T_MAGICBUF
Crypt::Bear::HKDF	T_MAGICBUF
Crypt::Bear::Shake	T_MAGICBUF
Crypt::Bear::AES_CTR::DRBG	T_MAGICBUF
Crypt::Bear::CBC::Enc	T_MAGICBUF
Crypt::Bear::CBC::Dec	T_MAGICBUF
Crypt::Bear::CTR	T_MAGICBUF
Crypt::Bear::CTRCBC	T_MAGICBUF
Crypt::Bear::AES_CBC::Enc	T_MAGICBUF
Crypt::Bear::AES_CBC::Dec	T_MAGICBUF
Crypt::Bear::AES_CTR	T_MAGICBUF
Crypt::Bear::AES_CTRCBC	T_MAGICBUF
Crypt::Bear::AEAD	T_MAGICBUF
Crypt::Bear::GCM	T_MAGICBUF
Crypt::Bear::EAX	T_MAGICBUF
Crypt::Bear::CCM	T_MAGICBUF
Crypt::Bear::RSA::PublicKey	T_MAGICEXT
Crypt::Bear::RSA::PrivateKey	T_MAGICEXT
Crypt::Bear::EC::PublicKey	T_MAGICEXT
Crypt::Bear::EC::PrivateKey	T_MAGICEXT
Crypt::Bear::PEM::Decoder	T_MAGICEXT
Crypt::Bear::X509::TrustAnchors	T_MAGICEXT
Crypt::Bear::X509::PrivateKey	T_MAGICEXT
Crypt::Bear::X509::Certificate	T_MAGICEXT
Crypt::Bear::X509::Certificate::Chain	T_MAGICEXT
Crypt::Bear::X509::Validator	T_MAGIC
Crypt::Bear::X509::Validator::Minimal	T_MAGIC
Crypt::Bear::X509::Validator::KnownKey	T_MAGIC
Crypt::Bear::SSL::PrivateCertificate	T_MAGICEXT
Crypt::Bear::SSL::Session	T_OPAQUEOBJ
Crypt::Bear::SSL::Engine	T_MAGICEXT_BASE
Crypt::Bear::SSL::Client	T_MAGICEXT
Crypt::Bear::SSL::Server	T_MAGICEXT

INPUT
T_MAP_POINTER_TYPE
	$var = (map_get(${\ (qq[$ntype] =~ s/_type$/s/r) }, $arg, \"${\ (qq[$ntype] =~ s/_type$//r) }\").pointer)
T_MAP_INT_TYPE
	$var = (map_get(${\ (qq[$ntype] =~ s/_type$/s/r) }, $arg, \"${\ (qq[$ntype] =~ s/_type$//r) }\").integer)
T_MAGIC
	{
	SV* arg = $arg;
	MAGIC* magic = SvROK(arg) && SvRMAGICAL(SvRV(arg)) ? mg_findext(SvRV(arg), PERL_MAGIC_ext, NULL) : NULL;
	if (magic)
		$var = ($type)magic->mg_ptr;
	else
		Perl_croak(aTHX_ \"%s object is lacking magic\", \"$ntype\");
	}

T_MAGICBUF
	{
	SV* arg = $arg;
	MAGIC* magic = SvROK(arg) && SvRMAGICAL(SvRV(arg)) ? mg_findext(SvRV(arg), PERL_MAGIC_ext, NULL) : NULL;
	if (magic)
		$var = ($type)magic->mg_ptr;
	else
		Perl_croak(aTHX_ \"%s object is lacking magic\", \"$ntype\");
	}

T_MAGICEXT
	{
	SV* arg = $arg;
	MAGIC* magic = SvROK(arg) && SvMAGICAL(SvRV(arg)) ? mg_findext(SvRV(arg), PERL_MAGIC_ext, &${type}_magic) : NULL;
	if (magic)
		$var = ($type)magic->mg_ptr;
	else
		Perl_croak(aTHX_ \"%s object is lacking magic\", \"$ntype\");
	}

T_MAGICEXT_BASE
	{
	SV* arg = $arg;
	MAGIC* magic = SvROK(arg) && SvMAGICAL(SvRV(arg)) ? mg_find(SvRV(arg), PERL_MAGIC_ext) : NULL;
	if (magic && magic->mg_virtual)
		$var = ($type)magic->mg_ptr;
	else
		Perl_croak(aTHX_ \"%s object is lacking magic\", \"$ntype\");
	}

T_OPAQUEOBJ
    {
		SV * sv = $arg;
		if (SvROK(sv) && SvPOK(SvRV(sv)) && SvCUR(SvRV(sv)) == sizeof(*$var))
			$var = ($type)SvPV_nolen(SvRV(sv));
		else
			croak(\"%s: %s is not of type %s\", ${$ALIAS?\q[GvNAME(CvGV(cv))]:\qq[\"$pname\"]}, \"$var\", \"$ntype\");
    }

T_OPAQUEOBJ_BASE
    {
		SV * sv = $arg;
		if (SvROK(sv) && SvPOK(SvRV(sv)) && sv_derived_from(sv, \"$ntype\"))
			$var = ($type)SvPV_nolen(SvRV(sv));
		else
			croak(\"%s: %s is not of type %s\", ${$ALIAS?\q[GvNAME(CvGV(cv))]:\qq[\"$pname\"]}, \"$var\", \"$ntype\");
    }

T_OPAQUEOBJ_MAYBE
	{
		SV * sv = $arg;
		if (SvOK(sv)) {
			if (SvROK(sv) && SvPOK(SvRV(sv)) && SvCUR(SvRV(sv)) == sizeof(*$var))
				$var = ($type)SvPV_nolen(SvRV(sv));
			else
				croak(\"%s: %s is not of type %s\", ${$ALIAS?\q[GvNAME(CvGV(cv))]:\qq[\"$pname\"]}, \"$var\", \"$ntype\");
		} else
			$var = NULL;
	}


OUTPUT
T_MAP_POINTER_TYPE
	STMT_START {
		union value value = { .pointer = $var };
		const entry* entry = map_reverse_find(${\ (qq[$ntype] =~ s/_type$/s/r) }, value);
		$arg = entry ? newSVpvn(entry->key, entry->length) : newSV(0);
	} STMT_END;
T_MAP_INT_TYPE
	STMT_START {
		union value value = { .integer = $var };
		const entry* entry = map_reverse_find(${\ (qq[$ntype] =~ s/_type$/s/r) }, value);
		$arg = entry ? newSVpvn(entry->key, entry->length) : newSV(0);
	} STMT_END;
T_MAGIC
	sv_magicext(newSVrv($arg, "$ntype"), NULL, PERL_MAGIC_ext, NULL, (const char*)$var, 0);
T_MAGICBUF
	{
	MAGIC* magic = sv_magicext(newSVrv($arg, "$ntype"), NULL, PERL_MAGIC_ext, NULL, (const char*)$var, 0);
	magic->mg_len = sizeof(*$var);
	}

T_MAGICEXT
	{
	MAGIC* magic = sv_magicext(newSVrv($arg, "$ntype"), NULL, PERL_MAGIC_ext, &${type}_magic, (const char*)$var, 0);
	magic->mg_flags |= MGf_COPY|MGf_DUP;
	}

T_OPAQUEOBJ
	{
		sv_usepvn(newSVrv($arg, \"$ntype\"), (char*)$var, sizeof(*$var));
		SvREADONLY_on(SvRV($arg));
	}

T_OPAQUEOBJ_MAYBE
	if (SvOK($var)) {
		sv_usepvn(newSVrv($arg, \"$ntype\"), (char*)$var, sizeof(*$var));
		SvREADONLY_on(SvRV($arg));
	}

