File Coverage

lib/Object/Pad/SlotAttr/Isa.xs
Criterion Covered Total %
statement 28 28 100.0
branch 8 8 100.0
condition n/a
subroutine n/a
pod n/a
total 36 36 100.0


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 -- 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             struct Data {
15             unsigned int is_weak : 1;
16             SV *slotname;
17             SV *classname;
18             };
19              
20 6           static int magic_set(pTHX_ SV *sv, MAGIC *mg)
21             {
22 6           struct Data *data = (struct Data *)mg->mg_ptr;
23 6           SV *savesv = mg->mg_obj;
24              
25 6           bool ok = sv_derived_from_sv(sv, data->classname, 0);
26              
27 6 100         if(ok) {
28 3           sv_setsv(savesv, sv);
29 3 100         if(data->is_weak)
30 3           sv_rvweaken(savesv);
31             return 1;
32             }
33              
34             /* Restore last known-good value */
35 3           sv_setsv_nomg(sv, savesv);
36 3 100         if(data->is_weak)
37 1           sv_rvweaken(sv);
38              
39 3           croak("Slot %" SVf " requires an object of type %" SVf,
40 3           SVfARG(data->slotname), SVfARG(data->classname));
41              
42             return 1;
43             }
44              
45             static const MGVTBL vtbl = {
46             .svt_set = &magic_set,
47             };
48              
49 3           static bool isa_apply(pTHX_ SlotMeta *slotmeta, SV *value, SV **hookdata_ptr, void *_funcdata)
50             {
51             struct Data *data;
52 3           Newx(data, 1, struct Data);
53              
54 3           data->is_weak = false;
55 3           data->slotname = SvREFCNT_inc(mop_slot_get_name(slotmeta));
56 3           data->classname = SvREFCNT_inc(value);
57              
58 3           *hookdata_ptr = (SV *)data;
59              
60 3           return TRUE;
61             }
62              
63 3           static void isa_seal(pTHX_ SlotMeta *slotmeta, SV *hookdata, void *_funcdata)
64             {
65             struct Data *data = (struct Data *)hookdata;
66              
67 3 100         if(mop_slot_get_attribute(slotmeta, "weak"))
68 1           data->is_weak = true;
69 3           }
70              
71 5           static void isa_post_initslot(pTHX_ SlotMeta *slotmeta, SV *hookdata, void *_funcdata, SV *slot)
72             {
73 5           sv_magicext(slot, newSV(0), PERL_MAGIC_ext, &vtbl, (char *)hookdata, 0);
74 5           }
75              
76             static const struct SlotHookFuncs isa_hooks = {
77             .ver = OBJECTPAD_ABIVERSION,
78             .flags = OBJECTPAD_FLAG_ATTR_MUST_VALUE,
79             .permit_hintkey = "Object::Pad::SlotAttr::Isa/Isa",
80              
81             .apply = &isa_apply,
82             .seal_slot = &isa_seal,
83             .post_initslot = &isa_post_initslot,
84             };
85              
86             MODULE = Object::Pad::SlotAttr::Isa PACKAGE = Object::Pad::SlotAttr::Isa
87              
88             BOOT:
89 3           register_slot_attribute("Isa", &isa_hooks, NULL);