#  You may distribute under the terms of either the GNU General Public License
#  or the Artistic License (the same terms as Perl itself)
#
#  (C) Paul Evans, 2023 -- leonerd@leonerd.org.uk

package Object::Pad::FieldAttr::Checked 0.01;

use v5.14;
use warnings;

use Object::Pad 0.66;

require XSLoader;
XSLoader::load( __PACKAGE__, our $VERSION );

=head1 NAME

C<Object::Pad::FieldAttr::Checked> - apply type constraint checks to C<Object::Pad> fields

=head1 SYNOPSIS

   TODO

=head1 DESCRIPTION

This module provides a third-party field attribute for L<Object::Pad>-based
classes, which declares that values assigned to the field must conform to a
given value constraint check.

B<WARNING> The ability for L<Object::Pad> to take third-party field attributes
is still new and highly experimental, and subject to much API change in
future. As a result, this module should be considered equally experimental.

=head1 FIELD ATTRIBUTES

=head2 :Checked

   field $name :Checked(EXPRESSION) ...;

Declares that any value assigned to the field must conform to the constraint
checking object specified by the expression. Attempts to assign a
non-conforming value will throw an exception and the field will not be
modified.

At compiletime, the string given by I<EXPRESSION> is C<eval()>'ed in scalar
context, and its result is stored as part of the field's definition. The value
of the expression must either be an object reference, or a string containing
the name of a package. In either case, a method called C<check> must exist on
it.

At runtime, this constraint checking value is used every time an attempt is
made to assign a new value to the field, whether that is from C<:param>
initialisation, invoking a C<:writer> or C<:mutator> accessor, or direct
assignment into the field variable by method code within the class. The
checker is used as the invocant for invoking a C<check> method, and the new
value for the field is passed as an argument. If the method returns true, the
assignment is allowed. If false, it is rejected with an exception and the
field itself remains unmodified.

   $ok = $checker->check( $value );

As this is the interface supported by L<Types::Standard>, any constraint
object provided by that module is already supported here.

   use Types::Standard qw( Str Num );

   field $name :Checked(Str);
   field $age  :Checked(Num);

=cut

sub import
{
   $^H{"Object::Pad::FieldAttr::Checked/Checked"}++;
}

sub unimport
{
   delete $^H{"Object::Pad::FieldAttr::Checked/Checked"};
}

=head1 TODO

=over 4

=item *

Consider caching the result of the C<check> method lookup.

=back

=head1 AUTHOR

Paul Evans <leonerd@leonerd.org.uk>

=cut

0x55AA;
