packages feed

streamly-0.11.0: docs/diagrams/module-diagram.hs

{-# LANGUAGE NoMonomorphismRestriction #-}
{-# LANGUAGE FlexibleContexts          #-}
{-# LANGUAGE TypeFamilies              #-}

import Diagrams.Prelude
import Diagrams.Backend.SVG.CmdLine
import Data.List (isPrefixOf)

splitOn :: Eq a => [a] -> [a] -> [[a]]
splitOn delim str = go str
  where
    go [] = [[]]
    go s
      | delim `isPrefixOf` s = [] : go (drop (length delim) s)
      | otherwise =
          let (c:cs) = s
              (x:xs) = go cs
          in (c:x) : xs

-------------------------------------------------------------------------------
-- Utilities
-------------------------------------------------------------------------------

title1 t =
  vsep 0.3 [ text line # fontSizeL 0.3 # bold | line <- splitOn "\n" t ]
title2 t = text t # fontSizeL 0.2 # bold

textBox x y t = t <> strutX x <> strutY y

item1 t = text t # fontSizeL 0.25
enumerate items = vsep 0.3 [ textBox 2.0 0.4 (item1 i) | i <- items ]

boxedXY :: Double -> Double -> Diagram B -> Diagram B
boxedXY w h content = content # centerXY  <> rect w h # lw thin

boxedEnum x y items =
    let list = enumerate items
    in boxedXY x y (list # centerXY)

titleW = 2.0
titleH = 0.5

boxedTitledEnum1 x y title items =
    let ttext = textBox titleW titleH (title1 title)
        list = enumerate items
    in boxedXY x y (vsep 0 [ttext, boxedXY x (y - titleH) (list # centerXY)])

connect1 = connectOutside' (with & arrowHead .~ tri & headLength .~ global 0.2)

coreOval :: String -> Diagram B
coreOval tag =
    textBox 2.0 0.5 (title1 tag # centerXY)
    <> ellipseXY 1.5 0.75 # fc lightblue # lw medium

-------------------------------------------------------------------------------
-- streamly-core diagram
-------------------------------------------------------------------------------

bigBoxW = 12
bigBoxH = 4
centerBoxW = bigBoxH
centerBoxH = bigBoxH

box1 = boxedXY bigBoxW bigBoxH
box2 = boxedXY centerBoxW centerBoxH

bigBoxSubContent = boxedTitledEnum1 (bigBoxW / 3) (bigBoxH - titleH)

streamsBox :: Diagram B
streamsBox =
    let prod    = bigBoxSubContent "Generation" ["Stream", "StreamK", "Unfold"]
        transf  = bigBoxSubContent "Transformation" ["Scanl"]
        cons    = bigBoxSubContent "Consumption" ["Fold", "Parser", "ParserK"]
        row     = hsep 0 [prod, transf, cons]
        title   = textBox titleW titleH (title1 "Streams")
        content = vsep 0 [title, row # centerXY]
    in box1 (content # centerXY)

arraysBox :: Diagram B
arraysBox =
    let immut  = bigBoxSubContent "Immutable" ["Array", "Array.Generic"]
        mut    = bigBoxSubContent "Mutable" ["MutArray", "MutArray.Generic", "RingArray"]
        ser    = bigBoxSubContent "Serialization" ["MutByteArray", "Unbox", "Serialize"]
        row    = hsep 0 [immut, mut, ser]
        title  = textBox titleW titleH (title1 "Arrays")
        content= vsep 0 [title, row # centerXY]
    in box1 (content # centerXY)

fileSystemBox :: Diagram B
fileSystemBox =
    let items = ["Console.Stdio", "FileIO", "DirIO", "Handle", "Path"]
        content = boxedTitledEnum1 centerBoxW centerBoxH "File System" items
    in box2 (content # centerXY)

otherModulesBox :: Diagram B
otherModulesBox =
    let unicode = boxedTitledEnum1 centerBoxW (centerBoxH * 2/3) "Unicode" ["Parser", "Stream", "String"]
        resmgmt = boxedTitledEnum1 centerBoxW (centerBoxH * 1/3) "Resource Management" ["Control.Exception"]
        content = vsep 0 [unicode, resmgmt]
    in box2 (content # centerXY)

streamlyCore :: Diagram B
streamlyCore =
    let center    = coreOval "streamly-core\n(types and modules)" # named "core"
        topBox    = streamsBox # named "streams"
        bottomBox = arraysBox # named "arrays"
        leftBox   = fileSystemBox # named "fs"
        rightBox  = otherModulesBox # named "others"

        placed = position
          [ (p2 (0,0), center)
          , (p2 (0,4), topBox)
          , (p2 (0,-4), bottomBox)
          , (p2 (-4,0), leftBox)
          , (p2 (4,0), rightBox)
          ]

        arrows = applyAll
          [ connect1 "core" "streams"
          , connect1 "core" "arrays"
          , connect1 "core" "fs"
          , connect1 "core" "others"
          ]
    in arrows placed

-------------------------------------------------------------------------------
-- streamly diagram
-------------------------------------------------------------------------------

concurrentStreamsBox :: Diagram B
concurrentStreamsBox =
    let prod    = bigBoxSubContent "Generation" ["Stream.Prelude"]
        transf  = bigBoxSubContent "Transformation" ["Scanl.Prelude"]
        cons    = bigBoxSubContent "Consumption" ["Fold.Prelude"]
        row     = hsep 0 [prod, transf, cons]
        title   = textBox titleW titleH (title1 "Concurrent Streams")
        content = vsep 0 [title, row # centerXY]
    in box1 (content # centerXY)

networkBox :: Diagram B
networkBox =
    let items = ["Network.Socket", "Network.Inet.TCP"]
        content = boxedTitledEnum1 centerBoxW centerBoxH "Network" items
    in box2 (content # centerXY)

streamly :: Diagram B
streamly =
    let center    = coreOval "streamly" # named "streamly"
        topBox    = concurrentStreamsBox # named "concurrent-streams"
        bottomBox = networkBox # named "network"

        placed = position
          [ (p2 (0,0), center)
          , (p2 (0,4), topBox)
          , (p2 (0,-4), bottomBox)
          ]

        arrows = applyAll
          [ connect1 "streamly" "concurrent-streams"
          , connect1 "streamly" "network"
          ]
    in arrows placed

main :: IO ()
main =
    mainWith
        [ ("streamly-core", (streamlyCore # centerXY # pad 1.1))
        , ("streamly", (streamly # centerXY # pad 1.1))
        ]