content: module Data.Text(
    Text,
    pack, unpack,
    show,
    empty,
    singleton,
    append,
    null,
    length,
    head,
    tail,
    cons,
    snoc,
    uncons,
    replicate,
    splitOn,
    dropWhileEnd,
    words,
    foldr,
    concat,
    lines,
    unlines,
    take,
    drop,
    takeWhile,
    dropWhile,
    dropWhileEnd,
    intercalate,
    isPrefixOf,
    isSuffixOf,
    isInfixOf,
    map,
    useAsCString,
    grabCString,
    ) where
  import qualified Prelude(); import MiniPrelude hiding(head, tail, null, length, words, map)
  import Primitives(Ptr)
  import Control.DeepSeq.Class
  import qualified Data.List as L
  import Data.Monoid.Internal
  import Data.String
  import qualified Data.ByteString.Internal as BS
  import Foreign.C.Types(CChar)
  import Unsafe.Coerce(unsafeCoerce)
  
  newtype Text = T BS.ByteString
  
  instance Eq Text where
    (==) = cmp (==)
    (/=) = cmp (/=)
  
  instance Ord Text where
    (<)  = cmp (<)
    (<=) = cmp (<=)
    (>)  = cmp (>)
    (>=) = cmp (>=)
  
  show :: Show a => a -> Text
  show = pack . MiniPrelude.show
  
  cmp :: (BS.ByteString -> BS.ByteString -> Bool) -> (Text -> Text -> Bool)
  cmp op (T x) (T y) = op x y
  
  instance Show Text where
    showsPrec p = showsPrec p . unpack
  
  instance IsString Text where
    fromString = pack
  
  instance Semigroup Text where
    (<>) = append
  
  instance Monoid Text where
    mempty = empty
  
  instance NFData Text where
    rnf (T bs) = seq bs ()
  
  empty :: Text
  empty = pack []
  
  singleton :: Char -> Text
  singleton c = pack [c]
  
  pack :: String -> Text
  pack s = T (_primitive "toUTF8" s)
  
  unpack :: Text -> String
  unpack (T t) = _primitive "fromUTF8" t
  
  append :: Text -> Text -> Text
  append (T x) (T y) = T (BS.append x y)
  
  null :: Text -> Bool
  null (T bs) = BS.null bs
  
  length :: Text -> Int
  length = L.length . unpack
  
  head :: Text -> Char
  head (T t)
    | BS.null t = error "Data.Text.head: empty"
    | otherwise = _primitive "headUTF8" t
  
  cons :: Char -> Text -> Text
  cons c t = singleton c `append` t
  
  snoc :: Text -> Char -> Text
  snoc t c = t `append` singleton c
  
  tail :: Text -> Text
  tail (T t)
    | BS.null t = error "Data.Text.tail: empty"
    | otherwise = _primitive "tailUTF8" t
  
  uncons :: Text -> Maybe (Char, Text)
  uncons t | null t    = Nothing
           | otherwise = Just (head t, tail t)
  
  replicate :: Int -> Text -> Text
  replicate = stimes
  
  splitOn :: Text -> Text -> [Text]
  splitOn s t = L.map pack $ splitOnList (unpack s) (unpack t)
  
  dropWhileEnd :: (Char -> Bool) -> Text -> Text
  dropWhileEnd p = pack . L.dropWhileEnd p . unpack
  
  splitOnList :: Eq a => [a] -> [a] -> [[a]]
  splitOnList [] = error "splitOn: empty"
  splitOnList sep = loop []
    where
      loop r  [] = [reverse r]
      loop r  s@(c:cs) | Just t <- L.stripPrefix sep s = reverse r : loop [] t
                       | otherwise = loop (c:r) cs
  
  words :: Text -> [Text]
  words = L.map pack . L.words . unpack
  
  foldr :: (Char -> a -> a) -> a -> Text -> a
  foldr f z = L.foldr f z . unpack
  
  concat :: [Text] -> Text
  concat = L.foldr append empty
  
  unlines :: [Text] -> Text
  unlines = L.foldr (\ l -> append (append l (pack "\n"))) empty
  
  lines :: Text -> [Text]
  lines = L.map pack . L.lines . unpack
  
  take :: Int -> Text -> Text
  take n = pack . L.take n . unpack
  
  drop :: Int -> Text -> Text
  drop n = pack . L.drop n . unpack
  
  intercalate :: Text -> [Text] -> Text
  intercalate _ [] = empty
  intercalate _ [x] = x
  intercalate s (x:xs) = x `append` s `append` intercalate s xs
  
  -- XXX Should make the BS version efficient and go via that
  isPrefixOf :: Text -> Text -> Bool
  isPrefixOf p s = L.isPrefixOf (unpack p) (unpack s)
  
  isSuffixOf :: Text -> Text -> Bool
  isSuffixOf p s = L.isSuffixOf (unpack p) (unpack s)
  
  isInfixOf :: Text -> Text -> Bool
  isInfixOf p s = L.isInfixOf (unpack p) (unpack s)
  
  dropWhile :: (Char -> Bool) -> Text -> Text
  dropWhile p = pack . L.dropWhile p . unpack
  
  takeWhile :: (Char -> Bool) -> Text -> Text
  takeWhile p = pack . L.takeWhile p . unpack
  
  map :: (Char -> Char) -> Text -> Text
  map f = pack . L.map f . unpack
  
  -- Get a C string of a Text.  The C string is encoded with
  -- modified UTF-8 (so no embedded NULs) and NUL terminated.
  -- The RTS retains ownership of the string, and the pointer
  -- should not be used after the subcomputations finishes.
  useAsCString :: Text -> (Ptr CChar -> IO a) -> IO a
  useAsCString (T bs) act = BS.useAsCString bs act
  
  -- Take a C string encoded with modified UTF-8 and turn it into Text.
  -- This will take ownership of the memory which will eventually
  -- be free()d.  The pointer should not be used by the caller after this call.
  grabCString :: Ptr CChar -> IO Text
  grabCString p = T <$> BS.grabCString p
  