-- |
-- Module      : Foundation.Primitives.Types.AsciiString
-- License     : BSD-style
-- Maintainer  : Haskell Foundation
-- Stability   : experimental
-- Portability : portable
--
-- A AsciiString type backed by a `ASCII` encoded byte array and all the necessary
-- functions to manipulate the string.
--
{-# LANGUAGE BangPatterns               #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE MagicHash                  #-}
{-# LANGUAGE TypeFamilies               #-}
{-# LANGUAGE FlexibleContexts           #-}
module Basement.Types.AsciiString
    ( AsciiString(..)
    , MutableAsciiString(..)
    -- * Binary conversion
    , fromBytesUnsafe
    , fromBytes
    ) where

import           Basement.Compat.Base
import           Basement.Compat.Semigroup
import           Basement.Types.Char7
import           Basement.UArray.Base
import qualified Basement.Types.Char7 as Char7
import qualified Basement.UArray as A (all, unsafeRecast)

-- | Opaque packed array of characters in the ASCII encoding
newtype AsciiString = AsciiString { AsciiString -> UArray Char7
toBytes :: UArray Char7 }
    deriving (Typeable, b -> AsciiString -> AsciiString
NonEmpty AsciiString -> AsciiString
AsciiString -> AsciiString -> AsciiString
(AsciiString -> AsciiString -> AsciiString)
-> (NonEmpty AsciiString -> AsciiString)
-> (forall b. Integral b => b -> AsciiString -> AsciiString)
-> Semigroup AsciiString
forall b. Integral b => b -> AsciiString -> AsciiString
forall a.
(a -> a -> a)
-> (NonEmpty a -> a)
-> (forall b. Integral b => b -> a -> a)
-> Semigroup a
stimes :: b -> AsciiString -> AsciiString
$cstimes :: forall b. Integral b => b -> AsciiString -> AsciiString
sconcat :: NonEmpty AsciiString -> AsciiString
$csconcat :: NonEmpty AsciiString -> AsciiString
<> :: AsciiString -> AsciiString -> AsciiString
$c<> :: AsciiString -> AsciiString -> AsciiString
Semigroup, Semigroup AsciiString
AsciiString
Semigroup AsciiString
-> AsciiString
-> (AsciiString -> AsciiString -> AsciiString)
-> ([AsciiString] -> AsciiString)
-> Monoid AsciiString
[AsciiString] -> AsciiString
AsciiString -> AsciiString -> AsciiString
forall a.
Semigroup a -> a -> (a -> a -> a) -> ([a] -> a) -> Monoid a
mconcat :: [AsciiString] -> AsciiString
$cmconcat :: [AsciiString] -> AsciiString
mappend :: AsciiString -> AsciiString -> AsciiString
$cmappend :: AsciiString -> AsciiString -> AsciiString
mempty :: AsciiString
$cmempty :: AsciiString
$cp1Monoid :: Semigroup AsciiString
Monoid, AsciiString -> AsciiString -> Bool
(AsciiString -> AsciiString -> Bool)
-> (AsciiString -> AsciiString -> Bool) -> Eq AsciiString
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: AsciiString -> AsciiString -> Bool
$c/= :: AsciiString -> AsciiString -> Bool
== :: AsciiString -> AsciiString -> Bool
$c== :: AsciiString -> AsciiString -> Bool
Eq, Eq AsciiString
Eq AsciiString
-> (AsciiString -> AsciiString -> Ordering)
-> (AsciiString -> AsciiString -> Bool)
-> (AsciiString -> AsciiString -> Bool)
-> (AsciiString -> AsciiString -> Bool)
-> (AsciiString -> AsciiString -> Bool)
-> (AsciiString -> AsciiString -> AsciiString)
-> (AsciiString -> AsciiString -> AsciiString)
-> Ord AsciiString
AsciiString -> AsciiString -> Bool
AsciiString -> AsciiString -> Ordering
AsciiString -> AsciiString -> AsciiString
forall a.
Eq a
-> (a -> a -> Ordering)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> a)
-> (a -> a -> a)
-> Ord a
min :: AsciiString -> AsciiString -> AsciiString
$cmin :: AsciiString -> AsciiString -> AsciiString
max :: AsciiString -> AsciiString -> AsciiString
$cmax :: AsciiString -> AsciiString -> AsciiString
>= :: AsciiString -> AsciiString -> Bool
$c>= :: AsciiString -> AsciiString -> Bool
> :: AsciiString -> AsciiString -> Bool
$c> :: AsciiString -> AsciiString -> Bool
<= :: AsciiString -> AsciiString -> Bool
$c<= :: AsciiString -> AsciiString -> Bool
< :: AsciiString -> AsciiString -> Bool
$c< :: AsciiString -> AsciiString -> Bool
compare :: AsciiString -> AsciiString -> Ordering
$ccompare :: AsciiString -> AsciiString -> Ordering
$cp1Ord :: Eq AsciiString
Ord)

newtype MutableAsciiString st = MutableAsciiString (MUArray Char7 st)
    deriving (Typeable)

instance Show AsciiString where
    show :: AsciiString -> String
show = (Char7 -> Char) -> [Char7] -> String
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap Char7 -> Char
Char7.toChar ([Char7] -> String)
-> (AsciiString -> [Char7]) -> AsciiString -> String
forall k (cat :: k -> k -> *) (b :: k) (c :: k) (a :: k).
Category cat =>
cat b c -> cat a b -> cat a c
. AsciiString -> [Char7]
forall l. IsList l => l -> [Item l]
toList
instance IsString AsciiString where
    fromString :: String -> AsciiString
fromString = [Char7] -> AsciiString
forall l. IsList l => [Item l] -> l
fromList ([Char7] -> AsciiString)
-> (String -> [Char7]) -> String -> AsciiString
forall k (cat :: k -> k -> *) (b :: k) (c :: k) (a :: k).
Category cat =>
cat b c -> cat a b -> cat a c
. (Char -> Char7) -> String -> [Char7]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap Char -> Char7
Char7.fromCharMask
instance IsList AsciiString where
    type Item AsciiString = Char7
    fromList :: [Item AsciiString] -> AsciiString
fromList = UArray Char7 -> AsciiString
AsciiString (UArray Char7 -> AsciiString)
-> ([Char7] -> UArray Char7) -> [Char7] -> AsciiString
forall k (cat :: k -> k -> *) (b :: k) (c :: k) (a :: k).
Category cat =>
cat b c -> cat a b -> cat a c
. [Char7] -> UArray Char7
forall l. IsList l => [Item l] -> l
fromList
    toList :: AsciiString -> [Item AsciiString]
toList (AsciiString UArray Char7
chars) = UArray Char7 -> [Item (UArray Char7)]
forall l. IsList l => l -> [Item l]
toList UArray Char7
chars

-- | Convert a Byte Array representing ASCII data directly to an AsciiString without checking for ASCII validity
--
-- If the input contains invalid Char7 value (anything above 0x7f),
-- it will trigger runtime async errors when processing data.
--
-- In doubt, use 'fromBytes'
fromBytesUnsafe :: UArray Word8 -> AsciiString
fromBytesUnsafe :: UArray Word8 -> AsciiString
fromBytesUnsafe = UArray Char7 -> AsciiString
AsciiString (UArray Char7 -> AsciiString)
-> (UArray Word8 -> UArray Char7) -> UArray Word8 -> AsciiString
forall k (cat :: k -> k -> *) (b :: k) (c :: k) (a :: k).
Category cat =>
cat b c -> cat a b -> cat a c
. UArray Word8 -> UArray Char7
forall a b. (PrimType a, PrimType b) => UArray a -> UArray b
A.unsafeRecast

-- | Convert a Byte Array representing ASCII checking validity.
--
-- If the byte array is not valid, then Nothing is returned
fromBytes :: UArray Word8 -> Maybe AsciiString
fromBytes :: UArray Word8 -> Maybe AsciiString
fromBytes UArray Word8
arr
    | (Word8 -> Bool) -> UArray Word8 -> Bool
forall ty. PrimType ty => (ty -> Bool) -> UArray ty -> Bool
A.all (\Word8
x -> Word8
x Word8 -> Word8 -> Bool
forall a. Ord a => a -> a -> Bool
< Word8
0x80) UArray Word8
arr = AsciiString -> Maybe AsciiString
forall a. a -> Maybe a
Just (AsciiString -> Maybe AsciiString)
-> AsciiString -> Maybe AsciiString
forall a b. (a -> b) -> a -> b
$ UArray Char7 -> AsciiString
AsciiString (UArray Char7 -> AsciiString) -> UArray Char7 -> AsciiString
forall a b. (a -> b) -> a -> b
$ UArray Word8 -> UArray Char7
forall a b. (PrimType a, PrimType b) => UArray a -> UArray b
A.unsafeRecast UArray Word8
arr
    | Bool
otherwise                  = Maybe AsciiString
forall a. Maybe a
Nothing