    module Network.PublicSuffixList.Serialize (getDataStructure, putDataStructure) where

    import           Blaze.ByteString.Builder           (Builder, fromWord8,
                                                         toByteString)
    import           Blaze.ByteString.Builder.Char.Utf8 (fromText)
    import qualified Data.ByteString                    as BS
    import           Data.Foldable                      (foldMap)
    import           Data.Map                           (Map)
    import qualified Data.Map                           as Map
    import           Data.Monoid                        (mappend)
    import qualified Data.Text                          as T
    import qualified Data.Text.Encoding                 as TE

    import           Network.PublicSuffixList.Types

    getTree :: BS.ByteString -> (Tree T.Text, BS.ByteString)
    getTree :: ByteString -> (Tree Text, ByteString)
    getTree =
        Map Text (Tree Text) -> ByteString -> (Tree Text, ByteString)
    loop Map Text (Tree Text)
    forall k a. Map k a
    Map.empty
      where
        loop :: Map Text (Tree Text) -> ByteString -> (Tree Text, ByteString)
    loop Map Text (Tree Text)
    m ByteString
    bs
            | ByteString -> Bool
    BS.null ByteString
    bs = (Map Text (Tree Text) -> Tree Text
    forall e. Map e (Tree e) -> Tree e
    Node Map Text (Tree Text)
    m, ByteString
    bs)
            | HasCallStack => ByteString -> Word8
    ByteString -> Word8
    BS.head ByteString
    bs Word8 -> Word8 -> Bool
    forall a. Eq a => a -> a -> Bool
    == Word8
    0 = (Map Text (Tree Text) -> Tree Text
    forall e. Map e (Tree e) -> Tree e
    Node Map Text (Tree Text)
    m, Int -> ByteString -> ByteString
    BS.drop Int
    1 ByteString
    bs)
            | Bool
    otherwise =
                let (Text
    k, Tree Text
    v, ByteString
    bs') = ByteString -> (Text, Tree Text, ByteString)
    getPair ByteString
    bs
                 in Map Text (Tree Text) -> ByteString -> (Tree Text, ByteString)
    loop (Text -> Tree Text -> Map Text (Tree Text) -> Map Text (Tree Text)
    forall k a. Ord k => k -> a -> Map k a -> Map k a
    Map.insert Text
    k Tree Text
    v Map Text (Tree Text)
    m) ByteString
    bs'

    getPair :: BS.ByteString -> (T.Text, Tree T.Text, BS.ByteString)
    getPair :: ByteString -> (Text, Tree Text, ByteString)
    getPair ByteString
    bs0 =
        (Text
    k, Tree Text
    v, ByteString
    bs2)
      where
        (Text
    k, ByteString
    bs1) = ByteString -> (Text, ByteString)
    getText ByteString
    bs0
        (Tree Text
    v, ByteString
    bs2) = ByteString -> (Tree Text, ByteString)
    getTree ByteString
    bs1

    getText :: BS.ByteString -> (T.Text, BS.ByteString)
    getText :: ByteString -> (Text, ByteString)
    getText ByteString
    bs0 =
        (ByteString -> Text
    TE.decodeUtf8 ByteString
    v, Int -> ByteString -> ByteString
    BS.drop Int
    1 ByteString
    bs1)
      where
        (ByteString
    v, ByteString
    bs1) = (Word8 -> Bool) -> ByteString -> (ByteString, ByteString)
    BS.break (Word8 -> Word8 -> Bool
    forall a. Eq a => a -> a -> Bool
    == Word8
    0) ByteString
    bs0

    getDataStructure :: BS.ByteString -> DataStructure
    getDataStructure :: ByteString -> DataStructure
    getDataStructure ByteString
    bs0 =
        (Tree Text
    x, Tree Text
    y)
      where
        (Tree Text
    x, ByteString
    bs1) = ByteString -> (Tree Text, ByteString)
    getTree ByteString
    bs0
        (Tree Text
    y, ByteString
    _) = ByteString -> (Tree Text, ByteString)
    getTree ByteString
    bs1

    putTree :: Tree T.Text -> Builder
    putTree :: Tree Text -> Builder
    putTree = Map Text (Tree Text) -> Builder
    putMap (Map Text (Tree Text) -> Builder)
    -> (Tree Text -> Map Text (Tree Text)) -> Tree Text -> Builder
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . Tree Text -> Map Text (Tree Text)
    forall e. Tree e -> Map e (Tree e)
    children

    putMap :: Map T.Text (Tree T.Text) -> Builder
    putMap :: Map Text (Tree Text) -> Builder
    putMap Map Text (Tree Text)
    m = ((Text, Tree Text) -> Builder) -> [(Text, Tree Text)] -> Builder
    forall m a. Monoid m => (a -> m) -> [a] -> m
    forall (t :: * -> *) m a.
    (Foldable t, Monoid m) =>
    (a -> m) -> t a -> m
    Data.Foldable.foldMap (Text, Tree Text) -> Builder
    putPair (Map Text (Tree Text) -> [(Text, Tree Text)]
    forall k a. Map k a -> [(k, a)]
    Map.toList Map Text (Tree Text)
    m) Builder -> Builder -> Builder
    forall a. Monoid a => a -> a -> a
    `mappend` Word8 -> Builder
    fromWord8 Word8
    0

    putPair :: (T.Text, Tree T.Text) -> Builder
    putPair :: (Text, Tree Text) -> Builder
    putPair (Text
    x, Tree Text
    y) = Text -> Builder
    putText Text
    x Builder -> Builder -> Builder
    forall a. Monoid a => a -> a -> a
    `mappend` Tree Text -> Builder
    putTree Tree Text
    y

    putText :: T.Text -> Builder
    putText :: Text -> Builder
    putText Text
    t = Text -> Builder
    fromText Text
    t Builder -> Builder -> Builder
    forall a. Monoid a => a -> a -> a
    `Data.Monoid.mappend` Word8 -> Builder
    fromWord8 Word8
    0

    putDataStructure :: DataStructure -> BS.ByteString
    putDataStructure :: DataStructure -> ByteString
    putDataStructure (Tree Text
    x, Tree Text
    y) = Builder -> ByteString
    toByteString (Builder -> ByteString) -> Builder -> ByteString
    forall a b. (a -> b) -> a -> b
    $ Tree Text -> Builder
    putTree Tree Text
    x Builder -> Builder -> Builder
    forall a. Monoid a => a -> a -> a
    `mappend` Tree Text -> Builder
    putTree Tree Text
    y