File Coverage

blib/lib/Google/ProtocolBuffers.pm
Criterion Covered Total %
statement 329 351 93.7
branch 81 116 69.8
condition 23 43 53.4
subroutine 47 47 100.0
pod 2 11 18.1
total 482 568 84.8


line stmt bran cond sub pod time code
1             package Google::ProtocolBuffers;
2            
3 14     14   181826 use 5.008008;
  14         29  
4 14     14   47 use warnings;
  14         15  
  14         246  
5 14     14   39 use strict;
  14         20  
  14         192  
6            
7 14     14   5528 use Google::ProtocolBuffers::Codec;
  14         30  
  14         393  
8 14     14   65 use Google::ProtocolBuffers::Constants qw/:complex_types :labels/;
  14         15  
  14         1827  
9 14     14   6637 use Class::Accessor;
  14         17110  
  14         62  
10 14     14   365 use Math::BigInt;
  14         13  
  14         59  
11 14     14   2743 use Carp;
  14         16  
  14         607  
12 14     14   7247 use Data::Dumper;
  14         58753  
  14         1651  
13            
14             our $VERSION = "0.12";
15            
16             sub parsefile {
17 10     10 1 1786 my $self = shift;
18 10         17 my $proto_filename = shift;
19 10   50     29 my $opts = shift || {};
20            
21 10         43 return $self->_parse({file=>$proto_filename}, $opts);
22             }
23            
24             sub parse {
25 12     12 1 4807 my $self = shift;
26 12         22 my $proto_text = shift;
27 12   100     47 my $opts = shift || {};
28            
29 12         71 return $self->_parse({text=>$proto_text}, $opts);
30             }
31            
32             ## Positional access is slightly faster than named one.
33             ## Currently, it's in the same order as text in proto file
34             ## "optional" (LABEL) int32 (type) foo (name) = 1 (number) [default=...]
35             use constant {
36 14         7240 F_LABEL => 0,
37             F_TYPE => 1,
38             F_NAME => 2,
39             F_NUMBER => 3,
40             F_DEFAULT => 4,
41 14     14   104 };
  14         16  
