Add `Seek::seek_relative`?

BufReader::seek_relative was added to address #31100. As explained in that issue, BufReader's stable API required that the internal buffer was dumped on any call to seek, so the new method was added to expose a way to seek without doing dumping the buffer.

Unfortunately, there isn't really a good way to take advantage of the method in generic code. If a method takes a R: Read + Seek, then only the regular (inefficient) seek implementation is exposed. The method could itself create a BufReader<R> and then call seek_relative, but then depending on what R is, it might end up making a BufReader<BufReader<File>> or BufReader<Cursor<Vec<u8>>> or some other silly type.

If the Seek trait had a seek_relative method (with the straightforward implementation as a default impl) then this could be solved.

Would not that require then teaching everybody to use seek_relative for more performant seeks? I think it makes more sense to add a newtype wrapper (or encode relative seek strategy at type level via some other means like extra type parameter to BufReader with default value) which changes relative seek strategy so that existing generic code does not need to be modified: it is not like code accepting R: Read + Seek can call BufReader::into_inner after seeking which as far as I understand was the sole reason existing behaviour was preserved.

Actually in my opinion it would have made more sense to encode relative seek strategy at type level when seek_relative was introduced and add function(s) to change type instead, but that ship has sailed. Still possible to add that parameter and sync_with_inner() (to achieve what seek(SeekFrom::Current(0)) currently does regardless of relative seek strategy in code which does know it has BufReader, but does not want to restrict strategy) though, that just can create confusion.

The BufReader::seek gotcha already exists and I think the ship has long since sailed on preventing it. As a result, we already have to teach everybody about BufReader::seek_relative.

My proposal would not require any new action from end users. They already have to know about wrapping file accesses in a BufReader, but wouldn't have to make any other changes to their code. Library authors whose code does a lot of seeks would however gain a new tool to work around the gotcha.

On the other hand, creating a wrapper type or an extra type parameter on BufReader would require action by end users. Specifically, they'd have to be the ones to decide to use the wrapper type based on a guess that the library function they're calling will do a lot of seeks.

2 Likes

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.