Skip to content

embed: openFile should implement ReaderAt #57803

Closed
@ncruces

Description

@ncruces

embed.openFile could trivially implement io.ReaderAt.

go/src/embed/embed.go

Lines 348 to 381 in 15605ca

var (
_ io.Seeker = (*openFile)(nil)
)
func (f *openFile) Close() error { return nil }
func (f *openFile) Stat() (fs.FileInfo, error) { return f.f, nil }
func (f *openFile) Read(b []byte) (int, error) {
if f.offset >= int64(len(f.f.data)) {
return 0, io.EOF
}
if f.offset < 0 {
return 0, &fs.PathError{Op: "read", Path: f.f.name, Err: fs.ErrInvalid}
}
n := copy(b, f.f.data[f.offset:])
f.offset += int64(n)
return n, nil
}
func (f *openFile) Seek(offset int64, whence int) (int64, error) {
switch whence {
case 0:
// offset += 0
case 1:
offset += f.offset
case 2:
offset += int64(len(f.f.data))
}
if offset < 0 || offset > int64(len(f.f.data)) {
return 0, &fs.PathError{Op: "seek", Path: f.f.name, Err: fs.ErrInvalid}
}
f.offset = offset
return offset, nil
}

That's the entire proposal.

Rationale

io.ReaderAt can be emulated with io.ReadSeeker, but this doesn't satisfy the goroutine safety of io.ReaderAt: “Clients of ReadAt can execute parallel ReadAt calls on the same input source.”

This came up twice now on implementing wazero syscalls, that follow pread semantics: tetratelabs/wazero#967, and now tetratelabs/wazero#1037.
It got its own mention in that project's design rationale.

It is also of note that io.ReaderAt is directly called out on the fs.File documentation: A file may implement io.ReaderAt or io.Seeker as optimizations.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions