X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?a=blobdiff_plain;f=lib%2FMoose%2FMeta%2FMethod%2FAccessor%2FNative%2FWriter.pm;h=165c6197e909ba5fe0b205de9f9219642b541100;hb=0f4afc62a4744c96758cf21d234b654f5c273828;hp=60b672db64e61d4b36997325016da9229ef6331c;hpb=5df5498008faffca14682ca93face59a9a23a5a6;p=gitmo%2FMoose.git diff --git a/lib/Moose/Meta/Method/Accessor/Native/Writer.pm b/lib/Moose/Meta/Method/Accessor/Native/Writer.pm index 60b672d..165c619 100644 --- a/lib/Moose/Meta/Method/Accessor/Native/Writer.pm +++ b/lib/Moose/Meta/Method/Accessor/Native/Writer.pm @@ -3,92 +3,161 @@ package Moose::Meta::Method::Accessor::Native::Writer; use strict; use warnings; -our $VERSION = '1.13'; -$VERSION = eval $VERSION; -our $AUTHORITY = 'cpan:STEVAN'; +use List::MoreUtils qw( any ); -use base 'Moose::Meta::Method::Accessor::Native'; +use Moose::Role; + +with 'Moose::Meta::Method::Accessor::Native'; + +requires '_potential_value'; sub _generate_method { my $self = shift; - my $inv = '$self'; + my $inv = '$self'; + my $slot_access = $self->_get_value($inv); - my $slot_access = $self->_inline_get($inv); + return ( + 'sub {', + 'my ' . $inv . ' = shift;', + $self->_inline_curried_arguments, + $self->_inline_writer_core($inv, $slot_access), + '}', + ); +} - my $code = 'sub {'; - $code .= "\n" . $self->_inline_pre_body(@_); +sub _inline_writer_core { + my $self = shift; + my ($inv, $slot_access) = @_; + + my $potential = $self->_potential_value($slot_access); + my $old = '@old'; + + my @code; + push @code, ( + $self->_inline_check_argument_count, + $self->_inline_process_arguments($inv, $slot_access), + $self->_inline_check_arguments('for writer'), + $self->_inline_check_lazy($inv, '$type_constraint', '$type_constraint_obj'), + ); + + if ($self->_return_value($slot_access)) { + # some writers will save the return value in this variable when they + # generate the potential value. + push @code, 'my @return;' + } + + push @code, ( + $self->_inline_coerce_new_values, + $self->_inline_copy_native_value(\$potential), + $self->_inline_tc_code($potential, '$type_constraint', '$type_constraint_obj'), + $self->_inline_get_old_value_for_trigger($inv, $old), + $self->_inline_capture_return_value($slot_access), + $self->_inline_set_new_value($inv, $potential, $slot_access), + $self->_inline_trigger($inv, $slot_access, $old), + $self->_inline_return_value($slot_access, 'for writer'), + ); + + return @code; +} - $code .= "\n" . 'my $self = shift;'; +sub _inline_process_arguments { return } - $code .= "\n" . $self->_inline_check_lazy($inv); +sub _inline_check_arguments { return } - $code .= "\n" . $self->_inline_curried_arguments; +sub _inline_coerce_new_values { return } - $code .= "\n" . $self->_inline_check_argument_count; +sub _writer_value_needs_copy { + my $self = shift; - $code .= "\n" . $self->_inline_process_arguments; + return $self->_constraint_must_be_checked; +} - $code .= "\n" . $self->_inline_check_arguments; +sub _constraint_must_be_checked { + my $self = shift; + + my $attr = $self->associated_attribute; - my $new_value = $self->_new_value($slot_access); - my $potential_value = $self->_potential_value($slot_access); + return $attr->has_type_constraint + && (!$self->_is_root_type( $attr->type_constraint ) + || ( $attr->should_coerce && $attr->type_constraint->has_coercion) + ); +} - $code .= "\n" . $self->_inline_copy_value( \$potential_value ); +sub _is_root_type { + my $self = shift; + my ($type) = @_; - $code .= "\n" - . $self->_inline_tc_code( - $new_value, - $potential_value - ); + my $name = $type->name; - $code .= "\n" . $self->_inline_get_old_value_for_trigger($inv); - $code .= "\n" . $self->_capture_old_value($slot_access); + return any { $name eq $_ } @{ $self->root_types }; +} - $code .= "\n" - . $self->_inline_set_new_value( - $inv, - $potential_value - ); +sub _inline_copy_native_value { + my $self = shift; + my ($potential_ref) = @_; - $code .= "\n" . $self->_inline_post_body(@_); - $code .= "\n" . $self->_inline_trigger( $inv, $slot_access, '@old' ); + return unless $self->_writer_value_needs_copy; - $code .= "\n" . $self->_return_value( $inv, '@old' ); + my $code = 'my $potential = ' . ${$potential_ref} . ';'; - $code .= "\n}"; + ${$potential_ref} = '$potential'; return $code; } -sub _inline_process_arguments {q{}} +around _inline_tc_code => sub { + my $orig = shift; + my $self = shift; + my ($value, $tc, $tc_obj, $for_lazy) = @_; + + return unless $for_lazy || $self->_constraint_must_be_checked; + + return $self->$orig(@_); +}; -sub _inline_check_arguments {q{}} +around _inline_check_constraint => sub { + my $orig = shift; + my $self = shift; + my ($value, $tc, $tc_obj, $for_lazy) = @_; -sub _value_needs_copy {0} + return unless $for_lazy || $self->_constraint_must_be_checked; -sub _inline_tc_code {die} + return $self->$orig(@_); +}; -sub _inline_check_coercion {die} +sub _inline_capture_return_value { return } -sub _inline_check_constraint { +sub _inline_set_new_value { my $self = shift; - return q{} unless $self->_constraint_must_be_checked; + return $self->_inline_store_value(@_) + if $self->_writer_value_needs_copy + || !$self->_slot_access_can_be_inlined + || !$self->_get_is_lvalue; + + return $self->_inline_optimized_set_new_value(@_); +} + +sub _get_is_lvalue { + my $self = shift; - return $self->SUPER::_inline_check_constraint( $_[0] ); + return $self->associated_attribute->associated_class->instance_metaclass->inline_get_is_lvalue; } -sub _constraint_must_be_checked {die} +sub _inline_optimized_set_new_value { + my $self = shift; -sub _capture_old_value { return q{} } + return $self->_inline_store_value(@_); +} -sub _inline_set_new_value { +sub _return_value { my $self = shift; + my ($slot_access) = @_; - return $self->SUPER::_inline_store(@_); + return $slot_access; } -sub _return_value { return q{} } +no Moose::Role; 1;