module AsciiString
(
AsciiString,
length,
fromSeptetList,
fromByteString,
fromShortByteString,
toSeptetList,
toByteString,
toShortByteString,
)
where
import AsciiString.Prelude hiding (length)
import qualified Data.List as List
import qualified Data.ByteString as ByteString
import qualified Data.ByteString.Short.Internal as ShortByteString
import qualified DeferredFolds.UnfoldM as UnfoldM
import qualified AsciiString.FoldMs as FoldMs
import qualified Control.Foldl as Foldl
import qualified PrimitiveExtras.PrimArray as PrimArray
import qualified Data.Serialize as Serialize
data AsciiString = AsciiString {-# UNPACK #-} !Int {-# UNPACK #-} !(PrimArray Word8)
deriving instance Eq AsciiString
deriving instance Ord AsciiString
deriving instance Generic AsciiString
instance NFData AsciiString where
rnf a = seq a ()
instance Hashable AsciiString where
hashWithSalt salt (AsciiString size pa@(PrimArray ba)) =
hashByteArrayWithSalt ba 0 (sizeofPrimArray pa) (hashWithSalt salt size)
instance Show AsciiString where
show = show . toByteString
instance IsString AsciiString where
fromString = fromSeptetList . fmap (fromIntegral . ord)
instance Serialize AsciiString where
put (AsciiString size (PrimArray ba)) = do
Serialize.put size
Serialize.putShortByteString (ShortByteString.SBS ba)
get = do
septetsAmount <- Serialize.get
let octetsAmount = div ((septetsAmount + 1) * 7) 8
ShortByteString.SBS ba <- Serialize.getShortByteString octetsAmount
return (AsciiString septetsAmount (PrimArray ba))
length :: AsciiString -> Int
length (AsciiString length _) = length
fromSeptetList :: [Word8] -> AsciiString
fromSeptetList list =
fromUnfoldM (List.length list) (UnfoldM.foldable list)
fromByteString :: ByteString -> AsciiString
fromByteString byteString =
fromUnfoldM (ByteString.length byteString) (UnfoldM.byteStringBytes byteString)
fromShortByteString :: ShortByteString -> AsciiString
fromShortByteString byteString =
fromUnfoldM (ShortByteString.length byteString) (UnfoldM.shortByteStringBytes byteString)
{-# INLINE fromUnfoldM #-}
fromUnfoldM :: Int -> UnfoldM IO Word8 -> AsciiString
fromUnfoldM size unfoldM =
AsciiString size (unsafeDupablePerformIO (UnfoldM.foldM (FoldMs.sizedSeptetPrimArrayFromSeptets size) unfoldM))
toSeptetList :: AsciiString -> [Word8]
toSeptetList = unsafeDupablePerformIO . UnfoldM.foldM (Foldl.generalize Foldl.list) . toOctetUnfoldM
toByteString :: AsciiString -> ByteString
toByteString = unsafeDupablePerformIO . runSizedFoldM FoldMs.sizedByteStringFromOctets
toShortByteString :: AsciiString -> ShortByteString
toShortByteString = primArraySBS . unsafeDupablePerformIO . runSizedFoldM PrimArray.elementsFoldM where
primArraySBS :: PrimArray Word8 -> ShortByteString
primArraySBS (PrimArray ba) = ShortByteString.SBS ba
toOctetUnfoldM :: AsciiString -> UnfoldM IO Word8
toOctetUnfoldM (AsciiString size pa) = let
takeLast = rem (7 * succ size) 8 /= 0
in UnfoldM.mapFoldMInput (FoldMs.overSeptets takeLast) (UnfoldM.primArray pa)
runSizedFoldM :: (Int -> FoldM IO Word8 output) -> AsciiString -> IO output
runSizedFoldM fold asciiString =
UnfoldM.foldM (fold (length asciiString)) (toOctetUnfoldM asciiString)