File Coverage

blib/lib/FFI/Platypus/Type/Enum.pm
Criterion Covered Total %
statement 67 68 98.5
branch 44 46 95.6
condition 9 11 81.8
subroutine 11 11 100.0
pod 0 1 0.0
total 131 137 95.6


line stmt bran cond sub pod time code
1             package FFI::Platypus::Type::Enum;
2              
3 1     1   272955 use strict;
  1         11  
  1         37  
4 1     1   6 use warnings;
  1         2  
  1         38  
5 1     1   6 use constant 1.32 ();
  1         18  
  1         16  
6 1     1   14 use 5.008001;
  1         3  
7 1     1   601 use Ref::Util qw( is_plain_arrayref is_plain_hashref is_ref );
  1         1922  
  1         102  
8 1     1   11 use Scalar::Util qw( dualvar );
  1         2  
  1         64  
9 1     1   9 use Carp qw( croak );
  1         3  
  1         999  
10              
11             # ABSTRACT: Custom platypus type for dealing with C enumerated types
12             our $VERSION = '0.06'; # VERSION
13              
14              
15             our @CARP_NOT = qw( FFI::Platypus );
16              
17             sub ffi_custom_type_api_1
18             {
19             my %config = defined $_[2] && is_plain_hashref $_[2]
20 14 100 66 14 0 60688 ? %{ splice(@_, 2, 1) }
  9         46  
21             : ();
22 14         40 my(undef, undef, @values) = @_;
23              
24 14         28 my $index = 0;
25 14         27 my %str_lookup;
26             my %int_lookup;
27 14 100       37 my $prefix = defined $config{prefix} ? $config{prefix} : '';
28 14   100     55 $config{rev} ||= 'str';
29 14 100       263 ($config{rev} =~ /^(int|str|dualvar)$/) or croak("rev must be either 'int', 'str', or 'dualvar'");
30              
31 13   100     61 $config{casing} ||= 'upper';
32 13 50       48 ($config{casing} =~ /^(upper|keep)$/) or croak("casing must be either 'upper' or 'keep'");
33              
34 13         29 foreach my $value (@values)
35             {
36 40         63 my $name;
37             my @aliases;
38              
39 40 100       98 if(is_plain_arrayref $value)
    100          
40             {
41 11         16 my %opt;
42 11 100       29 if(@$value % 2)
43             {
44 1         3 ($name,%opt) = @$value;
45             }
46             else
47             {
48 10         40 ($name,$index,%opt) = @$value;
49             }
50 11 100       16 @aliases = @{ delete $opt{alias} || [] };
  11         43  
51 11 100       27 croak("unrecognized options: @{[ sort keys %opt ]}") if %opt;
  1         112  
52             }
53             elsif(!is_ref $value)
54             {
55 28         43 $name = $value;
56             }
57             else
58             {
59 1         108 croak("not a array ref or scalar: $value");
60             }
61              
62 38 100       84 if($index < 0)
63             {
64 2   50     11 $config{type} ||= 'senum';
65             }
66              
67 38 100       74 if(my $packages = $config{package})
68             {
69 10 100       26 foreach my $package (is_plain_arrayref $packages ? @$packages : $packages)
70             {
71 12         25 foreach my $name ($name,@aliases)
72             {
73 16 100       58 my $full = join '::', $package, $prefix . ( $config{casing} eq 'upper' ? uc($name) : $name );
74 16         529 constant->import($full, $index);
75             }
76             }
77             }
78              
79 38 100       189 croak("$name declared twice") if exists $str_lookup{$name};
80              
81 37 100       101 $int_lookup{$index} = $name unless exists $int_lookup{$index};
82 37         74 $str_lookup{$_} = $index for @aliases;
83 37         104 $str_lookup{$name} = $index++;
84             }
85              
86 10   100     43 $config{type} ||= 'enum';
87              
88 10 100       25 if(defined $config{maps})
89             {
90 1 50       4 if(is_plain_arrayref $config{maps})
91             {
92 1         2 @{ $config{maps} } = (\%str_lookup, \%int_lookup, $config{type});
  1         4  
93             }
94             else
95             {
96 0         0 croak("maps is not an array reference");
97             }
98             }
99              
100             my %type = (
101             native_type => $config{type},
102             perl_to_native => sub {
103             exists $str_lookup{$_[0]}
104             ? $str_lookup{$_[0]}
105 32 100   32   9649 : exists $int_lookup{$_[0]}
    100          
106             ? $_[0]
107             : croak("illegal enum value $_[0]");
108             },
109 10         67 );
110              
111 10 100       30 if($config{rev} eq 'str')
    100          
112             {
113             $type{native_to_perl} = sub {
114             exists $int_lookup{$_[0]}
115 16 100   16   1283 ? $int_lookup{$_[0]}
116             : $_[0];
117             }
118 8         28 }
119             elsif($config{rev} eq 'dualvar')
120             {
121             $type{native_to_perl} = sub {
122             exists $int_lookup{$_[0]}
123 4 100   4   2711 ? dualvar( $_[0], $int_lookup{$_[0]} )
124             : $_[0];
125 1         4 };
126             }
127              
128 10         43 \%type;
129             }
130              
131             1;
132              
133             __END__