crystal-lang / crystal

The Crystal Programming Language
https://crystal-lang.org
Apache License 2.0
19.47k stars 1.62k forks source link

Add IO#read_string? and #read_bytes? #6905

Open straight-shoota opened 6 years ago

straight-shoota commented 6 years ago

As suggested in https://github.com/crystal-lang/crystal/pull/6873#issuecomment-424730829, the IO methods read_string and read_bytes don't have a non-raising counterpart which would be useful in situations where it's optional if the IO can provide an additional value.

See https://github.com/crystal-lang/crystal/pull/6501#discussion_r208516591 for another example where read_bytes? would be useful but a workaround needed to be employed.

Implementing #read_string? should be pretty easy. For #read_bytes?, we'd probably also need IO::ByteFormat#decode? or let IO::ByteFormat#decode return nil instead of raising. But then we'd need to ensure a proper exception is raised.

asterite commented 1 year ago

I don't think these methods should exist. What if read_bytes? reads a few bytes but not enough to decode the data? How can you recover those lost bytes?

straight-shoota commented 1 year ago

read_bytes? would be for use cases like https://forum.crystal-lang.org/t/read-nrrd-file-with-attached-header-and-gzipped-data/5355 where you know from the data format description that you can either read the full bytes or not. Anything in between would be a failure state and should probably raise. Excess bytes that have been read in the method could be attached to the exception if that's useful.

HertzDevil commented 1 year ago

What if read_bytes? reads a few bytes but not enough to decode the data? How can you recover those lost bytes?

In C you would ungetc the bytes already read. However I guess it isn't very appropriate to implement a similar in-memory buffer for every IO in Crystal

asterite commented 1 year ago

In the end I'm thinking that read_bytes can also fail in the same way, and right now there's no way to recover the lost bytes. So it's probably fine to add read_bytes? However, we must clearly document that if nil is returned it might be because there wasn't enough data to read, but some of it might have been read (IOs that have peek could sometimes avoid advancing the pointer)