Expand Read + Write + Seek object

Hey folks, I need to truncate a file to a larger size. The problem is, the struct I'm using defines the object-to-be-resized as a type T: Read + Write + Seek which is in principle what a file is, but crucially, none of these traits provide a set_len method. This exists on File rather than one of it's many implemented traits.

My question is how can I cause the buffer to expand with only those three traits?


Truncate only makes sense when shrinking. If you want to make the file bigger, you need to give it data. So just seek to the end and then write however many bytes you want to expand it by.

I feel this highlights that File isn't the union of those three disjoint sets of abilities (traits). From that vantage point, set_len is an ability of Seek + Write and thus would need it's own trait in order to have its own method in generic context.

(Seeking to the end and appending 0s isn't necessarily the same thing, as some File implementations may have optimized ways to 0-extend a file (sparse files).)

Well, you're totally able to seek past the end of a file and try to write to it. I would guess the standard library File would error, but the traits wouldn't mind.

1 Like

Meaning, you could write an impl Read + Write + Seek that wraps the standard library File, but calls set_len instead of returning an error.

I took the OP to mean that they're stuck in the context of having a T: Read + Write + Seek and were thus out of luck without specialization. If I'm wrong and they're in the context of having ahold of the File non-generically too, I agree a new type would open up a way to call set_len.

Interesting question on what "seek past the end and write" does though... the implementations of those traits are tragically underdocumented (though honestly if they were properly documented they'd probably just say "we do whatever your OS does" at best).

Writing a single byte (while taking more care than that quick experiment did[1]) may in fact get you some (but not all) of the optimized behavior.

(Note that appending won't work for all T: Read + Write + Seek either, e.g. Cursor<&mut [u8]>.)

  1. check position before and after write, fall back to attempt full appending ↩︎

1 Like

Thanks to everyone's input! I was able to get around my problem by using the behaviour of files (which is to expand if it doesn't fit) and define all other types to be invalid if they don't do this, which would result in an error, which can then be propagated.

It's not a nice solution but ultimately it's the one which gives the most well-defined behaviour, which we rustaceans love.....

Thanks guys

1 Like

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.