{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE TypeFamilies #-}
module Buf (Buf (..), SizedStr, SizedBuilder) where
import Data.Char (intToDigit)
import qualified Data.DList as D
import Data.Kind (Type)
import Data.String
import qualified Data.Text as S
import Data.Text.Lazy (Text)
import qualified Data.Text.Lazy as L
import qualified Data.Text.Lazy.Builder as T
import qualified Data.Text.Lazy.Builder.Int as T
newtype Sized a = Sized {unSized :: (a, Int)} deriving (Show, Ord, Eq)
type SizedStr = Sized (D.DList Char)
type SizedBuilder = Sized T.Builder
instance (IsString a) => IsString (Sized a) where
fromString s = Sized (fromString s, length s)
instance (Semigroup a) => Semigroup (Sized a) where
Sized (a, b) <> Sized (c, d) = Sized (a <> c, b + d)
{-# INLINE (<>) #-}
instance (Monoid a) => Monoid (Sized a) where
mempty = Sized (mempty, 0)
mappend = (<>)
{-# INLINE mappend #-}
class (Monoid a) => Buf a where
type Output a :: Type
str :: String -> a
sText :: S.Text -> a
sText = str . S.unpack
lText :: L.Text -> a
lText = str . L.unpack
singleton :: Char -> a
digit :: Int -> a
digit = singleton . intToDigit
{-# INLINE digit #-}
cons :: Char -> a -> a
cons c s = singleton c <> s
{-# INLINE cons #-}
repeatN :: Int -> Char -> a
repeatN n = str . replicate n
size :: a -> Int
finalize :: a -> Output a
instance Buf SizedStr where
type Output SizedStr = String
str a = Sized (D.fromList a, length a)
singleton c = Sized (D.singleton c, 1)
finalize = D.toList . fst . unSized
cons c (Sized (r, m)) = Sized (D.cons c r, m + 1)
repeatN n c = Sized (D.replicate n c, n)
size = snd . unSized
instance Buf SizedBuilder where
type Output SizedBuilder = Text
str a = Sized (fromString a, length a)
sText a = Sized (T.fromText a, S.length a)
lText a = Sized (T.fromLazyText a, fromIntegral (L.length a))
singleton c = Sized (T.singleton c, 1)
digit c = Sized (T.hexadecimal c, 1)
finalize = T.toLazyText . fst . unSized
size = snd . unSized