    {-# LANGUAGE CPP #-}
    {-# LANGUAGE RecordWildCards #-}
    {-# LANGUAGE GeneralizedNewtypeDeriving #-}
    module Hpack.Render.Dsl (
    -- * AST
      Element (..)
    , Value (..)

    -- * Render
    , RenderSettings (..)
    , CommaStyle (..)
    , defaultRenderSettings
    , Alignment (..)
    , Nesting
    , render

    -- * Utils
    , sortFieldsBy

    #ifdef TEST
    , Lines (..)
    , renderValue
    , addSortKey
    #endif
    ) where

    import           Data.String
    import           Data.List

    data Value =
        Literal String
      | CommaSeparatedList [String]
      | LineSeparatedList [String]
      | WordList [String]
      deriving (Value -> Value -> Bool
    (Value -> Value -> Bool) -> (Value -> Value -> Bool) -> Eq Value
    forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
    /= :: Value -> Value -> Bool
    $c/= :: Value -> Value -> Bool
    == :: Value -> Value -> Bool
    $c== :: Value -> Value -> Bool
    Eq, Int -> Value -> ShowS
    [Value] -> ShowS
    Value -> String
    (Int -> Value -> ShowS)
    -> (Value -> String) -> ([Value] -> ShowS) -> Show Value
    forall a.
    (Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
    showList :: [Value] -> ShowS
    $cshowList :: [Value] -> ShowS
    show :: Value -> String
    $cshow :: Value -> String
    showsPrec :: Int -> Value -> ShowS
    $cshowsPrec :: Int -> Value -> ShowS
    Show)

    data Element = Stanza String [Element] | Group Element Element | Field String Value | Verbatim String
      deriving (Element -> Element -> Bool
    (Element -> Element -> Bool)
    -> (Element -> Element -> Bool) -> Eq Element
    forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
    /= :: Element -> Element -> Bool
    $c/= :: Element -> Element -> Bool
    == :: Element -> Element -> Bool
    $c== :: Element -> Element -> Bool
    Eq, Int -> Element -> ShowS
    [Element] -> ShowS
    Element -> String
    (Int -> Element -> ShowS)
    -> (Element -> String) -> ([Element] -> ShowS) -> Show Element
    forall a.
    (Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
    showList :: [Element] -> ShowS
    $cshowList :: [Element] -> ShowS
    show :: Element -> String
    $cshow :: Element -> String
    showsPrec :: Int -> Element -> ShowS
    $cshowsPrec :: Int -> Element -> ShowS
    Show)

    data Lines = SingleLine String | MultipleLines [String]
      deriving (Lines -> Lines -> Bool
    (Lines -> Lines -> Bool) -> (Lines -> Lines -> Bool) -> Eq Lines
    forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
    /= :: Lines -> Lines -> Bool
    $c/= :: Lines -> Lines -> Bool
    == :: Lines -> Lines -> Bool
    $c== :: Lines -> Lines -> Bool
    Eq, Int -> Lines -> ShowS
    [Lines] -> ShowS
    Lines -> String
    (Int -> Lines -> ShowS)
    -> (Lines -> String) -> ([Lines] -> ShowS) -> Show Lines
    forall a.
    (Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
    showList :: [Lines] -> ShowS
    $cshowList :: [Lines] -> ShowS
    show :: Lines -> String
    $cshow :: Lines -> String
    showsPrec :: Int -> Lines -> ShowS
    $cshowsPrec :: Int -> Lines -> ShowS
    Show)

    data CommaStyle = LeadingCommas | TrailingCommas
      deriving (CommaStyle -> CommaStyle -> Bool
    (CommaStyle -> CommaStyle -> Bool)
    -> (CommaStyle -> CommaStyle -> Bool) -> Eq CommaStyle
    forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
    /= :: CommaStyle -> CommaStyle -> Bool
    $c/= :: CommaStyle -> CommaStyle -> Bool
    == :: CommaStyle -> CommaStyle -> Bool
    $c== :: CommaStyle -> CommaStyle -> Bool
    Eq, Int -> CommaStyle -> ShowS
    [CommaStyle] -> ShowS
    CommaStyle -> String
    (Int -> CommaStyle -> ShowS)
    -> (CommaStyle -> String)
    -> ([CommaStyle] -> ShowS)
    -> Show CommaStyle
    forall a.
    (Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
    showList :: [CommaStyle] -> ShowS
    $cshowList :: [CommaStyle] -> ShowS
    show :: CommaStyle -> String
    $cshow :: CommaStyle -> String
    showsPrec :: Int -> CommaStyle -> ShowS
    $cshowsPrec :: Int -> CommaStyle -> ShowS
    Show)

    newtype Nesting = Nesting Int
      deriving (Nesting -> Nesting -> Bool
    (Nesting -> Nesting -> Bool)
    -> (Nesting -> Nesting -> Bool) -> Eq Nesting
    forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
    /= :: Nesting -> Nesting -> Bool
    $c/= :: Nesting -> Nesting -> Bool
    == :: Nesting -> Nesting -> Bool
    $c== :: Nesting -> Nesting -> Bool
    Eq, Int -> Nesting -> ShowS
    [Nesting] -> ShowS
    Nesting -> String
    (Int -> Nesting -> ShowS)
    -> (Nesting -> String) -> ([Nesting] -> ShowS) -> Show Nesting
    forall a.
    (Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
    showList :: [Nesting] -> ShowS
    $cshowList :: [Nesting] -> ShowS
    show :: Nesting -> String
    $cshow :: Nesting -> String
    showsPrec :: Int -> Nesting -> ShowS
    $cshowsPrec :: Int -> Nesting -> ShowS
    Show, Integer -> Nesting
    Nesting -> Nesting
    Nesting -> Nesting -> Nesting
    (Nesting -> Nesting -> Nesting)
    -> (Nesting -> Nesting -> Nesting)
    -> (Nesting -> Nesting -> Nesting)
    -> (Nesting -> Nesting)
    -> (Nesting -> Nesting)
    -> (Nesting -> Nesting)
    -> (Integer -> Nesting)
    -> Num Nesting
    forall a.
    (a -> a -> a)
    -> (a -> a -> a)
    -> (a -> a -> a)
    -> (a -> a)
    -> (a -> a)
    -> (a -> a)
    -> (Integer -> a)
    -> Num a
    fromInteger :: Integer -> Nesting
    $cfromInteger :: Integer -> Nesting
    signum :: Nesting -> Nesting
    $csignum :: Nesting -> Nesting
    abs :: Nesting -> Nesting
    $cabs :: Nesting -> Nesting
    negate :: Nesting -> Nesting
    $cnegate :: Nesting -> Nesting
    * :: Nesting -> Nesting -> Nesting
    $c* :: Nesting -> Nesting -> Nesting
    - :: Nesting -> Nesting -> Nesting
    $c- :: Nesting -> Nesting -> Nesting
    + :: Nesting -> Nesting -> Nesting
    $c+ :: Nesting -> Nesting -> Nesting
    Num, Int -> Nesting
    Nesting -> Int
    Nesting -> [Nesting]
    Nesting -> Nesting
    Nesting -> Nesting -> [Nesting]
    Nesting -> Nesting -> Nesting -> [Nesting]
    (Nesting -> Nesting)
    -> (Nesting -> Nesting)
    -> (Int -> Nesting)
    -> (Nesting -> Int)
    -> (Nesting -> [Nesting])
    -> (Nesting -> Nesting -> [Nesting])
    -> (Nesting -> Nesting -> [Nesting])
    -> (Nesting -> Nesting -> Nesting -> [Nesting])
    -> Enum Nesting
    forall a.
    (a -> a)
    -> (a -> a)
    -> (Int -> a)
    -> (a -> Int)
    -> (a -> [a])
    -> (a -> a -> [a])
    -> (a -> a -> [a])
    -> (a -> a -> a -> [a])
    -> Enum a
    enumFromThenTo :: Nesting -> Nesting -> Nesting -> [Nesting]
    $cenumFromThenTo :: Nesting -> Nesting -> Nesting -> [Nesting]
    enumFromTo :: Nesting -> Nesting -> [Nesting]
    $cenumFromTo :: Nesting -> Nesting -> [Nesting]
    enumFromThen :: Nesting -> Nesting -> [Nesting]
    $cenumFromThen :: Nesting -> Nesting -> [Nesting]
    enumFrom :: Nesting -> [Nesting]
    $cenumFrom :: Nesting -> [Nesting]
    fromEnum :: Nesting -> Int
    $cfromEnum :: Nesting -> Int
    toEnum :: Int -> Nesting
    $ctoEnum :: Int -> Nesting
    pred :: Nesting -> Nesting
    $cpred :: Nesting -> Nesting
    succ :: Nesting -> Nesting
    $csucc :: Nesting -> Nesting
    Enum)

    newtype Alignment = Alignment Int
      deriving (Alignment -> Alignment -> Bool
    (Alignment -> Alignment -> Bool)
    -> (Alignment -> Alignment -> Bool) -> Eq Alignment
    forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
    /= :: Alignment -> Alignment -> Bool
    $c/= :: Alignment -> Alignment -> Bool
    == :: Alignment -> Alignment -> Bool
    $c== :: Alignment -> Alignment -> Bool
    Eq, Int -> Alignment -> ShowS
    [Alignment] -> ShowS
    Alignment -> String
    (Int -> Alignment -> ShowS)
    -> (Alignment -> String)
    -> ([Alignment] -> ShowS)
    -> Show Alignment
    forall a.
    (Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
    showList :: [Alignment] -> ShowS
    $cshowList :: [Alignment] -> ShowS
    show :: Alignment -> String
    $cshow :: Alignment -> String
    showsPrec :: Int -> Alignment -> ShowS
    $cshowsPrec :: Int -> Alignment -> ShowS
    Show, Integer -> Alignment
    Alignment -> Alignment
    Alignment -> Alignment -> Alignment
    (Alignment -> Alignment -> Alignment)
    -> (Alignment -> Alignment -> Alignment)
    -> (Alignment -> Alignment -> Alignment)
    -> (Alignment -> Alignment)
    -> (Alignment -> Alignment)
    -> (Alignment -> Alignment)
    -> (Integer -> Alignment)
    -> Num Alignment
    forall a.
    (a -> a -> a)
    -> (a -> a -> a)
    -> (a -> a -> a)
    -> (a -> a)
    -> (a -> a)
    -> (a -> a)
    -> (Integer -> a)
    -> Num a
    fromInteger :: Integer -> Alignment
    $cfromInteger :: Integer -> Alignment
    signum :: Alignment -> Alignment
    $csignum :: Alignment -> Alignment
    abs :: Alignment -> Alignment
    $cabs :: Alignment -> Alignment
    negate :: Alignment -> Alignment
    $cnegate :: Alignment -> Alignment
    * :: Alignment -> Alignment -> Alignment
    $c* :: Alignment -> Alignment -> Alignment
    - :: Alignment -> Alignment -> Alignment
    $c- :: Alignment -> Alignment -> Alignment
    + :: Alignment -> Alignment -> Alignment
    $c+ :: Alignment -> Alignment -> Alignment
    Num)

    data RenderSettings = RenderSettings {
      RenderSettings -> Int
    renderSettingsIndentation :: Int
    , RenderSettings -> Alignment
    renderSettingsFieldAlignment :: Alignment
    , RenderSettings -> CommaStyle
    renderSettingsCommaStyle :: CommaStyle
    } deriving (RenderSettings -> RenderSettings -> Bool
    (RenderSettings -> RenderSettings -> Bool)
    -> (RenderSettings -> RenderSettings -> Bool) -> Eq RenderSettings
    forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
    /= :: RenderSettings -> RenderSettings -> Bool
    $c/= :: RenderSettings -> RenderSettings -> Bool
    == :: RenderSettings -> RenderSettings -> Bool
    $c== :: RenderSettings -> RenderSettings -> Bool
    Eq, Int -> RenderSettings -> ShowS
    [RenderSettings] -> ShowS
    RenderSettings -> String
    (Int -> RenderSettings -> ShowS)
    -> (RenderSettings -> String)
    -> ([RenderSettings] -> ShowS)
    -> Show RenderSettings
    forall a.
    (Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
    showList :: [RenderSettings] -> ShowS
    $cshowList :: [RenderSettings] -> ShowS
    show :: RenderSettings -> String
    $cshow :: RenderSettings -> String
    showsPrec :: Int -> RenderSettings -> ShowS
    $cshowsPrec :: Int -> RenderSettings -> ShowS
    Show)

    defaultRenderSettings :: RenderSettings
    defaultRenderSettings :: RenderSettings
    defaultRenderSettings = Int -> Alignment -> CommaStyle -> RenderSettings
    RenderSettings 2 0 CommaStyle
    LeadingCommas

    render :: RenderSettings -> Nesting -> Element -> [String]
    render :: RenderSettings -> Nesting -> Element -> [String]
    render settings :: RenderSettings
    settings nesting :: Nesting
    nesting (Stanza name :: String
    name elements :: [Element]
    elements) = RenderSettings -> Nesting -> ShowS
    indent RenderSettings
    settings Nesting
    nesting String
    name String -> [String] -> [String]
    forall a. a -> [a] -> [a]
    : RenderSettings -> Nesting -> [Element] -> [String]
    renderElements RenderSettings
    settings (Nesting -> Nesting
    forall a. Enum a => a -> a
    succ Nesting
    nesting) [Element]
    elements
    render settings :: RenderSettings
    settings nesting :: Nesting
    nesting (Group a :: Element
    a b :: Element
    b) = RenderSettings -> Nesting -> Element -> [String]
    render RenderSettings
    settings Nesting
    nesting Element
    a [String] -> [String] -> [String]
    forall a. [a] -> [a] -> [a]
    ++ RenderSettings -> Nesting -> Element -> [String]
    render RenderSettings
    settings Nesting
    nesting Element
    b
    render settings :: RenderSettings
    settings nesting :: Nesting
    nesting (Field name :: String
    name value :: Value
    value) = RenderSettings -> Nesting -> String -> Value -> [String]
    renderField RenderSettings
    settings Nesting
    nesting String
    name Value
    value
    render settings :: RenderSettings
    settings nesting :: Nesting
    nesting (Verbatim str :: String
    str) = ShowS -> [String] -> [String]
    forall a b. (a -> b) -> [a] -> [b]
    map (RenderSettings -> Nesting -> ShowS
    indent RenderSettings
    settings Nesting
    nesting) (String -> [String]
    lines String
    str)

    renderElements :: RenderSettings -> Nesting -> [Element] -> [String]
    renderElements :: RenderSettings -> Nesting -> [Element] -> [String]
    renderElements settings :: RenderSettings
    settings nesting :: Nesting
    nesting = (Element -> [String]) -> [Element] -> [String]
    forall (t :: * -> *) a b. Foldable t => (a -> [b]) -> t a -> [b]
    concatMap (RenderSettings -> Nesting -> Element -> [String]
    render RenderSettings
    settings Nesting
    nesting)

    renderField :: RenderSettings -> Nesting -> String -> Value -> [String]
    renderField :: RenderSettings -> Nesting -> String -> Value -> [String]
    renderField settings :: RenderSettings
    settings@RenderSettings{..} nesting :: Nesting
    nesting name :: String
    name value :: Value
    value = case RenderSettings -> Value -> Lines
    renderValue RenderSettings
    settings Value
    value of
      SingleLine "" -> []
      SingleLine x :: String
    x -> [RenderSettings -> Nesting -> ShowS
    indent RenderSettings
    settings Nesting
    nesting (String
    name String -> ShowS
    forall a. [a] -> [a] -> [a]
    ++ ": " String -> ShowS
    forall a. [a] -> [a] -> [a]
    ++ String
    padding String -> ShowS
    forall a. [a] -> [a] -> [a]
    ++ String
    x)]
      MultipleLines [] -> []
      MultipleLines xs :: [String]
    xs -> (RenderSettings -> Nesting -> ShowS
    indent RenderSettings
    settings Nesting
    nesting String
    name String -> ShowS
    forall a. [a] -> [a] -> [a]
    ++ ":") String -> [String] -> [String]
    forall a. a -> [a] -> [a]
    : ShowS -> [String] -> [String]
    forall a b. (a -> b) -> [a] -> [b]
    map (RenderSettings -> Nesting -> ShowS
    indent RenderSettings
    settings (Nesting -> ShowS) -> Nesting -> ShowS
    forall a b. (a -> b) -> a -> b
    $ Nesting -> Nesting
    forall a. Enum a => a -> a
    succ Nesting
    nesting) [String]
    xs
      where
        Alignment fieldAlignment :: Int
    fieldAlignment = Alignment
    renderSettingsFieldAlignment
        padding :: String
    padding = Int -> Char -> String
    forall a. Int -> a -> [a]
    replicate (Int
    fieldAlignment Int -> Int -> Int
    forall a. Num a => a -> a -> a
    - String -> Int
    forall (t :: * -> *) a. Foldable t => t a -> Int
    length String
    name Int -> Int -> Int
    forall a. Num a => a -> a -> a
    - 2) ' '

    renderValue :: RenderSettings -> Value -> Lines
    renderValue :: RenderSettings -> Value -> Lines
    renderValue RenderSettings{..} v :: Value
    v = case Value
    v of
      Literal s :: String
    s -> String -> Lines
    SingleLine String
    s
      WordList ws :: [String]
    ws -> String -> Lines
    SingleLine (String -> Lines) -> String -> Lines
    forall a b. (a -> b) -> a -> b
    $ [String] -> String
    unwords [String]
    ws
      LineSeparatedList xs :: [String]
    xs -> CommaStyle -> [String] -> Lines
    renderLineSeparatedList CommaStyle
    renderSettingsCommaStyle [String]
    xs
      CommaSeparatedList xs :: [String]
    xs -> CommaStyle -> [String] -> Lines
    renderCommaSeparatedList CommaStyle
    renderSettingsCommaStyle [String]
    xs

    renderLineSeparatedList :: CommaStyle -> [String] -> Lines
    renderLineSeparatedList :: CommaStyle -> [String] -> Lines
    renderLineSeparatedList style :: CommaStyle
    style = [String] -> Lines
    MultipleLines ([String] -> Lines) -> ([String] -> [String]) -> [String] -> Lines
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . ShowS -> [String] -> [String]
    forall a b. (a -> b) -> [a] -> [b]
    map (String
    padding String -> ShowS
    forall a. [a] -> [a] -> [a]
    ++)
      where
        padding :: String
    padding = case CommaStyle
    style of
          LeadingCommas -> "  "
          TrailingCommas -> ""

    renderCommaSeparatedList :: CommaStyle -> [String] -> Lines
    renderCommaSeparatedList :: CommaStyle -> [String] -> Lines
    renderCommaSeparatedList style :: CommaStyle
    style = [String] -> Lines
    MultipleLines ([String] -> Lines) -> ([String] -> [String]) -> [String] -> Lines
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . case CommaStyle
    style of
      LeadingCommas -> ((Bool, String) -> String) -> [(Bool, String)] -> [String]
    forall a b. (a -> b) -> [a] -> [b]
    map (Bool, String) -> String
    renderLeadingComma ([(Bool, String)] -> [String])
    -> ([String] -> [(Bool, String)]) -> [String] -> [String]
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . [Bool] -> [String] -> [(Bool, String)]
    forall a b. [a] -> [b] -> [(a, b)]
    zip (Bool
    True Bool -> [Bool] -> [Bool]
    forall a. a -> [a] -> [a]
    : Bool -> [Bool]
    forall a. a -> [a]
    repeat Bool
    False)
      TrailingCommas -> ((Bool, String) -> String) -> [(Bool, String)] -> [String]
    forall a b. (a -> b) -> [a] -> [b]
    map (Bool, String) -> String
    renderTrailingComma ([(Bool, String)] -> [String])
    -> ([String] -> [(Bool, String)]) -> [String] -> [String]
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . [(Bool, String)] -> [(Bool, String)]
    forall a. [a] -> [a]
    reverse ([(Bool, String)] -> [(Bool, String)])
    -> ([String] -> [(Bool, String)]) -> [String] -> [(Bool, String)]
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . [Bool] -> [String] -> [(Bool, String)]
    forall a b. [a] -> [b] -> [(a, b)]
    zip (Bool
    True Bool -> [Bool] -> [Bool]
    forall a. a -> [a] -> [a]
    : Bool -> [Bool]
    forall a. a -> [a]
    repeat Bool
    False) ([String] -> [(Bool, String)])
    -> ([String] -> [String]) -> [String] -> [(Bool, String)]
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . [String] -> [String]
    forall a. [a] -> [a]
    reverse
      where
        renderLeadingComma :: (Bool, String) -> String
        renderLeadingComma :: (Bool, String) -> String
    renderLeadingComma (isFirst :: Bool
    isFirst, x :: String
    x)
          | Bool
    isFirst   = "  " String -> ShowS
    forall a. [a] -> [a] -> [a]
    ++ String
    x
          | Bool
    otherwise = ", " String -> ShowS
    forall a. [a] -> [a] -> [a]
    ++ String
    x

        renderTrailingComma :: (Bool, String) -> String
        renderTrailingComma :: (Bool, String) -> String
    renderTrailingComma (isLast :: Bool
    isLast, x :: String
    x)
          | Bool
    isLast    = String
    x
          | Bool
    otherwise = String
    x String -> ShowS
    forall a. [a] -> [a] -> [a]
    ++ ","

    instance IsString Value where
      fromString :: String -> Value
    fromString = String -> Value
    Literal

    indent :: RenderSettings -> Nesting -> String -> String
    indent :: RenderSettings -> Nesting -> ShowS
    indent RenderSettings{..} (Nesting nesting :: Int
    nesting) s :: String
    s = Int -> Char -> String
    forall a. Int -> a -> [a]
    replicate (Int
    nesting Int -> Int -> Int
    forall a. Num a => a -> a -> a
    * Int
    renderSettingsIndentation) ' ' String -> ShowS
    forall a. [a] -> [a] -> [a]
    ++ String
    s

    sortFieldsBy :: [String] -> [Element] -> [Element]
    sortFieldsBy :: [String] -> [Element] -> [Element]
    sortFieldsBy existingFieldOrder :: [String]
    existingFieldOrder =
        (((Int, Int), Element) -> Element)
    -> [((Int, Int), Element)] -> [Element]
    forall a b. (a -> b) -> [a] -> [b]
    map ((Int, Int), Element) -> Element
    forall a b. (a, b) -> b
    snd
      ([((Int, Int), Element)] -> [Element])
    -> ([Element] -> [((Int, Int), Element)]) -> [Element] -> [Element]
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . (((Int, Int), Element) -> (Int, Int))
    -> [((Int, Int), Element)] -> [((Int, Int), Element)]
    forall b a. Ord b => (a -> b) -> [a] -> [a]
    sortOn ((Int, Int), Element) -> (Int, Int)
    forall a b. (a, b) -> a
    fst
      ([((Int, Int), Element)] -> [((Int, Int), Element)])
    -> ([Element] -> [((Int, Int), Element)])
    -> [Element]
    -> [((Int, Int), Element)]
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . [(Maybe Int, Element)] -> [((Int, Int), Element)]
    forall a. [(Maybe Int, a)] -> [((Int, Int), a)]
    addSortKey
      ([(Maybe Int, Element)] -> [((Int, Int), Element)])
    -> ([Element] -> [(Maybe Int, Element)])
    -> [Element]
    -> [((Int, Int), Element)]
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . (Element -> (Maybe Int, Element))
    -> [Element] -> [(Maybe Int, Element)]
    forall a b. (a -> b) -> [a] -> [b]
    map (\a :: Element
    a -> (Element -> Maybe Int
    existingIndex Element
    a, Element
    a))
      where
        existingIndex :: Element -> Maybe Int
        existingIndex :: Element -> Maybe Int
    existingIndex (Field name :: String
    name _) = String
    name String -> [String] -> Maybe Int
    forall a. Eq a => a -> [a] -> Maybe Int
    `elemIndex` [String]
    existingFieldOrder
        existingIndex _ = Maybe Int
    forall a. Maybe a
    Nothing

    addSortKey :: [(Maybe Int, a)] -> [((Int, Int), a)]
    addSortKey :: [(Maybe Int, a)] -> [((Int, Int), a)]
    addSortKey = Int -> [(Int, (Maybe Int, a))] -> [((Int, Int), a)]
    forall a. Int -> [(Int, (Maybe Int, a))] -> [((Int, Int), a)]
    go (-1) ([(Int, (Maybe Int, a))] -> [((Int, Int), a)])
    -> ([(Maybe Int, a)] -> [(Int, (Maybe Int, a))])
    -> [(Maybe Int, a)]
    -> [((Int, Int), a)]
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . [Int] -> [(Maybe Int, a)] -> [(Int, (Maybe Int, a))]
    forall a b. [a] -> [b] -> [(a, b)]
    zip [0..]
      where
        go :: Int -> [(Int, (Maybe Int, a))] -> [((Int, Int), a)]
        go :: Int -> [(Int, (Maybe Int, a))] -> [((Int, Int), a)]
    go n :: Int
    n xs :: [(Int, (Maybe Int, a))]
    xs = case [(Int, (Maybe Int, a))]
    xs of
          [] -> []
          (x :: Int
    x, (Just y :: Int
    y, a :: a
    a)) : ys :: [(Int, (Maybe Int, a))]
    ys -> ((Int
    y, Int
    x), a
    a) ((Int, Int), a) -> [((Int, Int), a)] -> [((Int, Int), a)]
    forall a. a -> [a] -> [a]
    : Int -> [(Int, (Maybe Int, a))] -> [((Int, Int), a)]
    forall a. Int -> [(Int, (Maybe Int, a))] -> [((Int, Int), a)]
    go Int
    y [(Int, (Maybe Int, a))]
    ys
          (x :: Int
    x, (Nothing, a :: a
    a)) : ys :: [(Int, (Maybe Int, a))]
    ys -> ((Int
    n, Int
    x), a
    a) ((Int, Int), a) -> [((Int, Int), a)] -> [((Int, Int), a)]
    forall a. a -> [a] -> [a]
    : Int -> [(Int, (Maybe Int, a))] -> [((Int, Int), a)]
    forall a. Int -> [(Int, (Maybe Int, a))] -> [((Int, Int), a)]
    go Int
    n [(Int, (Maybe Int, a))]
    ys