linear-base icon indicating copy to clipboard operation
linear-base copied to clipboard

How to bring other `Handle`-using functions into the RIO world?

Open endgame opened this issue 2 years ago • 2 comments

TL;DR: linear-base seems to not provide me with a way to turn functions of type Handle -> IO a into Handle %1 -> RIO (Ur? a, Handle), and this seems to stop me from doing anything with ByteString.

I am trying to build a library to parse (and later, write) a data archive format from an old game, and do it with linear types to stretch myself. The file begins with a header listing the contents of all files in the archive, and their byte offsets into the archive itself. I want to write a function to return a ByteString stream from a Handle, when given the Record describing the name/offset/etc.

If I was using standard Haskell, I would write something like this, and trust the user not to abuse the Handle while streaming (we must hSeek to the offset and then stream the required number of bytes:

hGetRecord :: MonadIO m => Record -> Handle -> ByteStream m ()

But in linear-base, we seem to hit the following:

  1. We can't use the standard streaming types, we have to use the one in Streaming.Linear.
  2. This means we can't use the streaming-bytestring ByteStream type, and must use Stream (Of ByteString) from linear-base. Annoying, but OK.

The function I think I want to write with linear types:

hGetRecord :: Record -> Handle %1 -> Stream (Of ByteString) RIO Handle

This should let me safely seek the handle, without anyone interfering with it until the streaming is finished. But I cannot lift the ByteString I/O functions from System.IO.IO to RIO because the constructor for System.IO.Linear.Resource.Handle is not exported.

Describe the solution you'd like

I think that variants of unsafeFromSystemIOResource etc that allow me to bring Handle-using IO functions into RIO and have them play nicely with the existing Handle type in linear-base would give me everything I need, but that's probably an unsafe level of power. The functions I need are RIO versions of:

  • openBinaryFile
  • hSeek
  • Data.ByteString.Lazy.hGet

endgame avatar Aug 12 '22 12:08 endgame

I should add that while I can probably do the wrapping and unwrapping necessary with the Unsafe.Linear.coerce function and it's possibly reasonable to hide that behind an abstraction boundary, it's not fair to ask potential users to do the same: the unavailability of a RIO version of openBinaryFIle is probably a hard blocker on this type of interface.

endgame avatar Aug 12 '22 12:08 endgame

Hi, thanks for your interest.

I'll get back to you on this issue and your PR very soon.

aspiwack avatar Aug 22 '22 15:08 aspiwack