Exception-FFI-ErrorCode

 view release on metacpan or  search on metacpan

lib/Exception/FFI/ErrorCode.pm  view on Meta::CPAN

package Exception::FFI::ErrorCode 0.03 {

  use warnings;
  use 5.020;
  use constant 1.32 ();
  use experimental qw( signatures postderef );
  use Ref::Util qw( is_plain_arrayref );

  # ABSTRACT: Exception class based on integer error codes common in C code


  my %human_codes;

  sub import ($, %args)
  {
    my $class       = delete $args{class}       || caller;
    my $const_class = delete $args{const_class} || $class;
    my $codes       = delete $args{codes}       || {};

    if(%args) {
      require Carp;
      Carp::croak("Unknown options: @{[ sort keys %args ]}");
    }

    {
      no strict 'refs';
      push @{ "$class\::ISA" }, 'Exception::FFI::ErrorCode::Base';
    }


    foreach my $name (keys $codes->%*)
    {
      my($code, $human) = do {
        my $v = $codes->{$name};
        is_plain_arrayref $v ? @$v : ($v,$name);
      };
      constant->import("$const_class\::$name", $code);
      $human_codes{$class}->{$code} = $human;
    }
  }

  sub detect ($class)
  {
    my $sub;
    if(Carp::Always->can('import'))
    {
      require Sub::Identify;
      $Carp::CarpInternal{"Exception::FFI::ErrorCode::Base"}++;
      $sub = sub {
        [Sub::Identify::get_code_info($SIG{__WARN__})]->[0] eq 'Carp::Always'
      };
    }
    else
    {
      $sub = sub { 0 };
    }
    no warnings 'redefine';
    *Exception::FFI::ErrorCode::Base::_carp_always = $sub;
  }

  __PACKAGE__->detect;

  package Exception::FFI::ErrorCode::Base 0.03 {

    sub _carp_always;

    use Class::Tiny qw( package filename line code trace _longmess );
    use Ref::Util qw( is_blessed_ref );
    use overload
        '""' => sub ($self,@) {
          if(_carp_always)
          {
            return $self->_longmess;
          }
          else
          {
            return $self->as_string . "\n";
          }
        },
        bool => sub { 1 }, fallback => 1;

    sub throw ($proto, %rest)
    {
      my($package, $filename, $line) = caller( delete $rest{frame} // 0 );

      my $self;
      if(is_blessed_ref $proto)
      {
        $self = $proto;
        $self->package($package);
        $self->filename($filename);
        $self->line($line);
      }
      else
      {
        $self = $proto->new(
          %rest,
          package  => $package,
          filename => $filename,
          line     => $line,
        );
      }
      my $trace = $self->get_stack_trace;
      $self->trace($trace) if $trace;
      $self->_longmess(Carp::longmess($self->strerror)) if _carp_always;
      die $self;
    }

    sub get_stack_trace ($)
    {
      if($ENV{EXCEPTION_FFI_ERROR_CODE_STACK_TRACE})
      {
        require Devel::StackTrace;
        return Devel::StackTrace->new(
          ignore_package => 'Exception::FFI::ErrorCode::Base',
        );
      }
      else
      {
        return undef;
      }
    }

    sub strerror ($self)
    {
      my $code = $self->code;
      $code = 0 unless defined $code;
      my $str = $human_codes{ref $self}->{$code};



( run in 2.965 seconds using v1.01-cache-2.11-cpan-39bf76dae61 )