Open DemiMarie opened 2 months ago
I briefly considered this as an alternative to the current deferForeignPtrAvailability
stuff in 2022. But:
ByteString
s unsafely using ByteString
internals to be rewritten.
ByteString
s directly using the constructor.unsafeReadFromByteString :: ByteString -> (ForeignPtr Word8 -> Int -> IO a) -> a
is not really any safer than accursedUnutterablePerformIO
, although at least the conditions under which it is safe are probably more obvious to the uninitiated.unsafeReadFromByteStringIO :: ByteString -> (ForeignPtr Word8 -> Int -> IO a) -> IO a
is needed to allow reading from more than one ByteString
in a single IO
state thread.From my perspective, the most principled solution would be for base
to provide both MutableForeignPtr
and ImmutableForeignPtr
types, and just store an ImmutableForeignPtr Word8
in each ByteString
. Then, read operations don't need to pretend to do IO
, and initializing a ByteString
ultimately involves calling an unsafeFreezeMutableForeignPtr
primitive at the right time.
But I don't know how to realistically get there from the current status quo.
Could ByteString
provide the needed types itself?
Could
ByteString
provide the needed types itself?
There is some argument for doing so. After all, the only difference between a ByteString
and an ImmutableForeignPtr Word8
is that the former stores the length of (the relevant part of) its buffer.
But the main obstacles are impact assessment and migration, rather than finding the best possible home for the relevant types.
This allows passing the state thread used to initialize the ByteString’s pointer to the functions that access that pointer. As a result,
deferForeignPtrAvailability
can be removed, and most or all uses ofaccursedUnutterablePerformIO
can be replaced with a safer function that takes aState# RealWorld
argument.