42            
43             sub _parse {
44 22     22   31 my $self = shift;
45 22         27 my $source = shift;
46 22         24 my $opts = shift;
47            
48 22         6127 require 'Google/ProtocolBuffers/Compiler.pm';
49 22         143 my $types = Google::ProtocolBuffers::Compiler->parse($source, $opts);
50            
51             ##
52             ## 1. Create enums - they will be used as default values for fields
53             ##
54 22         18549 my @created_enums;
55 22         125 while (my ($type_name, $desc) = each %$types) {
56 344 100       819 next unless $desc->{kind} eq 'enum';
57 49         146 my $class_name = $self->_get_class_name_for($type_name, $opts);
58 49         116 $self->create_enum($class_name, $desc->{fields});
59 49         143 push @created_enums, $class_name;
60             }
61            
62             ##
63             ## 2. Create groups and messages,
64             ## Fill default values of fields and convert their
65             ## types (my_package.message_a) into Perl classes names (MyPackage::MessageA)
66             ##
67 22         138 my @created_messages;
68 22         85 while (my ($type_name, $desc) = each %$types) {
69 344         364 my $kind = $desc->{kind};
70 344         253 my @fields;
71             my %oneofs;
72            
73 344 100       1198 if ($kind =~ /^(enum|oneof)$/) {
    100          
    50          
74 50         125 next;
75             } elsif ($kind eq 'group') {
76 57         46 push @fields, @{$desc->{fields}};
  57         87  
77             } elsif ($kind eq 'message') {
78 237         177 push @fields, @{$desc->{fields}};
  237         389  
79            
80             ##
81             ## Get names for extensions fields.
82             ## Original (full quilified) name is like 'package.MessageA.field'.
83             ## If 'simple_extensions' is true, it will be cut to the last element: 'field'.
84             ## Otherwise, it will be enclosed in brackets and all part common to message type
85             ## will be removed, e.g. for message 'package.MessageB' it will be '[MessageA.field]'
86             ## If message is 'other_package.MessageB', it will be '[package.MessageA.field]'
87             ##
88 237         182 foreach my $e (@{$desc->{extensions}}) {
  237         390  
89 658         480 my $field_name = $e->[F_NAME];
90 658         395 my $new_name;
91 658 100       756 if ($opts->{simple_extensions}) {
92 6 100       34 $new_name = ($field_name =~ /\.(\w+)$/) ? $1 : $field_name;
93             } else {
94             ## remove common identifiers from start of f.q.i.
95 652         1352 my @type_idents = split qr/\./, $type_name;
96 652         1236 my @field_idents = split qr/\./, $field_name;
97 652   33     1871 while (@type_idents && @field_idents) {
98 1308 100       1620 last if $type_idents[0] ne $field_idents[0];
99 656         385 shift @type_idents;
100 656         1564 shift @field_idents;
101             }
102 652 50       714 die "Can't create name for extension field '$field_name' in '$type_name'"
103             unless @field_idents;
104 652         914 $new_name = '[' . join('.', @field_idents) . ']';
105             }
106 658         527 $e->[F_NAME] = $new_name;
107 658         605 push @fields, $e;
108             }
109              
110             ##
111             ## Get names for oneof fields.
112             ##
113 237         174 foreach my $oneof_name (@{$desc->{oneofs}}) {
  237         320  
114 1         2 my $oneof = $types->{$oneof_name};
115 1         1 my @oneof_fields = map { $_->[F_NAME] } @{$oneof->{fields}};
  2         4  
  1         2  
116 1 50       8 my $new_name = ($oneof_name =~ /\.(\w+)$/) ? $1 : $oneof_name;
117 1         3 $oneofs{$new_name} = \@oneof_fields;
118 1         1 push @fields, @{$oneof->{fields}};
  1         2  
119             }
120             } else {
121 0         0 die;
122             }
123            
124             ##
125             ## Replace proto type names by Perl classes names
126             ##
127 294         308 foreach my $f (@fields) {
128 2081         1455 my $type = $f->[F_TYPE];
129 2081 100       3851 if ($type !~ /^\d+$/) {
130             ## not a primitive type
131 462         581 $f->[F_TYPE] = $self->_get_class_name_for($type, $opts);
132             }
133             }
134            
135             ##
136             ## Default values: replace references to enum idents by their values
137             ##
138 294         299 foreach my $f (@fields) {
139 2081         1319 my $default_value = $f->[F_DEFAULT];
140 2081 100 100     4237 if ($default_value && ref $default_value) {
    100          
141             ## this default value is a literal
142 371 50       458 die "Unknown default value " . Data::Dumper::Dumper($default_value)
143             unless ref($default_value) eq 'HASH';
144 371         523 $f->[F_DEFAULT] = $default_value->{value};
145 0         0 } elsif ($default_value) {
146             ## this default is an enum value
147 56         189 my ($enum_name, $enum_field_name) = ($default_value =~ /(.*)\.(\w+)$/);
148 56         118 my $class_name = $self->_get_class_name_for($enum_name, $opts);
149 14     14   64 no strict 'refs';
  14         16  
  14         610  
150 56         50 $f->[F_DEFAULT] = &{"${class_name}::$enum_field_name"};
  56         167  
151 14     14   58 use strict;
  14         25  
  14         10147  
152             }
153             }
154            
155             ##
156             ## Create Perl classes
157             ##
158 294         514 my $class_name = $self->_get_class_name_for($type_name, $opts);
159 294 100       473 if ($kind eq 'message') {
    50          
160 237         443 $self->create_message($class_name, \@fields, \%oneofs, $opts);
161             } elsif ($kind eq 'group') {
162 57         108 $self->create_group($class_name, \@fields, $opts);
163             }
164 293         15893 push @created_messages, $class_name;
165             }
166            
167 21         74 my @created_classes = sort @created_enums;
168 21         147 push @created_classes, sort @created_messages;
169            
170             ## Generate Perl code of created classes
171 21 100       64 if ($opts->{generate_code}) {
172 3         965 require 'Google/ProtocolBuffers/CodeGen.pm';
173 3         5 my $fh;
174 3 50       10 if (!ref($opts->{generate_code})) {
175 3 50       66374 open($fh, ">$opts->{generate_code}")
176             or die "Can't write to '$opts->{generate_code}': $!";
177             } else {
178 0         0 $fh = $opts->{generate_code};
179             }
180            
181 3 100       26 my $package_str = ($opts->{'package_name'}) ?
182             "package $opts->{'package_name'};" : "";
183            
184 3 100       14 my $source_str = ($source->{'file'}) ?
185             "$source->{'file'}" : "inline text";
186            
187 3         136 print $fh <<"HEADER";
188             # Generated by the protocol buffer compiler (protoc-perl) DO NOT EDIT!
189             # source: $source_str
190            
191             $package_str
192            
193             use strict;
194             use warnings;
195            
196             use Google::ProtocolBuffers;
197             {
198             HEADER
199 3         11 foreach my $class_name (@created_classes) {
200 39         273 print $fh $class_name->getPerlCode($opts);
201             }
202 3         222 print $fh "}\n1;\n";
203             }
204 21         737 return @created_classes;
205             }
206            
207             # Google::ProtocolBuffers->create_message(
208             # 'AccountRecord',
209             # [
210             # ## required string name = 1;
211             # [LABEL_REQUIRED, TYPE_STRING, 'name', 1 ],
212             # [LABEL_OPTIONAL, TYPE_INT32, 'id', 2 ],
213             # ],
214             # );
215             sub create_message {
216 265     265 0 5810 my $self = shift;
217 265         209 my $class_name = shift;
218 265         198 my $fields = shift;
219 265         175 my $oneofs = shift;
220 265         190 my $opts = shift;
221            
222 265         391 return $self->_create_message_or_group(
223             $class_name, $fields, $oneofs, $opts,
224             'Google::ProtocolBuffers::Message'
225             );
226             }
227            
228             sub create_group {
229 63     63 0 255 my $self = shift;
230 63         53 my $class_name = shift;
231 63         45 my $fields = shift;
232 63         50 my $opts = shift;
233            
234 63         117 return $self->_create_message_or_group(
235             $class_name, $fields, undef, $opts,
236             'Google::ProtocolBuffers::Group'
237             );
238             }
239            
240             sub _create_message_or_group {
241 328     328   255 my $self = shift;
242 328         253 my $class_name = shift;
243 328         262 my $fields = shift;
244 328         321 my $oneofs = shift;
245 328         230 my $opts = shift;
246 328         247 my $base_class = shift;
247            
248             ##
249             ## Sanity checks
250             ## 1. Class name must be a valid Perl class name
251             ## (should we check that this class doesn't exist yet?)
252             ##
253 328 50       1195 die "Invalid class name: '$class_name'"
254             unless $class_name =~ /^[a-z_]\w*(?:::[a-z_]\w*)*$/i;
255            
256             ##
257             ##
258 328         236 my (%field_names, %field_numbers);
259 328         374 foreach my $f (@$fields) {
260 2307         2939 my ($label, $type_name, $name, $field_number, $default_value) = @$f;
261 2307 50       2797 die Dumper $f unless $name;
262            
263             ##
264             ## field names must be valid identifiers and be unique
265             ##
266 2307 50 33     7577 die "Invalid field name: '$name'"
267             unless $name && $name =~ /^\[?[a-z_][\w\.]*\]?$/i;
268 2307 100       4026 if ($field_names{$name}++) {
269 1         171 die "Field '$name' is defined more than once";
270             }
271            
272             ##
273             ## field number must be positive and unique
274             ##
275 2306 50       2625 die "Invalid field number: $field_number" unless $field_number>0;
276 2306 50       3259 if ($field_numbers{$field_number}++) {
277 0         0 die "Field number $field_number is used more than once";
278             }
279            
280             ## type is either a number (for primitive types)
281             ## or a class name. Can't check that complex $type
282             ## is valid, because it may not exist yet.
283 2306 50       2622 die "Field '$name' doesn't has a type" unless $type_name;
284 2306 100       3647 if ($type_name =~/^\d+$/) {
285             ## ok, this is an ID of primitive type
286             } else {
287 512 50       1144 die "Type '$type_name' is not valid Perl class name"
288             unless $type_name =~ /^[a-z_]\w*(?:::[a-z_]\w*)*$/i;
289             }
290            
291 2306 50 100     5169 die "Unknown label value: $label"
      66        
292             unless $label==LABEL_OPTIONAL || $label==LABEL_REQUIRED || $label==LABEL_REPEATED;
293             }
294            
295            
296             ## Make a copy of values and sort them so that field_numbers increase,
297             ## this is a requirement of protocol
298             ## Postitional addressation of field parts is sucks, TODO: replace by hash
299 327         441 my @field_list = sort { $a->[F_NUMBER] <=> $b->[F_NUMBER] } map { [@$_] } @$fields;
  2278         1779  
  2305         2998  
300 327         373 my %fields_by_field_name = map { $_->[F_NAME] => $_ } @field_list;
  2305         2606  
301 327         411 my %fields_by_field_number = map { $_->[F_NUMBER] => $_ } @field_list;
  2305         2522  
302            
303 327   100     1000 my $has_oneofs = defined($oneofs) && %$oneofs;
304 327         250 my %oneofs_rev;
305              
306 327 100       439 if ($has_oneofs) {
307 1         3 while (my ($name, $fields) = each %$oneofs) {
308 1         2 %oneofs_rev = (%oneofs_rev, map { $_, $name } @$fields);
  2         6  
309             }
310             }
311              
312 14     14   76 no strict 'refs';
  14         18  
  14         1580  
313 327         251 @{"${class_name}::ISA"} = $base_class;
  327         3321  
314 327     252   879 *{"${class_name}::_pb_fields_list"} = sub { \@field_list };
  327         1056  
  252         580  
315 327     50   574 *{"${class_name}::_pb_fields_by_name"} = sub { \%fields_by_field_name };
  327         814  
  50         78  
316 327     282   572 *{"${class_name}::_pb_fields_by_number"} = sub { \%fields_by_field_number };
  327         758  
  282         409  
317 327 100       493 if ($has_oneofs) {
318 1     8   2 *{"${class_name}::_pb_oneofs"} = sub { $oneofs };
  1         4  
  8         17  
319 1     4   2 *{"${class_name}::_pb_oneofs_rev"} = sub { \%oneofs_rev };
  1         4  
  4         10  
320             }
321 14     14   358 use strict;
  14         21  
  14         310  
322            
323 327 100       981 if ($opts->{create_accessors}) {
324 14     14   44 no strict 'refs';
  14         13  
  14         1279  
325 158         120 push @{"${class_name}::ISA"}, 'Class::Accessor';
  158         942  
326 158 100       316 if ($has_oneofs) {
327 1         2 *{"${class_name}::new"} = \&Google::ProtocolBuffers::new;
  1         3  
328 1         2 *{"${class_name}::which_oneof"} = \&Google::ProtocolBuffers::which_oneof;
  1         3  
329             }
330 158         149 *{"${class_name}::get"} = \&Google::ProtocolBuffers::get;
  158         438  
331 158         139 *{"${class_name}::set"} = \&Google::ProtocolBuffers::set;
  158         418  
332 14     14   50 use strict;
  14         13  
  14         3442  
333            
334 158 50       273 if ($opts->{follow_best_practice}) {
335 0         0 $class_name->follow_best_practice;
336             }
337 158         178 my @accessors = grep { /^[a-z_]\w*$/i } map { $_->[2] } @$fields;
  1116         1440  
  1116         877  
338 158         1108 $class_name->mk_accessors(@accessors);
339             }
340             }
341            
342             sub create_enum {
343 54     54 0 2870 my $self = shift;
344 54         49 my $class_name = shift;
345 54         39 my $fields = shift;
346 54         46 my $options = shift;
347            
348             ##
349             ## Sanity checks
350             ## 1. Class name must be a valid Perl class name
351             ## (should we check that this class doesn't exist yet?)
352             ## 2. Field names must be valid identifiers and be unique
353             ##
354 54 50       248 die "Invalid class name: '$class_name'"
355             unless $class_name =~ /^[a-z_]\w*(?:::[a-z_]\w*)*$/i;
356 54         73 my %names;
357 54         71 foreach my $f (@$fields) {
358 222         286 my ($name, $value) = @$f;
359 222 50 33     785 die "Invalid field name: '$name'"
360             unless $name && $name =~ /^[a-z_]\w*$/i;
361 222 50       479 if ($names{$name}++) {
362 0         0 die "Field '$name' is defined more than once";
363             }
364             }
365            
366             ## base class and constants export
367 14     14   58 no strict 'refs';
  14         16  
  14         676  
368 54         54 @{"${class_name}::ISA"} = "Google::ProtocolBuffers::Enum";
  54         709  
369 54         76 %{"${class_name}::EXPORT_TAGS"} = ('constants'=>[]);
  54         305  
370 14     14   64 use strict;
  14         15  
  14         378  
371            
372             ## create the constants
373 54         74 foreach my $f (@$fields) {
  0         0  
374 222         241 my ($name, $value) = @$f;
375 14     14   41 no strict 'refs';
  14         15  
  14         805  
376 222     116   526 *{"${class_name}::$name"} = sub { $value };
  222         542  
  116         4621  
377 222         149 push @{ ${"${class_name}::EXPORT_TAGS"}{'constants'} }, $name;
  222         135  
  222         380  
378 222         136 push @{"${class_name}::EXPORT_OK"}, $name;
  222         417  
379 14     14   43 use strict;
  14         12  
  14         496  
380             }
381            
382             ## create a copy of fields for introspection/code generation
383 54         70 my @fields = map { [@$_] } @$fields;
  222         281  
384 14     14   37 no strict 'refs';
  14         13  
  14         9904  
385 54     5   104 *{"${class_name}::_pb_fields_list"} = sub { \@fields };
  54         532  
  5         12  
386            
387             }
388            
389             ##
390             ## Accessors
391             ##
392             sub getExtension {
393 14     14 0 252 my $self = shift;
394 14 50       27 my $data = (ref $self) ? $self : shift();
395 14         13 my $extension_name = shift;
396            
397 14 50       27 unless($extension_name){
398 0         0 return \%{$self->_pb_fields_by_name()};
  0         0  
399             }
400            
401 14         22 $extension_name =~ s/::/./g;
402 14         20 my $key = "[$extension_name]";
403            
404 14         24 my $field = $self->_pb_fields_by_name->{$key};
405 14 100       21 if ($field) {
406 13 100       59 return (exists $data->{$key}) ? $data->{$key} : $field->[F_DEFAULT];
407             } else {
408 1   33     4 my $class_name = ref $self || $self;
409 1         89 die "There is no extension '$extension_name' in '$class_name'";
410             }
411             }
412            
413            
414            
415             sub setExtension {
416 5     5 0 7 my $self = shift;
417 5 50       11 my $data = (ref $self) ? $self : shift();
418 5         6 my $extension_name = shift;
419 5         5 my $value = shift;
420            
421 5         7 $extension_name =~ s/::/./g;
422 5         7 my $key = "[$extension_name]";
423            
424 5 100       10 if ($self->_pb_fields_by_name->{$key}) {
425 4         9 $data->{$key} = $value;
426             } else {
427 1   33     4 my $class_name = ref $self || $self;
428 1         159 die "There is no extension '$extension_name' in '$class_name'";
429             }
430             }
431            
432             ##
433             ## Overide the Class::Accessor new to handle oneof fields.
434             ##
435             sub new {
436 1     1 0 869 my ($proto, $fields) = @_;
437 1   33     7 my ($class) = ref $proto || $proto;
438              
439 1 50       3 $fields = {} unless defined $fields;
440              
441 1         2 my $self = bless {}, $class;
442              
443             ## Set the fields
444 1         5 while (my ($key, $value) = each %$fields) {
445 0 0       0 if (!defined($value)) {
446 0         0 $self->{$key} = undef;
447             }
448             else {
449 0         0 $self->set($key, $value);
450             }
451             }
452              
453 1         3 return $self;
454             }
455              
456             ##
457             ## Return which field in a oneof is set
458             ##
459             sub which_oneof {
460 3     3 0 230 my $self = shift;
461 3         4 my $oneof = shift;
462              
463             return undef unless $self->can('_pb_oneofs') &&
464 3 50 33     15 exists($self->_pb_oneofs->{$oneof});
465              
466 3         3 foreach my $f (@{$self->_pb_oneofs->{$oneof}}) {
  3         3  
467 5 100       14 if (defined($self->{$f})) {
468 2         7 return $f;
469             }
470             }
471              
472 1         4 return undef;
473             }
474              
475             ##
476             ## This is for Class::Accessor read-accessors, will be
477             ## copied to classes from Message/Group.
478             ## If no value is set, the default one will be returned.
479             ##
480             sub get {
481 56     56 0 6100 my $self = shift;
482            
483 56 50       95 if (@_==1) {
    0          
484             ## checking that $self->{$_[0]} exists is not enough,
485             ## since undef value may be set via Class::Accessor's new, e.g:
486             ## my $data = My::Message->new({ name => undef })
487 56 100       204 return $self->{$_[0]} if defined $self->{$_[0]};
488 31         56 my $field = $self->_pb_fields_by_name->{$_[0]};
489 31         124 return $field->[F_DEFAULT];
490             } elsif (@_>1) {
491 0         0 my @rv;
492             my $fields;
493 0         0 foreach my $key (@_) {
494 0 0       0 if (defined $self->{$key}) {
495 0         0 push @rv, $self->{$key};
496             } else {
497 0   0     0 $fields ||= $self->_pb_fields_by_name;
498 0         0 push @rv, $fields->{$key}->[F_DEFAULT];
499             }
500             }
501 0         0 return @rv;
502             } else {
503 0         0 Carp::confess("Wrong number of arguments received.");
504             }
505             }
506            
507             sub set {
508 17     17 0 111 my $self = shift;
509 17         20 my $key = shift;
510            
511 17 50       29 if (@_==1) {
    0          
512 17 100       26 if (defined $_[0]) {
513 16         28 $self->{$key} = $_[0];
514             } else {
515 1         3 delete $self->{$key};
516             }
517             } elsif (@_>1) {
518 0         0 $self->{$key} = [@_];
519             } else {
520 0         0 Carp::confess("Wrong number of arguments received.");
521             }
522              
523             # Is this a oneof field
524 17 50 66     94 if ($self->can('_pb_oneofs_rev') && exists($self->_pb_oneofs_rev->{$key})) {
525 2         2 foreach my $f (@{$self->_pb_oneofs->{$self->_pb_oneofs_rev->{$key}}}) {
  2         3  
526 4 100       11 delete $self->{$f} unless $f eq $key;
527             }
528             }
529             }
530            
531             sub _get_class_name_for{
532 861     861   656 my $self = shift;
533 861         602 my $type_name = shift;
534 861         544 my $opts = shift;
535            
536 861 100       985 if ($opts->{no_camel_case}) {
537 1         1 my $class_name = $type_name;
538 1         5 $class_name =~ s/\./::/g;
539 1         2 return $class_name;
540             } else {
541 860         2704 my @idents = split qr/\./, $type_name;
542 860         1119 foreach (@idents) {
543 1950         2747 s/_(.)/uc($1)/ge;
  982         1761  
544 1950         2162 $_ = "\u$_";
545             }
546 860         2102 return join("::", @idents);
547             }
548             }
549            
550             package Google::ProtocolBuffers::Message;
551 14     14   63 no warnings 'once';
  14         16  
  14         1750  
552             ## public
553             *encode = \&Google::ProtocolBuffers::Codec::encode;
554             *decode = \&Google::ProtocolBuffers::Codec::decode;
555             *setExtension = \&Google::ProtocolBuffers::setExtension;
556             *getExtension = \&Google::ProtocolBuffers::getExtension;
557             *getPerlCode = \&Google::ProtocolBuffers::CodeGen::generate_code_of_message_or_group;
558             ## internal
559             ## _pb_complex_type_kind can be removed and $class->isa('Google::ProtocolBuffers::Message')
560             ## can be used instead, but current implementation is faster
561 315     315   569 sub _pb_complex_type_kind { Google::ProtocolBuffers::Constants::MESSAGE() }
562             # _pb_fields_list ## These 3 methods are created in
563             # _pb_fields_by_name ## namespace of derived class
564             # _pb_fields_by_number
565            
566             package Google::ProtocolBuffers::Group;
567             *setExtension = \&Google::ProtocolBuffers::setExtension;
568             *getExtension = \&Google::ProtocolBuffers::getExtension;
569             *getPerlCode = \&Google::ProtocolBuffers::CodeGen::generate_code_of_message_or_group;
570 40     40   74 sub _pb_complex_type_kind { Google::ProtocolBuffers::Constants::GROUP() }
571             #_pb_fields_list
572             #_pb_fields_by_name
573             #_pb_fields_by_number
574            
575             package Google::ProtocolBuffers::Enum;
576 14     14   55 use base 'Exporter';
  14         12  
  14         1469  
577             *getPerlCode = \&Google::ProtocolBuffers::CodeGen::generate_code_of_enum;
578 26     26   36 sub _pb_complex_type_kind { Google::ProtocolBuffers::Constants::ENUM() }
579             #_pb_fields_list
580            
581             1;
582            
583             __END__