The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.
package MaxMind::DB::Reader::Role::Sysreader;
{
  $MaxMind::DB::Reader::Role::Sysreader::VERSION = '0.040003';
}
BEGIN {
  $MaxMind::DB::Reader::Role::Sysreader::AUTHORITY = 'cpan:TJMATHER';
}

use strict;
use warnings;
use namespace::autoclean;
use autodie;

use Carp qw( confess );
use MaxMind::DB::Types qw( FileHandle );

use Moo::Role;

has data_source => (
    is      => 'ro',
    isa     => FileHandle,
    lazy    => 1,
    builder => '_build_data_source',
);

sub _read {
    my $self          = shift;
    my $buffer        = shift;
    my $offset        = shift;
    my $wanted_size   = shift;
    my $seek_from_end = shift;

    my $source = $self->data_source();
    seek $source, $offset, $seek_from_end ? 2 : 0;

    my $read_offset = 0;
    while (1) {
        my $read_size = read(
            $source,
            ${$buffer},
            $wanted_size,
            $read_offset,
        );

        confess $! unless defined $read_size;

        # This error message doesn't provide much context, but it should only
        # be thrown because of a fundamental logic error in the reader code,
        # _or_ because the writer generated a database with broken pointers
        # and/or broken data elements.
        confess 'Attempted to read past the end of a file/memory buffer'
            if $read_size == 0;

        return if $wanted_size == $read_size;

        $wanted_size -= $read_size;
        $read_offset += $read_size;
    }

    return;
}

sub _build_data_source {
    my $class = ref shift;

    die "You must provide a data_source parameter to the constructor for $class";
}

1;