type-of-html 0.5.1.2 → 1.0.0.0
raw patch · 7 files changed
+124/−7 lines, 7 filesPVP ok
version bump matches the API change (PVP)
API changes (from Hackage documentation)
Files
- ChangeLog.md +7/−0
- Readme.md +60/−0
- src/Html/Convert.hs +9/−0
- src/Html/Reify.hs +7/−2
- src/Html/Type.hs +4/−3
- test/Main.hs +35/−0
- type-of-html.cabal +2/−2
ChangeLog.md view
@@ -1,5 +1,12 @@ # Revision history for type-of-html +## 1.0.0.0 -- 2017-09-18++* perf increase+* more compile time optimizations+* more test cases+* more Convert instances+ ## 0.5.1.0 -- 2017-09-13 * perf increase
Readme.md view
@@ -221,6 +221,66 @@ `-O2`. Be aware, that cabal compiles only with `-O` if you don't specify explicitly otherwise. +### Even faster++Need for speed? Consider following advise, which is sorted in+ascending order of perf gains:++If you've got attributes or contents of length 1, use a Char.++This allows for a more efficient conversion to builder, because we+know the length at compile time.++```haskell+div_ 'a'+```++If you know for sure that you don't need escaping, use `Raw`.++This allows for a more efficient conversion to builder, because we+don't need to escape.++```haskell+div_ (Raw "a")+```++If you've got numeric attributes or contents, don't convert it to a+string.++This allows for a more efficient conversion to builder, because we+don't need to escape and don't need to handle utf8.++```haskell+div_ (42 :: Int)+```++If you know that an attribute or content is empty, use `()`.++This allows for more compile time appending and avoids two runtime+appends.++```haskell+div_ ()+```++If you know for sure a string at compile time which doesn't need+escaping, use a `Proxy Symbol`.++This allows for more compile time appending and avoids two runtime+appends, escaping and conversion to a builder.++```haskell+div_ (Proxy @"hello")+```++These techniques can have dramatic performance implications,+especially the last two. If you replace for example in the `big page+with attributes` benchmark every string with a Proxy Symbol, it'll run+in 10 ns which is 500 times faster than `blaze-html`. Looking at core+shows that this is equivalent of directly embedding the entire+resulting html as bytestring in the binary and is therefore the+fastest possible output.+ ## Comparision to lucid and blaze-html Advantages of `type-of-html`:
src/Html/Convert.hs view
@@ -118,6 +118,9 @@ instance Convert b => Convert (a := b) where {-# INLINE convert #-} convert (AT x) = convert x+instance Convert (Raw Char) where+ {-# INLINE convert #-}+ convert (Raw c) = Converted (B.charUtf8 c) instance Convert (Raw String) where {-# INLINE convert #-} convert (Raw x) = stringConvRaw x@@ -127,6 +130,12 @@ instance Convert (Raw TL.Text) where {-# INLINE convert #-} convert (Raw x) = Converted (TL.encodeUtf8Builder x)+instance Convert (Raw B.Builder) where+ {-# INLINE convert #-}+ convert (Raw x) = Converted x+instance Convert Char where+ {-# INLINE convert #-}+ convert = Converted . BP.primBounded escapeUtf8 instance Convert String where {-# INLINE convert #-} convert = stringConv
src/Html/Reify.hs view
@@ -61,15 +61,20 @@ instance {-# INCOHERENT #-} ( Convert val- ) => Renderchunks (Tagged ("" ': ss) val) where+ ) => Renderchunks (Tagged '[""] val) where {-# INLINE renderchunks #-} renderchunks (Tagged x) = unConv (convert x) instance {-# INCOHERENT #-}+ Renderchunks (Tagged '[] val) where+ {-# INLINE renderchunks #-}+ renderchunks _ = mempty++instance {-# INCOHERENT #-} ( Convert val , KnownSymbol s- ) => Renderchunks (Tagged (s ': ss) val) where+ ) => Renderchunks (Tagged '[s] val) where {-# INLINE renderchunks #-} renderchunks (Tagged x) = unConv (convert (Proxy @ s))
src/Html/Type.hs view
@@ -659,7 +659,9 @@ CountContent (a # b) = CountContent a + CountContent b CountContent (_ > b) = CountContent b CountContent ((_ :@: b) c) = CountContent b + CountContent c+ CountContent (a := b) = CountContent b CountContent () = 0+ CountContent (Proxy _) = 0 CountContent _ = 1 -- | We need efficient cons, snoc and append. This API has cons(O1)@@ -680,14 +682,13 @@ -- | Flatten a html tree of elements into a type list of tags. type family ToTypeList a :: FingerTree where- ToTypeList (a # ()) = ToTypeList a- ToTypeList (() # b) = ToTypeList b ToTypeList (a # b) = ToTypeList a >< ToTypeList b ToTypeList (a > ()) = 'FingerTree '[] (If (HasContent (GetInfo a)) (AppendSymbol (OpenTag a) (CloseTag a)) (OpenTag a)) ToTypeList ((a :@: b) ()) = AppendSymbol "<" (ShowElement a) <| ToTypeList b |> If (HasContent (GetInfo a)) (AppendSymbol ">" (CloseTag a)) ">" ToTypeList (a > b) = OpenTag a <| ToTypeList b |> CloseTag a ToTypeList ((a :@: b) c) = (AppendSymbol "<" (ShowElement a) <| ToTypeList b) >< (">" <| ToTypeList c |> CloseTag a)- ToTypeList (a := b) = 'FingerTree '[ShowAttribute a] "\""+ ToTypeList (a := b) = ShowAttribute a <| ToTypeList b |> "\""+ ToTypeList () = 'FingerTree '[] "" ToTypeList (Proxy x) = 'FingerTree '[] x ToTypeList x = 'FingerTree '[""] ""
test/Main.hs view
@@ -1,3 +1,4 @@+{-# LANGUAGE TypeApplications #-} {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE TypeOperators #-} {-# LANGUAGE DataKinds #-}@@ -169,3 +170,37 @@ allT (img_A (A.id_ "a ä € 𝄞")) shouldBe "<img id=\"a ä € 𝄞\">"++ it "handles complex compile time documents" $ do++ allT (div_ () # i_ ())+ shouldBe+ "<div></div><i></i>"++ allT (div_ () # "a")+ shouldBe+ "<div></div>a"++ allT ("a" # i_ ())+ shouldBe+ "a<i></i>"++ allT (div_ () # i_ (Proxy @"a"))+ shouldBe+ "<div></div><i>a</i>"++ allT (div_ (Proxy @"a") # i_ ())+ shouldBe+ "<div>a</div><i></i>"++ allT (Proxy @"1" # "2")+ shouldBe+ "12"++ allT ("1" # Proxy @"2")+ shouldBe+ "12"++ allT (div_ () # td_ (Proxy @"1" # "2" # div_ () # i_A (A.id_ (Proxy @"3")) "4"))+ shouldBe+ "<div></div><td>12<div></div><i id=\"3\">4</i></td>"
type-of-html.cabal view
@@ -1,5 +1,5 @@ name: type-of-html-version: 0.5.1.2+version: 1.0.0.0 synopsis: High performance type driven html generation. description: This library makes most invalid html documents compile time errors and uses advanced type level features to realise compile time computations. license: BSD3@@ -37,7 +37,7 @@ type: exitcode-stdio-1.0 main-is: Main.hs hs-source-dirs: test- ghc-options: -Wall+ ghc-options: -Wall -O0 default-language: Haskell2010 build-depends: base >= 4.10 && < 4.11 , type-of-html