File Coverage

lib/Object/Pad/ClassAttr/Struct.xs
Criterion Covered Total %
statement 33 35 94.2
branch 22 36 61.1
condition n/a
subroutine n/a
pod n/a
total 55 71 77.4


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, 2021-2022 -- leonerd@leonerd.org.uk
5             */
6             #define PERL_NO_GET_CONTEXT
7              
8             #include "EXTERN.h"
9             #include "perl.h"
10             #include "XSUB.h"
11              
12             #include "object_pad.h"
13              
14             enum {
15             FLAG_READONLY = (1<<0),
16             };
17              
18 3           static bool struct_apply(pTHX_ ClassMeta *classmeta, SV *value, SV **attrdata_ptr, void *_funcdata)
19             {
20             U32 flags = 0;
21              
22 3 100         if(value && SvPOK(value)) {
    50          
23 1           const char *s = SvPVX(value), *e = s + SvCUR(value);
24              
25 2 100         while(s < e) {
26 1           const char *comma_at = strchr(s, ',');
27 1 50         if(!comma_at)
28             comma_at = e;
29 1           STRLEN len = comma_at - s;
30              
31 1 50         if(len == 8 && strnEQ(s, "readonly", len))
    50          
    50          
    0          
    50          
32             flags |= FLAG_READONLY;
33             else
34 0           croak("Unrecognised :Struct() option \"%.*s\"", (int)len, s);
35              
36             s += len;
37 1 50         while(*s == ',')
38 0           s++;
39             }
40             }
41              
42 3 100         if(flags)
43 1           *attrdata_ptr = newSVuv(flags);
44              
45 3           mop_class_apply_attribute(classmeta, "strict", sv_2mortal(newSVpvs("params")));
46 3           return TRUE;
47             }
48              
49 9           static void struct_post_add_field(pTHX_ ClassMeta *classmeta, SV *attrdata, void *_funcdata, FieldMeta *fieldmeta)
50             {
51 9 50         if(mop_field_get_sigil(fieldmeta) != '$')
52             return;
53              
54 9 100         U32 flags = attrdata ? SvUV(attrdata) : 0;
    50          
55              
56 9           mop_field_apply_attribute(fieldmeta, "param", NULL);
57              
58 9 100         if(flags & FLAG_READONLY)
59 3           mop_field_apply_attribute(fieldmeta, "reader", NULL);
60             else
61 6           mop_field_apply_attribute(fieldmeta, "mutator", NULL);
62             }
63              
64 3           static void struct_post_seal(pTHX_ ClassMeta *classmeta, SV *attrdata, void *_funcdata)
65             {
66 3           dSP;
67              
68 3           ENTER;
69 3           SAVETMPS;
70              
71 3 50         EXTEND(SP, 1);
72 3 50         PUSHMARK(SP);
73 3           PUSHs(mop_class_get_name(classmeta));
74 3           PUTBACK;
75              
76 3           call_pv("Object::Pad::ClassAttr::Struct::_post_seal", G_VOID);
77              
78 3 50         FREETMPS;
79 3           LEAVE;
80 3           }
81              
82             static const struct ClassHookFuncs struct_hooks = {
83             .ver = OBJECTPAD_ABIVERSION,
84             .flags = 0,
85             .permit_hintkey = "Object::Pad::ClassAttr::Struct/Struct",
86              
87             .apply = &struct_apply,
88             .post_add_field = &struct_post_add_field,
89             .post_seal = &struct_post_seal,
90             };
91              
92             MODULE = Object::Pad::ClassAttr::Struct PACKAGE = Object::Pad::ClassAttr::Struct
93              
94             BOOT:
95 4           register_class_attribute("Struct", &struct_hooks, NULL);