Created
April 15, 2024 15:48
-
-
Save sheaf/d5c2a5b111a441b1fd63d33d66f84d23 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{-# LANGUAGE DataKinds #-} | |
{-# LANGUAGE DerivingStrategies #-} | |
{-# LANGUAGE FlexibleInstances #-} | |
{-# LANGUAGE GeneralisedNewtypeDeriving #-} | |
{-# LANGUAGE OverloadedStrings #-} | |
{-# LANGUAGE ScopedTypeVariables #-} | |
{-# LANGUAGE StandaloneKindSignatures #-} | |
{-# LANGUAGE TypeApplications #-} | |
{-# LANGUAGE TypeOperators #-} | |
module Main (main) where | |
-- base | |
import Data.Kind | |
( Type ) | |
-- binary | |
import Data.Binary | |
( Binary, get, put ) | |
import qualified Data.Binary as Binary | |
-- bytestring | |
import qualified Data.ByteString.Lazy as LBS | |
-------------------------------------------------------------------------------- | |
main :: IO () | |
main = case filter (not . snd) tests of | |
[] -> putStrLn "OK, all tests passed." | |
bad -> do | |
let plural = if length bad > 1 then "" else "s" | |
error $ unlines $ | |
( "The following test" ++ plural ++ " failed:" ) | |
: map ( ( " - " ++ ) . fst ) bad | |
tests :: [(String, Bool)] | |
tests = | |
[ doTest "Word" data1 | |
, doTest "ByteString" data2 | |
, doTest "MyByteString" data3 | |
, doTest "[Int]" data4 ] | |
where | |
doTest str a = (str, a == roundTrip a) | |
roundTrip :: forall a. Binary a => a -> a | |
roundTrip val1 = | |
let val2 :: LBS.ByteString | |
val2 = Binary.encode @(InScope User a) (InScope val1) | |
val3 :: LBS.ByteString | |
InScope val3 = Binary.decode @(InScope System LBS.ByteString) val2 | |
val4 :: LBS.ByteString | |
val4 = Binary.encode @(InScope System LBS.ByteString) (InScope val3) | |
val5 :: a | |
InScope val5 = Binary.decode @(InScope User a) val4 | |
in val5 | |
data1 :: Word | |
data1 = 13 | |
data2 :: LBS.ByteString | |
data2 = "hello" | |
data3 :: MyByteString | |
data3 = MyByteString "goodbye" | |
data4 :: [Int] | |
data4 = [4,5,6,7] | |
data Scope = User | System | |
type InScope :: Scope -> Type -> Type | |
newtype InScope scope ty = InScope ty | |
instance Binary arg => Binary (InScope User arg) where | |
put (InScope arg) = put @LBS.ByteString (Binary.encode arg) | |
get = do | |
dat <- get @LBS.ByteString | |
case Binary.decodeOrFail dat of | |
Left (_,_, err) -> fail err | |
Right (_,_,res) -> return $ InScope res | |
instance arg ~ LBS.ByteString => Binary (InScope System arg) where | |
put (InScope arg) = put arg | |
get = InScope <$> get | |
newtype MyByteString = MyByteString LBS.ByteString | |
deriving newtype (Eq, Binary) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment