packages feed

algebraic-graphs-io-0.5: src/Algebra/Graph/IO/Serialise.hs

{-# LANGUAGE BangPatterns #-}
{-# LANGUAGE LambdaCase #-}
{-|
Module      : Algebra.Graph.IO.Serialise
Description : 'serialise' instances for algebraic-graphs types
Copyright   : (c) Marco Zocca, 2022
Maintainer  : ocramz
Stability   : experimental
Portability : POSIX

Orphan instances for compatibility between 'algebraic-graphs' and 'serialise'.

Import only if you know what you're doing.
-}
module Algebra.Graph.IO.Serialise () where

-- alga
import qualified Algebra.Graph as G (Graph(..), edges, foldg)
import qualified Algebra.Graph.Labelled as GL (Graph(..), edges, foldg)
-- serialise
import qualified Codec.Serialise as CS (Serialise(..), serialise, serialiseIncremental, deserialiseOrFail, DeserialiseFailure)
import qualified Codec.Serialise.Encoding as CS (encodeListLen, encodeListLenIndef, encodeWord)
import qualified Codec.Serialise.Decoding as CS (decodeListLen, decodeListLenIndef, decodeWord)


instance CS.Serialise a => CS.Serialise (G.Graph a) where
  encode = \case
    G.Empty -> CS.encodeListLen 1 <> CS.encodeWord 0
    G.Vertex x -> CS.encodeListLen 2 <> CS.encodeWord 1 <> CS.encode x
    G.Overlay a b -> CS.encodeListLen 3 <> CS.encodeWord 2 <> CS.encode a <> CS.encode b
    G.Connect a b -> CS.encodeListLen 3 <> CS.encodeWord 3 <> CS.encode a <> CS.encode b
  decode = do
    n <- CS.decodeListLen
    t <- CS.decodeWord -- constructor tag
    case (t, n) of
      (0, 1) -> pure $ G.Empty
      (1, 2) -> do
        !x <- CS.decode
        pure $ G.Vertex x
      (2, 3) -> do
        !x <- CS.decode
        !y <- CS.decode
        pure $ G.Overlay x y
      (3, 3) -> do
        !x <- CS.decode
        !y <- CS.decode
        pure $ G.Connect x y
      e -> fail $ unwords ["unknown tag", show e]

instance (CS.Serialise e, CS.Serialise a) => CS.Serialise (GL.Graph e a) where
  encode = \case
    GL.Empty -> CS.encodeListLen 1 <> CS.encodeWord 0
    GL.Vertex x -> CS.encodeListLen 2 <> CS.encodeWord 1 <> CS.encode x
    GL.Connect e a b -> CS.encodeListLen 4 <> CS.encodeWord 2 <> CS.encode e <> CS.encode a <> CS.encode b
  decode = do
    n <- CS.decodeListLen
    t <- CS.decodeWord -- constructor tag
    case (t, n) of
      (0, 1) -> pure $ GL.Empty
      (1, 2) -> do
        !x <- CS.decode
        pure $ GL.Vertex x
      (2, 4) -> do
        !e <- CS.decode
        !x <- CS.decode
        !y <- CS.decode
        pure $ GL.Connect e x y
      e -> fail $ unwords ["unknown tag", show e]