-
Notifications
You must be signed in to change notification settings - Fork 18.8k
Closed
Milestone
Description
embed.openFile could trivially implement io.ReaderAt.
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: wazero/wazero#967, and now wazero/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.
icholy, Jorropo, ericlagergren, bcmills, komuw and 5 more