+instance SortingCollection Headers (CIAscii, Ascii) where
+ {-# INLINE minView #-}
+ minView (Headers m) = second Headers <$> minView m
+
+merge ∷ Ascii → Ascii → Ascii
+{-# INLINE merge #-}
+merge a b
+ | nullA a ∧ nullA b = (∅)
+ | nullA a = b
+ | nullA b = a
+ | otherwise = a ⊕ ", " ⊕ b
+ where
+ nullA ∷ Ascii → Bool
+ {-# INLINE nullA #-}
+ nullA = null ∘ A.toByteString
+
+{-
+ message-header = field-name ":" [ field-value ]
+ field-name = token
+ field-value = *( field-content | LWS )
+ field-content = <field-value を構成し、*TEXT あるいは
+ token, separators, quoted-string を連結
+ したものから成る OCTET>
+
+ field-value の先頭および末尾にある LWS は全て削除され、それ以外の
+ LWS は單一の SP に變換される。
+-}
+headers ∷ Parser Headers
+{-# INLINEABLE headers #-}
+headers = do xs ← P.many header
+ crlf
+ return $ fromFoldable xs
+ where
+ header ∷ Parser (CIAscii, Ascii)
+ header = do name ← A.toCIAscii <$> token
+ void $ char ':'
+ skipMany lws
+ values ← content `sepBy` try lws
+ skipMany (try lws)
+ crlf
+ return (name, joinValues values)
+
+ content ∷ Parser Ascii
+ {-# INLINE content #-}
+ content = A.unsafeFromByteString
+ <$>
+ takeWhile1 (\c → isText c ∧ c ≢ '\x20')
+
+ joinValues ∷ [Ascii] → Ascii
+ {-# INLINE joinValues #-}
+ joinValues = A.fromAsciiBuilder
+ ∘ mconcat
+ ∘ intersperse (A.toAsciiBuilder "\x20")
+ ∘ map A.toAsciiBuilder
+
+printHeaders ∷ Headers → AsciiBuilder
+printHeaders (Headers m)
+ = mconcat (map printHeader (fromFoldable m)) ⊕
+ A.toAsciiBuilder "\x0D\x0A"
+ where
+ printHeader ∷ (CIAscii, Ascii) → AsciiBuilder
+ printHeader (name, value)
+ = A.toAsciiBuilder (A.fromCIAscii name) ⊕
+ A.toAsciiBuilder ": " ⊕
+ A.toAsciiBuilder value ⊕
+ A.toAsciiBuilder "\x0D\x0A"