make native trait inlining work
[gitmo/Moose.git] / lib / Moose / Meta / Method / Accessor / Native.pm
1 package Moose::Meta::Method::Accessor::Native;
2
3 use strict;
4 use warnings;
5
6 use Carp qw( confess );
7 use Scalar::Util qw( blessed weaken );
8
9 our $VERSION = '1.19';
10 $VERSION = eval $VERSION;
11 our $AUTHORITY = 'cpan:STEVAN';
12
13 use Moose::Role;
14
15 around new => sub {
16     my $orig = shift;
17     my $class   = shift;
18     my %options = @_;
19
20     exists $options{curried_arguments}
21         || ( $options{curried_arguments} = [] );
22
23     ( $options{curried_arguments}
24             && ( 'ARRAY' eq ref $options{curried_arguments} ) )
25         || confess
26         'You must supply a curried_arguments which is an ARRAY reference';
27
28     $options{definition_context} = $options{attribute}->definition_context;
29
30     $options{accessor_type} = 'native';
31
32     return $class->$orig(%options);
33 };
34
35 sub _new {
36     my $class = shift;
37     my $options = @_ == 1 ? $_[0] : {@_};
38
39     return bless $options, $class;
40 }
41
42 sub root_types { (shift)->{'root_types'} }
43
44 sub _initialize_body {
45     my $self = shift;
46
47     $self->{'body'} = $self->_compile_code( [$self->_generate_method] );
48
49     return;
50 }
51
52 sub _inline_curried_arguments {
53     my $self = shift;
54
55     return unless @{ $self->curried_arguments };
56
57     return ('unshift @_, @curried;');
58 }
59
60 sub _inline_check_argument_count {
61     my $self = shift;
62
63     my @code;
64
65     if (my $min = $self->_minimum_arguments) {
66         push @code, (
67             'if (@_ < ' . $min . ') {',
68                 $self->_inline_throw_error(
69                     sprintf(
70                         '"Cannot call %s without at least %s argument%s"',
71                         $self->delegate_to_method,
72                         $min,
73                         ($min == 1 ? '' : 's'),
74                     )
75                 ) . ';',
76             '}',
77         );
78     }
79
80     if (defined(my $max = $self->_maximum_arguments)) {
81         push @code, (
82             'if (@_ > ' . $max . ') {',
83                 $self->_inline_throw_error(
84                     sprintf(
85                         '"Cannot call %s with %s argument%s"',
86                         $self->delegate_to_method,
87                         $max ? "more than $max" : 'any',
88                         ($max == 1 ? '' : 's'),
89                     )
90                 ) . ';',
91             '}',
92         );
93     }
94
95     return @code;
96 }
97
98 sub _inline_return_value {
99     my $self = shift;
100     my ($slot_access, $for_writer) = @_;
101
102     return (
103         'return ' . $self->_return_value($slot_access, $for_writer) . ';',
104     );
105 }
106
107 sub _minimum_arguments { 0 }
108 sub _maximum_arguments { undef }
109
110 override _inline_get => sub {
111     my $self = shift;
112     my ($instance) = @_;
113
114     return $self->_slot_access_can_be_inlined
115         ? super()
116         : $instance . '->$reader';
117 };
118
119 override _inline_store => sub {
120     my $self = shift;
121     my ($instance, $value) = @_;
122
123     return $self->_slot_access_can_be_inlined
124         ? super()
125         : $instance . '->$writer(' . $value . ')';
126 };
127
128 override _eval_environment => sub {
129     my $self = shift;
130
131     my $env = super();
132
133     $env->{'@curried'} = $self->curried_arguments;
134
135     return $env if $self->_slot_access_can_be_inlined;
136
137     my $reader = $self->associated_attribute->get_read_method_ref;
138     $reader = $reader->body if blessed $reader;
139
140     $env->{'$reader'} = \$reader;
141
142     my $writer = $self->associated_attribute->get_write_method_ref;
143     $writer = $writer->body if blessed $writer;
144
145     $env->{'$writer'} = \$writer;
146
147     return $env;
148 };
149
150 sub _slot_access_can_be_inlined {
151     my $self = shift;
152
153     return $self->is_inline && $self->_instance_is_inlinable;
154 }
155
156 no Moose::Role;
157
158 1;