Lets say I’ve got a good old ByteString conduit source:
source :: Conduit () ByteString m a
And I’ve got a conduit that transforms this into tokens
data Token = AnInt Int | OtherStuff String | EndOfLine | ...
myTransform1 :: Conduit ByteString Token m ()
And lets say I’ve also got:
myTransform2 :: Settings -> Conduit Token Token m ()
myTransform3 :: Conduit Token ByteString m ()
sink :: Conduit ByteString () m ()
Ordinarily, I would want to process one line, which gives me the Settings
on how to process the rest.
But, if the Settings
are invalid, I don’t want to continue tokenising my input. I just want to pass the whole conduit through unchanged.
i.e. I just want to send the remainder of source
straight to sink
, not through myTransform(1,2,3)
What I think needs to be done is what I’m using to read from myTransform1
needs to tell myTransform1
, after EndOfLine
has been pulled from it, to push the “leftovers” from myTransform1
back to source
.
But I don’t think I can do this. After all, myTransform1
is basically just await
ing on bytestrings and yield
ing tokens. Internally there’s an index of where it’s up to in the currently processing bytestring, but that’s not exposed to conduit.
I guess I could change myTransform1
to:
data AbortAtEOL = YesAbortAtEOL | NoAbortAtEOL
myTransform1 :: AbortAtEOL -> Conduit ByteString Token m ()
And have the conduit, if it receives YesAbortAtEOL
as an option, then just push any leftovers back once it receives an EndOfLine
token.
But I note that this solution is quite specific. What about if in general I have a downstream provider, and it may want to perform some computation before deciding how to continue, but it doesn’t want to lose any data in doing so?
Or am I just going about solving this in a completely wrong way?
In short, I want to process a little bit of a Conduit ByteString source, but if something goes wrong, I just want to pass it through to a sink without losing information.