File Coverage

blib/lib/Data/Checks.pm
Criterion Covered Total %
statement 63 63 100.0
branch 1 2 50.0
condition n/a
subroutine 27 27 100.0
pod 19 19 100.0
total 110 111 99.1


line stmt bran cond sub pod time code
1             # You may distribute under the terms of either the GNU General Public License
2             # or the Artistic License (the same terms as Perl itself)
3             #
4             # (C) Paul Evans, 2024-2025 -- leonerd@leonerd.org.uk
5              
6             package Data::Checks 0.11;
7              
8 14     14   3660929 use v5.22;
  14         72  
9 14     14   115 use warnings;
  14         85  
  14         842  
10              
11 14     14   87 use Carp;
  14         24  
  14         1257  
12              
13 14     14   8844 use builtin qw( export_lexically );
  14         1871  
  14         715  
14 14     14   96 no warnings "experimental::builtin";
  14         34  
  14         19233  
15              
16             sub import
17             {
18 17     17   259431 shift;
19 17         63 my @syms = @_;
20              
21             # @EXPORT_OK is provided by XS code
22 17         1319 foreach my $sym ( @syms ) {
23 41 50       121 grep { $sym eq $_ } our @EXPORT_OK or
  820         1445  
24             croak "$sym is not exported by ".__PACKAGE__;
25              
26 41         719 export_lexically( $sym => \&$sym );
27             }
28             }
29              
30             require XSLoader;
31             XSLoader::load( __PACKAGE__, our $VERSION );
32              
33             =head1 NAME
34              
35             C - Value constraint checking
36              
37             =head1 SYNOPSIS
38              
39             With L:
40              
41             =for highlighter perl
42              
43             use v5.26;
44             use Sublike::Extended 0.29 'sub';
45             use Signature::Attribute::Checked;
46              
47             use Data::Checks qw( Str );
48              
49             sub greet ( $message :Checked(Str) ) {
50             say "Hello, $message";
51             }
52              
53             greet( "world" ); # is fine
54             greet( undef ); # throws an exception
55              
56             With L:
57              
58             use v5.22;
59             use Object::Pad;
60             use Object::Pad::FieldAttr::Checked;
61              
62             use Data::Checks qw( Str );
63              
64             class Datum {
65             field $name :param :reader :Checked(Str);
66             }
67              
68             my $x = Datum->new( name => "something" ); # is fine
69             my $y = Datum->new( name => undef ); # throws an exception
70              
71             With L on Perl v5.38 or later:
72              
73             use v5.38;
74             use Syntax::Operator::Is;
75              
76             use Data::Checks qw( Num Object );
77              
78             my $x = ...;
79              
80             if($x is Num) {
81             say "x can be used as a number";
82             }
83             elsif($x is Object) {
84             say "x can be used as an object";
85             }
86              
87             =head1 DESCRIPTION
88              
89             This module provides functions that implement various value constraint
90             checking behaviours. These are the parts made visible by the
91             C import line, in Perl code.
92              
93             It also provides the underlying common framework XS functions to assist in
94             writing modules that actually implement such constraint checking. These parts
95             are not visible in Perl code, but instead made visible at the XS level by the
96             C<#include "DataChecks.h"> directive.
97              
98             See the L section above for several examples of other CPAN modules
99             that make direct use of these constraint checks.
100              
101             =cut
102              
103             =head1 CONSTRAINTS
104              
105             The following constraint checks are inspired by the same-named ones in
106             L. They may be called fully-qualified, or imported
107             I into the calling scope.
108              
109             B to users familiar with C: some of these functions
110             behave slightly differently. In particular, these constraints are generally
111             happy to accept an object reference to a class that provides a conversion
112             overload, whereas the ones in C often are not. Additionally
113             functions that are parametric take their parameters in normal Perl function
114             argument lists, not wrapped in additional array references.
115              
116             =head2 Defined
117              
118             Defined()
119              
120             Accepts any defined value, rejects only C.
121              
122             =head2 Object
123              
124             Object()
125              
126             Accepts any blessed object reference, rejects non-references or references to
127             unblessed data.
128              
129             =head2 Str
130              
131             Str()
132              
133             Accepts any defined non-reference value, or a reference to an object in a
134             class that overloads stringification. Rejects undefined, unblessed references,
135             or references to objects in classes that do not overload stringification.
136              
137             =head2 StrEq
138              
139             StrEq($s)
140             StrEq($s1, $s2, ...)
141              
142             I
143              
144             Accepts any value that passes the L check, and additionally is exactly
145             equal to I the given strings.
146              
147             =head2 StrMatch
148              
149             StrMatch(qr/pattern/)
150              
151             I
152              
153             Accepts any value that passes the L check, and additionally matches the
154             given regexp pattern.
155              
156             Remember that the pattern must be supplied as a C expression, not
157             simply C or C.
158              
159             =head2 Num
160              
161             Num()
162              
163             Accepts any defined non-reference value that is either a plain number, or a
164             string that could be used as one without warning, or a reference to an object
165             in a class that overloads numification.
166              
167             Rejects undefined, not-a-number, strings that would raise a warning if
168             converted to a number, unblessed references, or references to objects in
169             classes that do not overload numification.
170              
171             =head2 NumGT
172              
173             =head2 NumGE
174              
175             =head2 NumLE
176              
177             =head2 NumLT
178              
179             NumGT($bound)
180             NumGE($bound)
181             NumLE($bound)
182             NumLT($bound)
183              
184             I
185              
186             Accepts any value that passes the L check, and additionally is within
187             the bound given. C and C exclude the bound value itself,
188             C and C include it.
189              
190             =head2 NumRange
191              
192             NumRange($boundge, $boundlt)
193              
194             I
195              
196             Accepts any value that passes the L check, and additionally is between
197             the two bounds given. The lower bound is inclusive, and the upper bound is
198             exclusive.
199              
200             This choice is made so that a set of C constraints can easily be
201             created that cover distinct sets of numbers:
202              
203             NumRange(0, 10), NumRange(10, 20), NumRange(20, 30), ...
204              
205             To implement checks with both lower and upper bounds but other kinds of
206             inclusivity, use two C checks combined with an C. For example,
207             to test between 0 and 100 inclusive at both ends:
208              
209             All(NumGE(0), NumLE(100))
210              
211             Combinations like this are internally implemented as efficiently as a single
212             C constraint.
213              
214             =head2 NumEq
215              
216             NumEq($n)
217             NumEq($n1, $n2, ...)
218              
219             I
220              
221             Accepts any value that passes the L check, and additionally is exactly
222             equal to I the given numbers.
223              
224             =head2 Isa
225              
226             Isa($classname)
227              
228             I
229              
230             Accepts any blessed object reference to an instance of the given class name,
231             or a subclass derived from it (i.e. anything accepted by the C operator).
232              
233             =head2 Can
234              
235             Can($methodname)
236             Can($methodname1, $methodname2, ...)
237              
238             I
239              
240             Accepts any blessed object reference to an instance in a class, or a class
241             name directly, that has the all of the given method names (i.e. anything that
242             passes a C<< ->can >> test on every name).
243              
244             To accept only object references and not package names, combine this check
245             with C by using the C combination:
246              
247             All(Object, Can($methodname, ...))
248              
249             =head2 ArrayRef
250              
251             ArrayRef()
252              
253             I
254              
255             Accepts any plain reference to an array, or any object reference to an
256             instance of a class that provides an array dereference overload.
257              
258             =head2 HashRef
259              
260             HashRef()
261              
262             I
263              
264             Accepts any plain reference to a hash, or any object reference to an instance
265             of a class that provides a hash dereference overload.
266              
267             =head2 Callable
268              
269             Callable()
270              
271             I
272              
273             Accepts any plain reference to a subroutine, or any object reference to an
274             instance of a class that provides a subroutine dereference overload.
275              
276             =head2 Maybe
277              
278             Maybe($C)
279              
280             I
281              
282             Accepts C in addition to anything else accepted by the given
283             constraint.
284              
285             =head2 Any
286              
287             Any($C1, $C2, ...)
288              
289             I
290              
291             Accepts a value that is accepted by at least one of the given constraints.
292             Rejects if none of them accept it.
293              
294             At least one constraint is required; it is an error to try to call C
295             with no arguments. If you need a constraint that accepts any value at all, see
296             L.
297              
298             $C1 | $C2 | ...
299              
300             I
301              
302             This function is used to implement C<|> operator overloading, so constraint
303             checks can be written using this more convenient syntax.
304              
305             =head2 All
306              
307             All($C1, $C2, ...)
308             All()
309              
310             I
311              
312             Accepts a value that is accepted by every one of the given constraints.
313             Rejects if at least one of them rejects it.
314              
315             Note that if no constraints are given, this accepts all possible values. This
316             may be useful as an "accept-all" fallback case for generated code, or other
317             situations where it is required to provide a constraint check but you do not
318             wish to constraint allowed values.
319              
320             =head1 CONSTRAINT METHODS
321              
322             While not intended to be called from regular Perl code, these constraints
323             still act like objects with the following methods.
324              
325             =head2 check
326              
327             $ok = $constraint->check( $value );
328              
329             I
330              
331             Returns a boolean value indicating whether the constraint accepts the given
332             value.
333              
334             =cut
335              
336             {
337             package # hide from indexer
338             Data::Checks::Constraint;
339              
340             use overload
341 14     14   131 '|' => sub { my ( $lhs, $rhs ) = @_; return Data::Checks::Any( $lhs, $rhs ) };
  14     3   34  
  14         190  
  3         14  
  3         7  
342             # For now we won't support or encourage & to mean All() because parsing
343             # of expressions like `Str & Object` doesn't actually work properly.
344             }
345              
346             =head1 XS FUNCTIONS
347              
348             The following functions are provided by the F header file for
349             use in XS modules that implement value constraint checking.
350              
351             =for highlighter c
352              
353             =head2 boot_data_checks
354              
355             void boot_data_checks(double ver);
356              
357             Call this function from your C section in order to initialise the module
358             and load the rest of the support functions.
359              
360             I should either be 0 or a decimal number for the module version
361             requirement; e.g.
362              
363             boot_data_checks(0.01);
364              
365             =head2 make_checkdata
366              
367             struct DataChecks_Checker *make_checkdata(SV *checkspec);
368              
369             Creates a C structure, which wraps the intent of
370             the value constraint check. The returned value is used as the I
371             argument for the remaining functions.
372              
373             The constraint check itself is specified by the C given by I,
374             which should come directly from the user code. The constraint check may be
375             specified in any of three ways:
376              
377             =for highlighter perl
378              
379             =over 4
380              
381             =item *
382              
383             An B reference in a class which has a C method. Value checks
384             will be invoked as
385              
386             $ok = $checkerobj->check( $value );
387              
388             =item *
389              
390             A B name as a plain string of a package which has a C method.
391             Value checks will be invoked as
392              
393             $ok = $checkerpkg->check( $value );
394              
395             =item *
396              
397             A B. Value checks will be invoked with a single argument, as
398              
399             $ok = $checkersub->( $value );
400              
401             I this form is now deprecated, because it does not easily
402             support a way to query the constraint for its name or stringified form, which
403             is useful when generating error messages.
404              
405             =item *
406              
407             Additionally, the constraint check functions provided by this module may be
408             implemented using any of the above mechanisms, or may use an unspecified
409             fourth different mechanism. Outside code should not rely on what that
410             mechanism may be.
411              
412             =back
413              
414             =for highlighter c
415              
416             Once constructed into a checker structure, the choice of which implementation
417             is used is fixed, and if a method lookup is involved its result is stored
418             directly as a CV pointer for efficiency of later invocations. In either of the
419             first two cases, the reference count on the I SV is increased to
420             account for the argument value used on each invocation. In the third case, the
421             reference SV is not retained, but the underlying CV it refers to has its
422             reference count increased.
423              
424             =head2 free_checkdata
425              
426             void free_checkdata(struct DataChecks_Checker *checker);
427              
428             Releases any stored SVs in the checker structure, and the structure itself.
429              
430             =head2 gen_assertmess
431              
432             void gen_assertmess(struct DataChecks_Checker *checker, SV *name, SV *constraint);
433              
434             Generates and stores a message string for the assert message to be used by
435             L and L. The message will take the form
436              
437             =for highlighter
438              
439             NAME requires a value satisfying CONSTRAINT
440              
441             =for highlighter c
442              
443             Both I and I SVs used as temporary strings to generate the
444             stored message string. Neither SV is retained by the checker directly.
445              
446             =head2 make_assertop
447              
448             OP *make_assertop(struct DataChecks_Checker *checker, OP *argop);
449              
450             Shortcut to calling L with I set to zero.
451              
452             =head2 make_assertop_flags
453              
454             OP *make_assertop_flags(struct DataChecks_Checker *checker, U32 flags, OP *argop);
455              
456             Creates an optree fragment for a value check assertion operation.
457              
458             Given an optree fragment in scalar context that generates an argument value
459             (I), constructs a larger optree fragment that consumes it and checks
460             that the value is accepted by the constraint check given by I. The
461             behaviours of the returned optree fragment will depend on the I.
462              
463             If I is C the returned optree will yield nothing.
464              
465             If I is zero, the return behaviour is not otherwise specified.
466              
467             =head2 check_value
468              
469             bool check_value(struct DataChecks_Checker *checker, SV *value);
470              
471             Checks whether a given SV is accepted by the given constraint check, returning
472             true if so, or false if not.
473              
474             =head2 assert_value
475              
476             void assert_value(struct DataChecks_Checker *checker, SV *value);
477              
478             Checks whether a given SV is accepted by the given constraint check, throwing
479             its assertion message if it does not.
480              
481             =cut
482              
483             =head1 TODO
484              
485             =over 4
486              
487             =item *
488              
489             Unit constraints - maybe C, some plain-only variants of C and
490             C, some reference types, etc...
491              
492             =item *
493              
494             Structural constraints - C, C, etc...
495              
496             =item *
497              
498             Think about a convenient name for inclusive-bounded numerical constraints.
499              
500             =item *
501              
502             Look into making const-folding work with the C flip-flop operator
503              
504             =item *
505              
506             Performance enhancements for lists of many values in C, C, etc
507              
508             =item *
509              
510             Performance enhancement of C by caching per package name
511              
512             =back
513              
514             =cut
515              
516             =head1 AUTHOR
517              
518             Paul Evans
519              
520             =cut
521              
522             0x55AA;