=head1 NAME

XS::Framework::Manual::SVAPI::Sub - XS::Framework Sub C++ class reference

=head1 Sub

=head2 Overview

C<Sub> is C++ wrapper around callable Perl subroutine. It inherits all methods
from C<Sv> and disables a few ones, which have no sense for the class, e.g.
construction of C<Sub> object from array C<AV*> or coercion to C<AV*>.

As the C<Sv> it might hold the underlying Perl C<SV*> or may not.

=head2 Construction

    static Sub noinc (SV* val)
    static Sub noinc (CV* val)

    Sub (std::nullptr_t = nullptr) {}
    Sub (SV* sv, bool policy = INCREMENT)
    Sub (CV* sv, bool policy = INCREMENT)

The C<Sub> object can be constructed either from Perl C<CV*> or from C<SV*>, which
is perl subroutine pointer. If the supplied C<SV*>/C<SV*> points to C<NULL> or
C<undef>, then the object will held NULL. Otherwise, on all other invalid C<SV*>
an exception will be thrown. The valid C<SV*> should be either C<CV*> or
reference to C<CV*> or C<undef>.

    explicit Sub (panda::string_view subname, I32 flags = 0)

The Perl subroutine reference can be get via string literal, please refer
C<get_cvn_flags> in L<perlapi>. In other words, if the named Perl subroutine
C<subname> is found, than non-empty C<Sub> object will be created, e.g.

    Sub sub("MyPackage::my_fun");

Copy and move-constructors are also available:

    Sub (const Sub& oth)
    Sub (Sub&& oth)
    Sub (const Sv& oth)
    Sub (Sv&& oth)

=head2 assignment operators

    Sub& operator= (SV* val)
    Sub& operator= (CV* val)
    Sub& operator= (const Sub& oth)
    Sub& operator= (Sub&& oth)
    Sub& operator= (const Sv& oth)
    Sub& operator= (Sv&& oth)

The assignment operators are complementaty to the constructors above. They
inherit behaviour from C<Sv>, including NULL-safety. The previously held
C<SV*> will be C<dec>-remented.

    void set (SV* val)

The C<set> method directly assigns the value to the underlying C<SV*>,
I<bypassing all checks>. Use the method with caution.

=head2 getters

Theere are zero-cost NULL-safe getters:

    CV* operator-> () const
    template <typename T = SV> one_of_t<T,SV,CV>* get () const

This are NULL-safe methods.

=head2 stash()

    Stash stash () const

Returns stash object, i.e. package / symbol table, where underlying subroutine
belongs to. This is NULL-unsafe method.

=head2 glob()

    Glob  glob  () const;

Returns glob object. This is NULL-unsafe method.

=head2 name()

    panda::string_view name () const;

Returns subroutine name. This is NULL-unsafe method.

=head2 bool named()

    bool named () const

Returns C<true> if the underlying subroutine points to named subrouitene, and
C<false> for anonymous one. This is NULL-unsafe method.

=head2 SUPER ()

=head2 SUPER_strict ()


    Sub SUPER () const
    Sub SUPER_strict () const

This methods return C<Sub> object, which represends the same subroutine but for
base class of the current one. They differ in behaviour, when the SUPER
subroutine cannot be found. The C<SUPER()> method just returns empty C<Sub>,
while C<SUPER_strict()> throwns exception.

The method resolution is performed via C<DFS> algorithm (see L<mro>).

This are NULL-unsafe methods.

=head2 call()

=head2 operator()

    template <class...Ctx, class...Args>
    *depends* call (Args&&...args) const
    
    template <class...Ctx, class...Args>
    *depends* operator() (Args&&...args) const

This methods calls perl subroutine. Here are a few examples:

    Sub sub = ...;
    // invoked in scalar context
    Scalar p1 = sub.call();
    Scalar p2 = sub.call(Simple(123));

    Simple arg1(1), arg2(2), arg3(3);
    // scalar context, array ref expected
    Array p3 = sub(arg1, arg2, arg3);

    // invoked in void context
    sub.call<void>(Simple(2), Scalar(Simple(3)), Sv(Simple(4)));
    
    //invoked in list context
    List list = sub.call<List>(arg1, arg2);
    
