Skip to content

Instantly share code, notes, and snippets.

@ccapndave
Created July 30, 2018 15:23
Show Gist options
  • Save ccapndave/7b2742da5b06ef55a984a7aa1a434d9c to your computer and use it in GitHub Desktop.
Save ccapndave/7b2742da5b06ef55a984a7aa1a434d9c to your computer and use it in GitHub Desktop.
module TreePath.Tree4
exposing
( DecoderConfig
, Tree
, TreePath1
, TreePath2
, TreePath3
, TreePath4
, data1
, data2
, data3
, data4
, decoder
, down1
, down2
, down3
, down4
, downs1
, downs2
, downs3
, downs4
, offset1
, offset2
, offset3
, offset4
, pathDecoder
, pathEncode1
, pathEncode2
, pathEncode3
, pathEncode4
, toRootPath
, top1
, top2
, top3
, top4
, up1
, up2
, up3
, up4
)
import Array exposing (Array)
import Json.Decode as JD exposing (Decoder)
import Json.Encode as JE exposing (Value)
import TreePath.Data as Data exposing (Data)
type alias Tree a b c leaf =
Tree4 a b c leaf
type Tree1 leaf
= Tree1
{ data : leaf
}
type Tree2 a leaf
= Tree2
{ data : Data a leaf
, children : Array (Tree1 leaf)
}
type Tree3 a b leaf
= Tree3
{ data : Data a leaf
, children : Array (Tree2 b leaf)
}
type Tree4 a b c leaf
= Tree4
{ data : Data a leaf
, children : Array (Tree3 b c leaf)
}
type TreePath1 a b c leaf
= TreePath1
{ tree : Tree4 a b c leaf
, path : Array Int
}
type TreePath2 a b c leaf
= TreePath2
{ tree : Tree4 a b c leaf
, path : Array Int
}
type TreePath3 a b c leaf
= TreePath3
{ tree : Tree4 a b c leaf
, path : Array Int
}
type TreePath4 a b c leaf
= TreePath4
{ tree : Tree4 a b c leaf
, path : Array Int
}
type alias DecoderConfig a b c leaf path =
{ level4 :
{ decoder : Decoder a
, encoders : a -> List ( String, Value )
, pathType : TreePath4 a b c leaf -> path
, childrenField : String
}
, level3 :
{ decoder : Decoder b
, encoders : b -> List ( String, Value )
, pathType : TreePath3 a b c leaf -> path
, childrenField : String
}
, level2 :
{ decoder : Decoder c
, encoders : c -> List ( String, Value )
, pathType : TreePath2 a b c leaf -> path
, childrenField : String
}
, leaf :
{ decoder : Decoder leaf
, encode : leaf -> Value
, pathType : TreePath1 a b c leaf -> path
}
}
decoder : DecoderConfig a b c leaf path -> Decoder (Tree4 a b c leaf)
decoder config =
decoder4
( config.level4.decoder, config.level4.childrenField )
( config.level3.decoder, config.level3.childrenField )
( config.level2.decoder, config.level2.childrenField )
config.leaf.decoder
encode : DecoderConfig a b c leaf path -> Tree4 a b c leaf -> Value
encode config tree =
encode4
( config.level4.encoders, config.level4.childrenField )
( config.level3.encoders, config.level3.childrenField )
( config.level2.encoders, config.level2.childrenField )
config.leaf.encode
tree
pathDecoder : DecoderConfig a b c leaf path -> Decoder path
pathDecoder config =
(JD.field "path" <| JD.array JD.int)
|> JD.andThen
(\path ->
case Array.length path of
0 ->
JD.succeed (config.level4.pathType << TreePath4)
1 ->
JD.succeed (config.level3.pathType << TreePath3)
2 ->
JD.succeed (config.level2.pathType << TreePath2)
3 ->
JD.succeed (config.leaf.pathType << TreePath1)
otherwise ->
JD.fail <| "Illegal path length " ++ toString (Array.length path)
)
|> JD.andThen
(\pathConstructor ->
JD.map2 (\tree path -> pathConstructor { tree = tree, path = path })
(JD.field "tree" <| decoder config)
(JD.field "path" <| JD.array JD.int)
)
toRootPath : Tree4 a b c leaf -> TreePath4 a b c leaf
toRootPath tree =
TreePath4
{ tree = tree
, path = Array.empty
}
decoder1 : Decoder leaf -> Decoder (Tree1 leaf)
decoder1 leafDecoder =
leafDecoder
|> JD.map (\data -> Tree1 { data = data })
encode1 : (leaf -> Value) -> Tree1 leaf -> Value
encode1 leafEncode (Tree1 { data }) =
leafEncode data
pathEncode1 : DecoderConfig a b c leaf path -> TreePath1 a b c leaf -> Value
pathEncode1 config (TreePath1 { tree, path }) =
JE.object
[ ( "tree", encode config tree )
, ( "path", (JE.array << Array.map JE.int) path )
]
getFocusedTree1 : TreePath1 a b c leaf -> Tree1 leaf
getFocusedTree1 (TreePath1 { tree, path }) =
getFocusedTree2 (TreePath2 { tree = tree, path = path })
|> treeChildren2
|> Array.get (Array.get 2 path |> unsafe "getFocusedTree1")
|> unsafe "getFocusedTree1"
treeData1 : Tree1 leaf -> leaf
treeData1 (Tree1 { data }) =
data
data1 : TreePath1 a b c leaf -> leaf
data1 =
getFocusedTree1 >> treeData1
top1 : TreePath1 a b c leaf -> TreePath4 a b c leaf
top1 (TreePath1 { tree, path }) =
TreePath4 { tree = tree, path = Array.empty }
offset1 : Int -> TreePath1 a b c leaf -> Maybe (TreePath1 a b c leaf)
offset1 dx ((TreePath1 { tree, path }) as treePath) =
treePath
|> up1
|> Maybe.andThen (down2 <| (Array.get 2 path |> unsafe "offset1") + dx)
down1 : Int -> TreePath1 a b c leaf -> Maybe Never
down1 idx ((TreePath1 { tree, path }) as treePath) =
Nothing
downs1 : TreePath1 a b c leaf -> List Never
downs1 ((TreePath1 { tree, path }) as treePath) =
[]
up1 : TreePath1 a b c leaf -> Maybe (TreePath2 a b c leaf)
up1 (TreePath1 { tree, path }) =
Just <| TreePath2 { tree = tree, path = Array.slice 0 -1 path }
decoder2 : ( Decoder a, String ) -> Decoder leaf -> Decoder (Tree2 a leaf)
decoder2 ( aDecoder, aChildrenField ) leafDecoder =
JD.oneOf
[ JD.map2 (\data children -> Tree2 { data = data, children = children })
(aDecoder |> JD.map Data.BranchData)
(JD.field aChildrenField (JD.array <| decoder1 leafDecoder))
, JD.map (\data -> Tree2 { data = data, children = Array.empty })
(leafDecoder |> JD.map Data.LeafData)
]
encode2 : ( a -> List ( String, Value ), String ) -> (leaf -> Value) -> Tree2 a leaf -> Value
encode2 ( aEncoders, aChildrenField ) leafEncode (Tree2 { data, children }) =
case data of
Data.BranchData b ->
JE.object <|
( aChildrenField, JE.array <| Array.map (encode1 leafEncode) children )
:: aEncoders b
Data.LeafData l ->
leafEncode l
pathEncode2 : DecoderConfig a b c leaf path -> TreePath2 a b c leaf -> Value
pathEncode2 config (TreePath2 { tree, path }) =
JE.object
[ ( "tree", encode config tree )
, ( "path", (JE.array << Array.map JE.int) path )
]
getFocusedTree2 : TreePath2 a b c leaf -> Tree2 c leaf
getFocusedTree2 (TreePath2 { tree, path }) =
getFocusedTree3 (TreePath3 { tree = tree, path = path })
|> treeChildren3
|> Array.get (Array.get 1 path |> unsafe "getFocusedTree2")
|> unsafe "getFocusedTree2"
treeChildren2 : Tree2 a leaf -> Array (Tree1 leaf)
treeChildren2 (Tree2 { children }) =
children
treeData2 : Tree2 a leaf -> Data a leaf
treeData2 (Tree2 { data }) =
data
data2 : TreePath2 a b c leaf -> Data c leaf
data2 =
getFocusedTree2 >> treeData2
top2 : TreePath2 a b c leaf -> TreePath4 a b c leaf
top2 (TreePath2 { tree, path }) =
TreePath4 { tree = tree, path = Array.empty }
offset2 : Int -> TreePath2 a b c leaf -> Maybe (TreePath2 a b c leaf)
offset2 dx ((TreePath2 { tree, path }) as treePath) =
treePath
|> up2
|> Maybe.andThen (down3 <| (Array.get 1 path |> unsafe "offset2") + dx)
down2 : Int -> TreePath2 a b c leaf -> Maybe (TreePath1 a b c leaf)
down2 idx ((TreePath2 { tree, path }) as treePath) =
getFocusedTree2 treePath
|> treeChildren2
|> Array.get idx
|> Maybe.map (\_ -> TreePath1 { tree = tree, path = Array.push idx path })
downs2 : TreePath2 a b c leaf -> List (TreePath1 a b c leaf)
downs2 ((TreePath2 { tree, path }) as treePath) =
getFocusedTree2 treePath
|> treeChildren2
|> (\children -> Array.length children - 1)
|> List.range 0
|> List.map (\idx -> TreePath1 { tree = tree, path = Array.push idx path })
up2 : TreePath2 a b c leaf -> Maybe (TreePath3 a b c leaf)
up2 (TreePath2 { tree, path }) =
Just <| TreePath3 { tree = tree, path = Array.slice 0 -1 path }
decoder3 : ( Decoder a, String ) -> ( Decoder b, String ) -> Decoder leaf -> Decoder (Tree3 a b leaf)
decoder3 ( aDecoder, aChildrenField ) ( bDecoder, bChildrenField ) leafDecoder =
JD.oneOf
[ JD.map2 (\data children -> Tree3 { data = data, children = children })
(aDecoder |> JD.map Data.BranchData)
(JD.field aChildrenField (JD.array <| decoder2 ( bDecoder, bChildrenField ) leafDecoder))
, JD.map (\data -> Tree3 { data = data, children = Array.empty })
(leafDecoder |> JD.map Data.LeafData)
]
encode3 : ( a -> List ( String, Value ), String ) -> ( b -> List ( String, Value ), String ) -> (leaf -> Value) -> Tree3 a b leaf -> Value
encode3 ( aEncoders, aChildrenField ) ( bEncoders, bChildrenField ) leafEncode (Tree3 { data, children }) =
case data of
Data.BranchData b ->
JE.object <|
( aChildrenField, JE.array <| Array.map (encode2 ( bEncoders, bChildrenField ) leafEncode) children )
:: aEncoders b
Data.LeafData l ->
leafEncode l
pathEncode3 : DecoderConfig a b c leaf path -> TreePath3 a b c leaf -> Value
pathEncode3 config (TreePath3 { tree, path }) =
JE.object
[ ( "tree", encode config tree )
, ( "path", (JE.array << Array.map JE.int) path )
]
getFocusedTree3 : TreePath3 a b c leaf -> Tree3 b c leaf
getFocusedTree3 (TreePath3 { tree, path }) =
getFocusedTree4 (TreePath4 { tree = tree, path = path })
|> treeChildren4
|> Array.get (Array.get 0 path |> unsafe "getFocusedTree3")
|> unsafe "getFocusedTree3"
treeChildren3 : Tree3 a b leaf -> Array (Tree2 b leaf)
treeChildren3 (Tree3 { children }) =
children
treeData3 : Tree3 a b leaf -> Data a leaf
treeData3 (Tree3 { data }) =
data
data3 : TreePath3 a b c leaf -> Data b leaf
data3 =
getFocusedTree3 >> treeData3
top3 : TreePath3 a b c leaf -> TreePath4 a b c leaf
top3 (TreePath3 { tree, path }) =
TreePath4 { tree = tree, path = Array.empty }
offset3 : Int -> TreePath3 a b c leaf -> Maybe (TreePath3 a b c leaf)
offset3 dx ((TreePath3 { tree, path }) as treePath) =
treePath
|> up3
|> Maybe.andThen (down4 <| (Array.get 0 path |> unsafe "offset3") + dx)
down3 : Int -> TreePath3 a b c leaf -> Maybe (TreePath2 a b c leaf)
down3 idx ((TreePath3 { tree, path }) as treePath) =
getFocusedTree3 treePath
|> treeChildren3
|> Array.get idx
|> Maybe.map (\_ -> TreePath2 { tree = tree, path = Array.push idx path })
downs3 : TreePath3 a b c leaf -> List (TreePath2 a b c leaf)
downs3 ((TreePath3 { tree, path }) as treePath) =
getFocusedTree3 treePath
|> treeChildren3
|> (\children -> Array.length children - 1)
|> List.range 0
|> List.map (\idx -> TreePath2 { tree = tree, path = Array.push idx path })
up3 : TreePath3 a b c leaf -> Maybe (TreePath4 a b c leaf)
up3 (TreePath3 { tree, path }) =
Just <| TreePath4 { tree = tree, path = Array.slice 0 -1 path }
decoder4 : ( Decoder a, String ) -> ( Decoder b, String ) -> ( Decoder c, String ) -> Decoder leaf -> Decoder (Tree4 a b c leaf)
decoder4 ( aDecoder, aChildrenField ) ( bDecoder, bChildrenField ) ( cDecoder, cChildrenField ) leafDecoder =
JD.oneOf
[ JD.map2 (\data children -> Tree4 { data = data, children = children })
(aDecoder |> JD.map Data.BranchData)
(JD.field aChildrenField (JD.array <| decoder3 ( bDecoder, bChildrenField ) ( cDecoder, cChildrenField ) leafDecoder))
, JD.map (\data -> Tree4 { data = data, children = Array.empty })
(leafDecoder |> JD.map Data.LeafData)
]
encode4 : ( a -> List ( String, Value ), String ) -> ( b -> List ( String, Value ), String ) -> ( c -> List ( String, Value ), String ) -> (leaf -> Value) -> Tree4 a b c leaf -> Value
encode4 ( aEncoders, aChildrenField ) ( bEncoders, bChildrenField ) ( cEncoders, cChildrenField ) leafEncode (Tree4 { data, children }) =
case data of
Data.BranchData b ->
JE.object <|
( aChildrenField, JE.array <| Array.map (encode3 ( bEncoders, bChildrenField ) ( cEncoders, cChildrenField ) leafEncode) children )
:: aEncoders b
Data.LeafData l ->
leafEncode l
pathEncode4 : DecoderConfig a b c leaf path -> TreePath4 a b c leaf -> Value
pathEncode4 config (TreePath4 { tree, path }) =
JE.object
[ ( "tree", encode config tree )
, ( "path", (JE.array << Array.map JE.int) path )
]
getFocusedTree4 : TreePath4 a b c leaf -> Tree4 a b c leaf
getFocusedTree4 (TreePath4 { tree, path }) =
tree
treeChildren4 : Tree4 a b c leaf -> Array (Tree3 b c leaf)
treeChildren4 (Tree4 { children }) =
children
treeData4 : Tree4 a b c leaf -> Data a leaf
treeData4 (Tree4 { data }) =
data
data4 : TreePath4 a b c leaf -> Data a leaf
data4 =
getFocusedTree4 >> treeData4
top4 : TreePath4 a b c leaf -> TreePath4 a b c leaf
top4 (TreePath4 { tree, path }) =
TreePath4 { tree = tree, path = Array.empty }
offset4 : Int -> TreePath4 a b c leaf -> Maybe (TreePath4 a b c leaf)
offset4 dx ((TreePath4 { tree, path }) as treePath) =
Nothing
down4 : Int -> TreePath4 a b c leaf -> Maybe (TreePath3 a b c leaf)
down4 idx ((TreePath4 { tree, path }) as treePath) =
getFocusedTree4 treePath
|> treeChildren4
|> Array.get idx
|> Maybe.map (\_ -> TreePath3 { tree = tree, path = Array.push idx path })
downs4 : TreePath4 a b c leaf -> List (TreePath3 a b c leaf)
downs4 ((TreePath4 { tree, path }) as treePath) =
getFocusedTree4 treePath
|> treeChildren4
|> (\children -> Array.length children - 1)
|> List.range 0
|> List.map (\idx -> TreePath3 { tree = tree, path = Array.push idx path })
up4 : TreePath4 a b c leaf -> Maybe Never
up4 (TreePath4 { tree, path }) =
Nothing
unsafe : String -> Maybe a -> a
unsafe msg maybe =
case maybe of
Just a ->
a
Nothing ->
Debug.crash msg
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment