well-typed / cborg

Binary serialisation in the CBOR format
https://hackage.haskell.org/package/cborg
191 stars 86 forks source link

serialise: Usage without requiring `Serialise` instances #329

Open ocharles opened 12 months ago

ocharles commented 12 months ago

From what I can tell, the serialise library requires instances of Serialise. This is unfortunate as it requires:

It would be great if serialise had serialiseEncoding :: Encoding -> ByteString and deserialiseWith :: Decoder s a -> Bytestring -> a.

Alternatively, we would need a type that has id implementations

adamgundry commented 11 months ago

@ocharles perhaps I'm misunderstanding your question, but it sounds like you should be depending on cborg directly, rather than using serialise? Essentially all serialise includes is the Serialise class/instances and a few utility functions; all the encoding/decoding stuff lives in cborg.

ocharles commented 11 months ago

Yes and no. I do want access to Serialise (the class), because then I can easily whip up a decoder for [[Foo]], for example. However, cborg's documentation states:

Note, however, that cborg does not itself aim to be a serialisation library; it merely serves as the substrate on which such a library might be built. See the serialise library if you are looking for convenient serialisation of Haskell values.

Which makes me think I shouldn't directly use cborg, unless I really need to.

I did also see that https://hackage.haskell.org/package/serialise-0.2.6.1/docs/src/Codec.Serialise.html#deserialise is an actual implementation and not a proxy to something in cborg, which makes me think I should be using serialise.

It's also a minor annoyance to need two dependencies, but at the end of the day that's very minor.

So I guess it mostly comes down to either only needing to depend on serialise. Happy for it to be closed if it doesn't seem worth expanding the API just for that!

adamgundry commented 11 months ago

I suspect (but have not carefully verified) that there is not much difference in practice between Codec.Serialise.deserialise[OrFail] vs. Codec.CBOR.Read.deserialiseFromBytes decode, and I don't think depending on both packages is a big problem. But I do agree that since e.g. Codec.Serialise.Decoding exposes a Decoder-based interface, it would make sense for serialise to expose deserialiseFromBytes and better encapsulate the cborg interface.

(A similar issue I've faced is wanting to encode a list [T] with a custom encoder rather than the one from the Serialise T instance, where ideally I wanted defaultEncodeList to be slightly generalised to encodeListWith :: (a -> Encoding) -> [a] -> Encoding.)