Andrew Thaddeus Martin
Andrew Thaddeus Martin

Reputation: 3285

Safely serialize Text to Bytestring

The text package does not provide an instance of Binary to encode/decode text. I have read about and understand the reasoning behind this (namely, Text should be encoding-agnostic). However, I need a Binary instance of Text. I've found that there is a package called text-binary that does this. However, the instance is as follows:

instance Binary T.Text where
    put = put . T.encodeUtf8
    get = T.decodeUtf8 <$> get

Pretty good, except that decodeUtf8 is a partial function, so I'd rather be using decodeUtf8' and passing the failure through the Get monad. I can't figure out how to fail correctly with the Get monad. Just from looking around in Data.Binary.Get, I see this:

data Decoder a = Fail !B.ByteString {-# UNPACK #-} !ByteOffset String
          | Partial (Maybe B.ByteString -> Decoder a)
          | Done !B.ByteString {-# UNPACK #-} !ByteOffset a

Which seems to indicate that there is a way to do what I want. I just can't see how the library authors intend for it to be used. I appreciate any insights that a more learned mind than my own has to offer.

Upvotes: 2

Views: 134

Answers (1)

leftaroundabout
leftaroundabout

Reputation: 120741

Well, though we tend to disregard it, the Monad class still has that yucky fail method:

   get = do
      utf8'd <- get 
      case T.decodeUtf8' utf8'd of
         Just t  -> return t
         Nothing -> fail "No parse for UTF-8 Text"

I'm not sure if it should still be considered "correct" to use fail, but it seems to be the obvious thing for a case like this. I suppose even if it's removed from the Monad class, there'll be some other class MonadPlus m => MonadFail m where fail :: String -> m a which Get will be an instance of.

Upvotes: 4

Related Questions