    -- |
    -- 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, 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
    $c<> :: AsciiString -> AsciiString -> AsciiString
    <> :: AsciiString -> AsciiString -> AsciiString
    $csconcat :: NonEmpty AsciiString -> AsciiString
    sconcat :: NonEmpty AsciiString -> AsciiString
    $cstimes :: forall b. Integral b => b -> AsciiString -> AsciiString
    stimes :: forall b. Integral b => b -> 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
    $cmempty :: AsciiString
    mempty :: AsciiString
    $cmappend :: AsciiString -> AsciiString -> AsciiString
    mappend :: AsciiString -> AsciiString -> AsciiString
    $cmconcat :: [AsciiString] -> AsciiString
    mconcat :: [AsciiString] -> AsciiString
    Monoid, AsciiString -> AsciiString -> Bool
    (AsciiString -> AsciiString -> Bool)
    -> (AsciiString -> AsciiString -> Bool) -> Eq AsciiString
    forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
    $c== :: AsciiString -> AsciiString -> Bool
    == :: AsciiString -> AsciiString -> Bool
    $c/= :: AsciiString -> AsciiString -> Bool
    /= :: 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
    $ccompare :: AsciiString -> AsciiString -> Ordering
    compare :: AsciiString -> AsciiString -> Ordering
    $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
    >= :: AsciiString -> AsciiString -> Bool
    $cmax :: AsciiString -> AsciiString -> AsciiString
    max :: AsciiString -> AsciiString -> AsciiString
    $cmin :: AsciiString -> AsciiString -> AsciiString
    min :: AsciiString -> AsciiString -> AsciiString
    Ord)

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

    instance Show AsciiString where
        show :: AsciiString -> String
    show = (Char7 -> Char) -> [Char7] -> String
    forall a b. (a -> b) -> [a] -> [b]
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
    fmap Char7 -> Char
    Char7.toChar ([Char7] -> String)
    -> (AsciiString -> [Char7]) -> AsciiString -> String
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    forall {k} (cat :: k -> k -> *) (b :: k) (c :: k) (a :: k).
    Category cat =>
    cat b c -> cat a b -> cat a c
    . AsciiString -> [Item AsciiString]
    AsciiString -> [Char7]
    forall l. IsList l => l -> [Item l]
    toList
    instance IsString AsciiString where
        fromString :: String -> AsciiString
    fromString = [Item AsciiString] -> AsciiString
    [Char7] -> AsciiString
    forall l. IsList l => [Item l] -> l
    fromList ([Char7] -> AsciiString)
    -> (String -> [Char7]) -> String -> AsciiString
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    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 a b. (a -> b) -> [a] -> [b]
    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 b c a. (b -> c) -> (a -> b) -> a -> c
    forall {k} (cat :: k -> k -> *) (b :: k) (c :: k) (a :: k).
    Category cat =>
    cat b c -> cat a b -> cat a c
    . [Item (UArray Char7)] -> UArray Char7
    [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 b c a. (b -> c) -> (a -> b) -> a -> c
    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