=head3 Supported argument types

=over

=item Variadic number of any type that is convertible to SV* (any svapi type, pure SV*, etc)

If any of arguments represents non-scalar value (pure array, pure hash, etc), an exception will be thrown

=item std::initializer_list<Scalar>

Only explicitly specified, as template argument deduction can't decude initializer list constructor type

    sub.call(std::initializer_list<Scalar>{ arg1, arg2 }); // well-formed
    std::initializer_list<Scalar> l{ arg1, arg2 };
    sub.call(l);                                           // well-formed
    sub.call({ arg1, arg2 });                              // ill-formed
    
=item SV* arg0, std::initializer_list<Scalar> list

C<arg0> is prepended before C<list>. Useful for proxy-method that adds one arguments in the beginning

=item SV*const* list, size_t items

Useful when proxying calls from XS functions

    void some_xs_func () {
        ...
        sub.call(&ST(0), items);
    }
    
=item SV* arg0, SV*const* list, size_t items

Same as previous, but adds C<arg0> before list. Useful when proxying calls from XS functions

    void some_xs_func () {
        ...
        sub.call(obj, &ST(0), items);
    }
    
=item const Scalar* list, size_t items

=item SV* arg0, const Scalar* list, size_t items

same as previous ones

=back

=head3 Return type / call context

Return type of the call is specified as one or more template parameters for C<call()> function. Sub will be called in corresponding context.

    sub.call<void>();
    sub.call<Scalar>(); // same as sub.call()
    sub.call<List>();
    // ... etc
    
List of supported context template parameters in format "template params, sub.call() return type, perl sub call context":

=over

=item <void>, void, G_VOID

Anything that sub returns is discarded

=item <> or <Scalar>, Scalar, G_SCALAR

Any scalar expected

=item <Sv>, Sv, G_SCALAR

Any scalar expected

=item <Simple>, Simple, G_SCALAR

Sub is expected to return perl primitive (number or string). If returned value is not a primitive, exception is thrown.
The same applies for svapi types listed below.

=item <Ref>, Ref, G_SCALAR

Any reference expected

=item <Array>, Array, G_SCALAR

Array ref expected

=item <Hash>, Hash, G_SCALAR

Hash ref expected

=item <Stash>, Stash, G_SCALAR

Stash(class) ref expected

=item <Object>, Object, G_SCALAR

Object (blessed reference of any kind) expected

=item <Sub>, Sub, G_SCALAR

Subroutine reference expected

=item <Glob>, Glob, G_SCALAR

Glob or reference to glob expected

=item <List>, List, G_ARRAY

Any number of any types expected. List contains all the returned values.

    auto list = sub.call<List>();
    for (auto& val : list) { ... }

=item <std::array<T,N>>, std::array<T,N>, G_ARRAY

C<T> may be any type of svapi. Expected C<N> return values of type C<T>.
If sub returns more than C<N> values, extra values are discarded.
If sub returns less than C<N> values, then remaining are returned as C<undefs>.

    auto arr = sub.call<std::array<Simple, 3>>(args);
    for (auto elem : arr) cout << (int)elem << endl;

=item <T1, T2, ...> or <std::tuple<T1, T2, ...>, std::tuple<T1, T2, ...>, G_ARRAY

C<Tx> may be any type of svapi. Expected C<N = count of Tx> return values of various Tx(T1, T2, ...) types.
If sub returns more than C<N> values, extra values are discarded.
If sub returns less than C<N> values, then remaining are returned as C<undefs>.

    auto ret = sub.call<Simple, Array, Hash>(args);
    auto simple = std::get<0>(ret);
    auto arr    = std::get<1>(ret);
    auto hash   = std::get<2>(ret);
    
=item <panda::string>, panda::string, G_SCALAR

Primitive expected

    auto str = sub.call<string>();
    
=item <any numeric type>, that type, G_SCALAR

Primitive expected

    auto num = sub.call<long>();
    
=back

=head1 SEE ALSO

L<XS::Framework>

L<XS::Framework::Manual::SVAPI>

L<XS::Framework::Manual::SVAPI::Sv>

=cut
