File Coverage

blib/lib/Devel/MAT/Tool/Object/Pad/_SVs.pm
Criterion Covered Total %
statement 80 80 100.0
branch 11 18 61.1
condition 15 20 75.0
subroutine 19 19 100.0
pod n/a
total 125 137 91.2


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, 2022 -- leonerd@leonerd.org.uk
5              
6 2     2   1032 use v5.14;
  2         6  
7 2     2   8 use warnings;
  2         3  
  2         54  
8              
9             package Devel::MAT::Tool::Object::Pad::_SVs;
10              
11 2     2   9 use Devel::MAT::SV;
  2         3  
  2         40  
12              
13 2     2   8 use List::Util qw( first );
  2         4  
  2         786  
14              
15             my $field_index_for = sub {
16             my $self = shift;
17             my ( $name ) = @_;
18              
19             my $fields = $self->structtype->fields;
20              
21             return first { $fields->[$_]->name eq $name } 0 .. $#$fields;
22             };
23              
24             my $make_accessor = sub {
25             my ( $name ) = @_;
26              
27             return sub {
28 36     36   80 my $self = shift;
        36      
29 36         53 state $idx = $self->$field_index_for( $name );
30 36         134 return $self->field( $idx );
31             };
32             };
33              
34             my $make_sv_accessor = sub {
35             my ( $name ) = @_;
36              
37             return sub {
38 11     11   825 my $self = shift;
39 11         17 state $idx = $self->$field_index_for( $name );
40 11         51 return $self->df->sv_at( $self->field( $idx ) );
41             };
42             };
43              
44             my $make_sv_pv_accessor = sub {
45             my ( $name ) = @_;
46              
47             return sub {
48 44     44   11026 my $self = shift;
49 44         58 state $idx = $self->$field_index_for( $name );
50 44         158 return $self->df->sv_at( $self->field( $idx ) )->pv;
51             };
52             };
53              
54             my $make_sv_elems_accessor = sub {
55             my ( $name ) = @_;
56              
57             return sub {
58 16     16   16 my $self = shift;
59 16         18 state $idx = $self->$field_index_for( $name );
60 16         60 return $self->df->sv_at( $self->field( $idx ) )->elems;
61             };
62             };
63              
64             package # hide
65             Devel::MAT::Tool::Object::Pad::_ClassSV;
66 2     2   11 use base qw( Devel::MAT::SV::C_STRUCT );
  2         4  
  2         1105  
67              
68             *objectpad_name = $make_sv_pv_accessor->( "the name SV" );
69              
70             *objectpad_type = $make_accessor->( "type" );
71              
72             *objectpad_repr = $make_accessor->( "repr" );
73              
74             *objectpad_superclass = $make_sv_accessor->( "the supermeta" );
75              
76             *objectpad_direct_fields = $make_sv_elems_accessor->( "the direct fields AV" );
77              
78             *objectpad_direct_roles = $make_sv_elems_accessor->( "the direct roles AV" );
79              
80             sub objectpad_fieldnames_by_idx
81             {
82 2     2   3 my $self = shift;
83 2   66     6 return $self->{objectpad_fieldnames_by_idx} //= do {
84 1         1 my @fieldnames;
85 1         15 $self->_objectpad_fieldnames_for_class( \@fieldnames, $self );
86 1         4 \@fieldnames;
87             };
88             }
89              
90             sub _objectpad_fieldnames_for_class
91             {
92 3     3   14 my $self = shift;
93 3         7 my ( $fieldnames, $classmeta, $nameprefix, $offset ) = @_;
94 3   100     10 $offset //= 0;
95              
96 3         4 my $is_class = $classmeta->objectpad_type == 0;
97              
98 3 100 100     8 if( $is_class and my $superclass = $classmeta->objectpad_superclass ) {
99 1         12 $self->_objectpad_fieldnames_for_class( $fieldnames, $superclass, $superclass->objectpad_name );
100             }
101              
102 3         25 foreach my $fieldmeta ( $classmeta->objectpad_direct_fields ) {
103 5         84 my $name = $fieldmeta->objectpad_name;
104 5         46 my $fieldix = $fieldmeta->objectpad_fieldix + $offset;
105              
106             my $fieldname = Devel::MAT::Cmd->format_note(
107 5         7 join( "/", grep { defined } $nameprefix, $name ), 1
  10         31  
108             );
109              
110 5         27 $fieldnames->[$fieldix] = "the $fieldname field";
111             }
112              
113 3 100       6 if( $is_class ) {
114 2         4 foreach my $embedding ( $classmeta->objectpad_direct_roles ) {
115 1         22 my $rolemeta = $embedding->objectpad_role;
116              
117 1         10 $self->_objectpad_fieldnames_for_class( $fieldnames, $rolemeta, $rolemeta->objectpad_name, $embedding->objectpad_offset );
118             }
119             }
120             }
121              
122             package # hide
123             Devel::MAT::Tool::Object::Pad::_RoleSV;
124 2     2   12 use base qw( Devel::MAT::SV::C_STRUCT );
  2         4  
  2         526  
