snap-core-0.2.1: src/Data/CIByteString.hs
{-# LANGUAGE BangPatterns #-}
{-# LANGUAGE OverloadedStrings #-}
-- | "Data.CIByteString" is a module containing 'CIByteString', a wrapper for
-- 'ByteString' which provides case-insensitive (ASCII-wise) 'Ord' and 'Eq'
-- instances.
--
-- 'CIByteString' also has an 'IsString' instance, so if you use the
-- \"OverloadedStrings\" LANGUAGE pragma you can write case-insensitive string
-- literals, e.g.:
--
-- @
-- \> let a = \"Foo\" in
-- putStrLn $ (show $ unCI a) ++ \"==\\\"FoO\\\" is \" ++ show (a == \"FoO\")
-- \"Foo\"==\"FoO\" is True
-- @
module Data.CIByteString
( CIByteString
, toCI
, unCI
, ciToLower
) where
-- for IsString instance
import Data.ByteString.Char8 ()
import Data.ByteString (ByteString)
import Data.ByteString.Internal (c2w, w2c)
import qualified Data.ByteString as S
import Data.Char
import Data.String
-- | A case-insensitive newtype wrapper for 'ByteString'
data CIByteString = CIByteString { unCI :: !ByteString
, _lowercased :: !ByteString }
toCI :: ByteString -> CIByteString
toCI s = CIByteString s t
where
t = lowercase s
ciToLower :: CIByteString -> ByteString
ciToLower = _lowercased
instance Show CIByteString where
show (CIByteString s _) = show s
lowercase :: ByteString -> ByteString
lowercase = S.map (c2w . toLower . w2c)
instance Eq CIByteString where
(CIByteString _ a) == (CIByteString _ b) = a == b
(CIByteString _ a) /= (CIByteString _ b) = a /= b
instance Ord CIByteString where
(CIByteString _ a) <= (CIByteString _ b) = a <= b
instance IsString CIByteString where
fromString = toCI . fromString