{-# LANGUAGE TypeFamilies, OverloadedStrings #-} {- | Module : Data.Graph.Planar.Serialisation.PlanarCode Description : Implementation of PLANAR CODE. Copyright : (c) Ivan Lazar Miljenovic License : 3-Clause BSD-style Maintainer : Ivan.Miljenovic@gmail.com -} module Data.Graph.Planar.Serialisation.PlanarCode(PlanarCode(..)) where import Data.Graph.Planar(SerialisedGraph) import Data.Graph.Planar.Serialisation.Internal import Blaze.ByteString.Builder import Data.Attoparsec.ByteString.Lazy import qualified Data.ByteString as SBS import Data.Foldable(foldMap) import Control.Applicative((<*)) import Data.Monoid(Monoid(..)) import Control.Monad(replicateM) -- ----------------------------------------------------------------------------- {- | PLANAR_CODE is the most common encoding for planar graphs, and is supported by various generation and visualisation tools. It is a binary format and not intended to be human-readable. The default encoding only supports graphs with @<256@ nodes, and takes @2*|E|+|N|+1@ bytes per graph. Please note that PLANAR_CODE is /not/ suitable for graphs with multiple loops on vertices (multiple edges with distinct endpoints however are catered for). As such, no guarantees are made about what happens with multiple loops. -} data PlanarCode = PlanarCode deriving (Eq, Ord, Show, Read) instance PlanarEncoding PlanarCode where type NLabel PlanarCode = () type ELabel PlanarCode = () putSG = const putPlanarCode getSG = const getPlanarCode putName = const $ fromByteString ">>planar_code<<" getName = string ">>planar_code<<" >> return PlanarCode sepByNewline = const False putPlanarCode :: ((Int,Int),SerialisedGraph n e) -> Builder putPlanarCode ((ord,_),sg) = fromWord8 (fromIntegral ord) `mappend` foldMap (fromWrite . putNode . nodeEdgesSer) sg where putNode es = foldMap (writeWord8 . succ . fromIntegral . toNodeSer) es `mappend` writeWord8 0 -- Need succ here, because the SerialisedGraph is 0-based, but PC is 1-based. getPlanarCode :: Parser (SerialisedGraph () ()) getPlanarCode = do num <- fromIntegral `fmap` anyWord8 ess <- replicateM num getNode -- Convert to 0-based Word values let ess' = map (map $ fromIntegral . pred) ess return $ processPC ess' where getNode = SBS.unpack `fmap` takeWhile1 (/= 0) <* anyWord8 -- will be 0