-- | Utilities for working with 'Data.Text.Short.ShortText'
--
-- This module is meant to be imported qualified as
-- @
-- import Mikan.Utils.ShortText qualified as TS
-- @
module Mikan.Utils.ShortText
  ( -- * Creation
    unsafeCreate
    -- * Length
  , lengthBytes
    -- * Breaking into lines and words
  , unwords
    -- * Conversion
  , toByteArray
  , unsafeFromByteArray
  , copyBytes
  ) where

import Prelude hiding (unwords)

import Control.Monad.ST
import Control.Monad.Primitive

import Data.ByteString.Short qualified as SBS
import Data.Primitive.ByteArray
import Data.Text.Short (ShortText)
import Data.Text.Short qualified as TS
import Data.Text.Short.Unsafe qualified as TS

import Mikan.Utils.MinimalArray.Lifted qualified as AL
import Mikan.Utils.Text qualified as T

--------------------------------------------------------------------------------
-- Creation

{-# INLINE unsafeCreate #-}
-- | \(\mathcal{O}(1)\). Create a 'ShortText' from a newly allocated 'MutableByteArray'
-- of length @n@.
--
-- The caller is responsible for ensuring that the 'MutableByteArray' is filled with
-- valid UTF-8 encoded text.
unsafeCreate :: Int -> (forall s. MutableByteArray s -> ST s ()) -> ShortText
unsafeCreate :: Int -> (forall s. MutableByteArray s -> ST s ()) -> ShortText
unsafeCreate Int
n forall s. MutableByteArray s -> ST s ()
go = (forall s. ST s ShortText) -> ShortText
forall a. (forall s. ST s a) -> a
runST do
  arr <- Int -> ST s (MutableByteArray (PrimState (ST s)))
forall (m :: * -> *).
PrimMonad m =>
Int -> m (MutableByteArray (PrimState m))
newByteArray Int
n
  go arr
  TS.fromShortByteStringUnsafe . SBS.ShortByteString <$> unsafeFreezeByteArray arr

--------------------------------------------------------------------------------
-- Length

{-# INLINE lengthBytes #-}
-- | \(\mathcal{O}(1)\). Get the length of a 'ShortText' in bytes.
lengthBytes :: ShortText -> Int
lengthBytes :: ShortText -> Int
lengthBytes = ShortByteString -> Int
SBS.length (ShortByteString -> Int)
-> (ShortText -> ShortByteString) -> ShortText -> Int
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ShortText -> ShortByteString
TS.toShortByteString

--------------------------------------------------------------------------------
-- Breaking into lines and words

{-# INLINE unwords #-}
unwords :: [ShortText] -> ShortText
unwords :: [ShortText] -> ShortText
unwords = ShortText -> [ShortText] -> ShortText
TS.intercalate ShortText
" "

--------------------------------------------------------------------------------
-- Conversion

{-# INLINE toByteArray #-}
-- | \(\mathcal{O}(1)\). Get the underlying 'ByteArray' of a 'ShortText'.
toByteArray :: ShortText -> ByteArray
toByteArray :: ShortText -> ByteArray
toByteArray = ShortByteString -> ByteArray
SBS.unShortByteString (ShortByteString -> ByteArray)
-> (ShortText -> ShortByteString) -> ShortText -> ByteArray
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ShortText -> ShortByteString
TS.toShortByteString

{-# INLINE unsafeFromByteArray #-}
-- | \(\mathcal{O}(1)\). Unsafely convert a 'ByteArray' to 'ShortText'.
--
-- The caller is responsible for ensuring that the 'ByteArray' contains
-- valid UTF-8.
unsafeFromByteArray :: ByteArray -> ShortText
unsafeFromByteArray :: ByteArray -> ShortText
unsafeFromByteArray = ShortByteString -> ShortText
TS.fromShortByteStringUnsafe (ShortByteString -> ShortText)
-> (ByteArray -> ShortByteString) -> ByteArray -> ShortText
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ByteArray -> ShortByteString
SBS.ShortByteString

{-# INLINE copyBytes #-}
-- | \(\mathcal{O}(n)\). Copy bytes from a 'ShortText' into a 'MutableByteArray'.
copyBytes
  :: (PrimMonad m)
  => MutableByteArray (PrimState m)
  -- ^ Destination buffer.
  -> Int
  -- ^ Offset into the destination buffer, measured in bytes.
  -> ShortText
  -- ^ Source 'ShortText'.
  -> Int
  -- ^ Offset into the 'ShortText', measured in bytes.
  -> Int
  -- ^ How many bytes to copy
  -> m ()
copyBytes :: forall (m :: * -> *).
PrimMonad m =>
MutableByteArray (PrimState m)
-> Int -> ShortText -> Int -> Int -> m ()
copyBytes MutableByteArray (PrimState m)
dest Int
destOff ShortText
src Int
srcOff Int
len =
  MutableByteArray (PrimState m)
-> Int -> ByteArray -> Int -> Int -> m ()
forall (m :: * -> *).
PrimMonad m =>
MutableByteArray (PrimState m)
-> Int -> ByteArray -> Int -> Int -> m ()
copyByteArray MutableByteArray (PrimState m)
dest Int
destOff (ShortText -> ByteArray
toByteArray ShortText
src) Int
srcOff Int
len