module Data.SmallString
( SmallString
, fromString
, toString
, fromText
, toText
) where
import qualified Data.SmallArray as A
import qualified Data.SmallArray.Unsafe as A
import qualified Codec.Binary.UTF8.String as UTF8
import Data.Word (Word8)
import qualified Data.String as S ( IsString(..) )
import qualified Data.Text as T
import qualified Data.Text.Encoding as T
import qualified Data.ByteString as B
import qualified Data.ByteString.Internal as B
import qualified Data.ByteString.Unsafe as B
import Control.DeepSeq
import Foreign.Ptr (Ptr, plusPtr)
import Foreign.Storable (poke)
import Data.Hashable as H
newtype SmallString = SmallString (A.Array Word8)
instance Eq SmallString where
(==) = eqSmallString
instance Ord SmallString where
compare = compareSmallString
instance Show SmallString where
show = show . toString
instance NFData SmallString where
rnf (SmallString arr) = rnf arr
instance S.IsString SmallString where
fromString = fromString
instance H.Hashable SmallString where
hash (SmallString arr) = H.hash arr
compareSmallString :: SmallString -> SmallString -> Ordering
compareSmallString (SmallString lhsAry) (SmallString rhsAry)
= compare lhsAry rhsAry
eqSmallString :: SmallString -> SmallString -> Bool
eqSmallString (SmallString lhs) (SmallString rhs)
= lhs == rhs
fromString :: String -> SmallString
fromString
= SmallString . A.fromList . UTF8.encode
toString :: SmallString -> String
toString (SmallString ary)
= UTF8.decode . A.toList $ ary
fromText :: T.Text -> SmallString
fromText = fromBS . T.encodeUtf8
toText :: SmallString -> T.Text
toText = T.decodeUtf8 . toBS
fromBS :: B.ByteString -> SmallString
fromBS bs = SmallString $
let len = B.length bs
in A.run $ do
arr <- A.unsafeNew len
mapM_ (\ix -> A.unsafeWrite arr ix (B.unsafeIndex bs ix)) [0 .. len]
return arr
toBS :: SmallString -> B.ByteString
toBS (SmallString ary) = B.unsafeCreate len (go ary 0)
where
len = A.length ary
go :: A.Array Word8 -> Int -> Ptr Word8 -> IO ()
go !ary !i !p
| i < len = do poke p (A.unsafeIndex ary i)
go ary (i + 1) (p `plusPtr` 1)
| otherwise = return ()