File Coverage

blib/lib/Tangence/Struct.pm
Criterion Covered Total %
statement 80 85 94.1
branch 3 4 75.0
condition 5 12 41.6
subroutine 17 18 94.4
pod 1 6 16.6
total 106 125 84.8


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, 2012-2024 -- leonerd@leonerd.org.uk
5              
6 14     14   201 use v5.26;
  14         53  
7 14     14   87 use warnings;
  14         27  
  14         941  
8 14     14   85 use Object::Pad 0.800;
  14         122  
  14         721  
9              
10             package Tangence::Struct 0.33;
11 14     14   10673 class Tangence::Struct :isa(Tangence::Meta::Struct);
  14         46  
  14         1893  
12              
13 14     14   1529 use Carp;
  14         31  
  14         1146  
14              
15 14     14   90 use meta 0.004;
  14         230  
  14         506  
16 14     14   76 no warnings 'meta::experimental';
  14         27  
  14         732  
17              
18 14     14   83 use Tangence::Type;
  14         27  
  14         413  
19 14     14   7723 use Tangence::Meta::Field;
  14         58  
  14         35748  
20              
21             =head1 NAME
22              
23             C - server implementation of a C struct
24              
25             =head1 DESCRIPTION
26              
27             This module is a component of L. It is not intended for
28             end-user use directly.
29              
30             =cut
31              
32             our %STRUCTS_BY_NAME;
33             our %STRUCTS_BY_PERLNAME;
34              
35 69         127 sub make ( $class, %args )
36 69     69 0 130 {
  69         200  
  69         107  
37 69         156 my $name = $args{name};
38              
39 69   66     968 return $STRUCTS_BY_NAME{$name} //= $class->new( %args );
40             }
41              
42 57         123 sub declare ( $class, $perlname, %args )
  57         117  
43 57     57 0 288514 {
  57         163  
  57         82  
44 57         319 ( my $name = $perlname ) =~ s{::}{.}g;
45 57 100       209 $name = $args{name} if $args{name};
46              
47 57         170 my @fields;
48 57         153 for( $_ = 0; $_ < @{$args{fields}}; $_ += 2 ) {
  199         589  
49             push @fields, Tangence::Meta::Field->new(
50             name => $args{fields}[$_],
51 142         806 type => Tangence::Type->make_from_sig( $args{fields}[$_+1] ),
52             );
53             }
54              
55 57         175 my $self = $class->make( name => $name );
56 57         164 $self->_set_perlname( $perlname );
57              
58 57         164 $self->define(
59             fields => \@fields,
60             );
61              
62 57         152 $STRUCTS_BY_PERLNAME{$perlname} = $self;
63 57         184 return $self;
64             }
65              
66             sub declare_builtin
67             {
68 56     56 0 108 my $class = shift;
69 56         156 my $self = $class->declare( @_ );
70              
71 56         285 $Tangence::Stream::ALWAYS_PEER_HASSTRUCT{$self->perlname} = [ $self, my $structid = ++$Tangence::Struct::BUILTIN_STRUCTIDS ];
72 56         233 $Tangence::Stream::BUILTIN_ID2STRUCT{$structid} = $self;
73              
74 56         181 return $self;
75             }
76              
77             sub define
78             {
79 67     67 1 120 my $self = shift;
80 67         338 $self->SUPER::define( @_ );
81              
82 67         219 my $class = $self->perlname;
83 67         3392 my $classmeta = meta::package->get( $class );
84 67         447 my @fieldnames = map { $_->name } $self->fields;
  192         446  
85              
86             # Now construct the actual perl package
87 322         519 my %subs = (
88 322     322   885 new => sub ( $class, %args ) {
  322         928  
  322         414  
89 322   33     1434 exists $args{$_} or croak "$class is missing $_" for @fieldnames;
90 322         2623 bless [ @args{@fieldnames} ], $class;
91             },
92 67         475 );
93 67     849   276 $subs{$fieldnames[$_]} = do { my $i = $_; sub { shift->[$i] } } for 0 .. $#fieldnames;
  192         282  
  192         872  
  849         4383  
94              
95 67         226 foreach my $name ( keys %subs ) {
96 259 50       1058 next if $classmeta->try_get_symbol( '&' . $name );
97 259         1531 $classmeta->add_symbol( '&' . $name => $subs{$name} );
98             }
99             }
100              
101 0         0 sub for_name ( $class, $name )
102 0     0 0 0 {
  0         0  
  0         0  
103 0   0     0 return $STRUCTS_BY_NAME{$name} // croak "Unknown Tangence::Struct for '$name'";
104             }
105              
106 171         294 sub for_perlname ( $class, $perlname )
107 171     171 0 276 {
  171         287  
  171         261  
108 171   66     3297 return $STRUCTS_BY_PERLNAME{$perlname} // croak "Unknown Tangence::Struct for '$perlname'";
109             }
110              
111 57     57   139 field $perlname :writer(_set_perlname);
  57         125  
112              
113             method perlname
114             {
115             return $perlname if defined $perlname;
116             ( $perlname = $self->name ) =~ s{\.}{::}g; # s///rg in 5.14
117             return $perlname;
118             }
119              
120             Tangence::Struct->declare_builtin(
121             "Tangence::Struct::Class",
122             name => "Tangence.Class",
123             fields => [
124             methods => "dict(any)",
125             events => "dict(any)",
126             properties => "dict(any)",
127             superclasses => "list(str)",
128             ],
129             );
130              
131             Tangence::Struct->declare_builtin(
132             "Tangence::Struct::Method",
133             name => "Tangence.Method",
134             fields => [
135             arguments => "list(str)",
136             returns => "str",
137             ],
138             );
139              
140             Tangence::Struct->declare_builtin(
141             "Tangence::Struct::Event",
142             name => "Tangence.Event",
143             fields => [
144             arguments => "list(str)",
145             ],
146             );
147              
148             Tangence::Struct->declare_builtin(
149             "Tangence::Struct::Property",
150             name => "Tangence.Property",
151             fields => [
152             dimension => "int",
153             type => "str",
154             smashed => "bool",
155             ],
156             );
157              
158             =head1 AUTHOR
159              
160             Paul Evans
161              
162             =cut
163              
164             0x55AA;