my class CompUnit::PrecompilationUnit::File does CompUnit::PrecompilationUnit {
    has CompUnit::PrecompilationId:D $.id   is built(:bind) is required;
    has IO::Path                     $.path is built(:bind);
    has Str $!checksum        is built;
    has Str $!source-checksum is built;
    has CompUnit::PrecompilationDependency @!dependencies is built(:bind);
    has $!bytecode            is built(:bind);
    has $!store               is built(:bind);

    has Bool $!initialized;
    has IO::Handle $!handle;
    has $!update-lock;

    submethod TWEAK(--> Nil) {
        if $!bytecode {
            $!checksum = nqp::sha1($!bytecode.decode('iso-8859-1'));
            $!initialized := True;
        }
        else {
            $!initialized := False;
        }
        $!update-lock := Lock.new;
    }

    method modified(--> Instant:D) {
        $!path.modified
    }

    method !read-dependencies(--> Nil) {
        $!initialized || $!update-lock.protect: {
            unless $!initialized {  # another thread beat us
                $!handle := $!path.open(:r) unless $!handle;

                $!checksum        = $!handle.get;
                $!source-checksum = $!handle.get;
                my $dependency   := $!handle.get;
                my $dependencies := nqp::create(IterationBuffer);
                while $dependency {
                    nqp::push(
                      $dependencies,
                      CompUnit::PrecompilationDependency::File.deserialize($dependency)
                    );
                    $dependency := $!handle.get;
                }
                nqp::bindattr(@!dependencies,List,'$!reified',$dependencies);
                $!initialized := True;
            }
        }
    }

    method dependencies(--> Array[CompUnit::PrecompilationDependency]) {
        self!read-dependencies;
        @!dependencies
    }

    method bytecode(--> Buf:D) {
        $!update-lock.protect: {
            unless $!bytecode {
                self!read-dependencies;
                $!bytecode := $!handle.slurp(:bin,:close)
            }
            $!bytecode
        }
    }

    method bytecode-handle(--> IO::Handle:D) {
        self!read-dependencies;
        $!handle
    }

    method source-checksum() is rw {
        self!read-dependencies;
        $!source-checksum
    }

    method checksum() is rw {
        self!read-dependencies;
        $!checksum
    }

    method Str(--> Str:D) {
        self.path.Str
    }

    method close(--> Nil) {
        $!update-lock.protect: {
            $!handle.close if $!handle;
            $!handle      := IO::Handle;
            $!initialized := False;
        }
    }

    method save-to(IO::Path $precomp-file) {
        my $handle := $precomp-file.open(:w);
        $handle.print($!checksum ~ "\n");
        $handle.print($!source-checksum ~ "\n");
        $handle.print($_.serialize ~ "\n") for @!dependencies;
        $handle.print("\n");
        $handle.write($!bytecode);
        $handle.close;
        $!path := $precomp-file;
    }

    method is-up-to-date(
      CompUnit::PrecompilationDependency:D $dependency,
      Bool :$check-source
    --> Bool:D) {
        my $result := self.CompUnit::PrecompilationUnit::is-up-to-date($dependency, :$check-source);
        $!store.remove-from-cache($.id) unless $result;
        $result
    }
}

# vim: expandtab shiftwidth=4