125              
126             *objectpad_name = $make_sv_pv_accessor->( "the name SV" );
127              
128             *objectpad_type = $make_accessor->( "type" );
129              
130             *objectpad_repr = $make_accessor->( "repr" );
131              
132             *objectpad_direct_fields = $make_sv_elems_accessor->( "the direct fields AV" );
133              
134             package # hide
135             Devel::MAT::Tool::Object::Pad::_FieldSV;
136 2     2   12 use base qw( Devel::MAT::SV::C_STRUCT );
  2         18  
  2         474  
137              
138             *objectpad_name = $make_sv_pv_accessor->( "the name SV" );
139              
140             *objectpad_class = $make_sv_accessor->( "the class" );
141              
142             *objectpad_fieldix = $make_accessor->( "fieldix" );
143              
144             package # hide
145             Devel::MAT::Tool::Object::Pad::_MethodSV;
146 2     2   20 use base qw( Devel::MAT::SV::C_STRUCT );
  2         5  
  2         453  
147              
148             *objectpad_name = $make_sv_pv_accessor->( "the name SV" );
149              
150             *objectpad_class = $make_sv_accessor->( "the class" );
151              
152             package # hide
153             Devel::MAT::Tool::Object::Pad::_RoleEmbeddingSV;
154 2     2   10 use base qw( Devel::MAT::SV::C_STRUCT );
  2         4  
  2         461  
155              
156             *objectpad_role = $make_sv_accessor->( "the role" );
157              
158             *objectpad_class = $make_sv_accessor->( "the class" );
159              
160             *objectpad_offset = $make_accessor->( "offset" );
161              
162             package # hide
163             Devel::MAT::Tool::Object::Pad::_FieldAV;
164 2     2   10 use base qw( Devel::MAT::SV::ARRAY );
  2         4  
  2         521  
165              
166             # TODO: Devel::MAT ought to export these somehow
167             BEGIN {
168 2     2   9 *STRENGTH_STRONG = \&Devel::MAT::SV::STRENGTH_STRONG;
169 2         487 *STRENGTH_INDIRECT = \&Devel::MAT::SV::STRENGTH_INDIRECT;
170             }
171              
172             sub _outrefs
173             {
174 2     2   2203 my $self = shift;
175 2         5 my ( $match, $no_desc ) = @_;
176              
177 2 50       6 my $instance = $self->df->sv_at( $self->{objectpad_instance_at} ) or
178             return $self->Devel::MAT::SV::ARRAY::_outrefs( @_ );
179              
180 2 50       48 my $package = $instance->blessed or
181             die "SV is not a blessed object instance\n";
182              
183 2 50       27 my $class = $package->objectpad_class or
184             die $package->stashname . " is not an Object::Pad class\n";
185              
186             # Try to give outrefs per index a better name by using field names
187 2         20 my $fieldnames_by_idx = $class->objectpad_fieldnames_by_idx;
188              
189 2         7 my @elems = $self->elems;
190 2         94 my @outrefs;
191              
192 2         5 foreach my $idx ( 0 .. $#elems ) {
193 10         30 my $value = $elems[$idx];
194              
195 10   33     16 my $name = $fieldnames_by_idx->[$idx] //
196             ( "element " . Devel::MAT::Cmd->format_value( $idx, index => 1 ) );
197              
198 10 50       15 if( $match & STRENGTH_STRONG ) {
199 10 50       19 push @outrefs, $no_desc ? ( strong => $value ) :
200             Devel::MAT::SV::Reference( $name, strong => $value );
201             }
202 10 50 100     60 if( $match & STRENGTH_INDIRECT and $value->type eq "REF" and !$value->{magic} and my $rv = $value->rv ) {
      66        
      66        
203 2 50       29 push @outrefs, $no_desc ? ( indirect => $rv ) :
204             Devel::MAT::SV::Reference( $name . " via RV", indirect => $rv );
205             }
206             }
207              
208 2         19 return @outrefs;
209             }
210              
211             0x55AA;