module Text.Ascii
(
IsAscii(..)
, isAscii
, Ascii
, maybeAscii
, ascii
, isControl
, isPrintable
, isWhiteSpace
, isSpaceOrTab
, isLower
, isUpper
, toLower
, toUpper
, isAlpha
, isAlphaNum
, isDecDigit
, isNzDecDigit
, fromDecDigit
, fromNzDecDigit
, unsafeFromDecDigit
, isBinDigit
, isNzBinDigit
, fromBinDigit
, fromNzBinDigit
, unsafeFromBinDigit
, isOctDigit
, isNzOctDigit
, fromOctDigit
, fromNzOctDigit
, unsafeFromOctDigit
, isUpHexDigit
, isNzUpHexDigit
, fromUpHexDigit
, fromNzUpHexDigit
, unsafeFromUpHexDigit
, isLowHexDigit
, isNzLowHexDigit
, fromLowHexDigit
, fromNzLowHexDigit
, unsafeFromLowHexDigit
, isHexDigit
, isNzHexDigit
, fromHexDigit
, fromNzHexDigit
, unsafeFromHexDigit
, isControl8
, isPrintable8
, isWhiteSpace8
, isSpaceOrTab8
, isLower8
, isUpper8
, toLower8
, toUpper8
, isAlpha8
, isAlphaNum8
, isDecDigit8
, isNzDecDigit8
, fromDecDigit8
, fromNzDecDigit8
, unsafeFromDecDigit8
, isBinDigit8
, isNzBinDigit8
, fromBinDigit8
, fromNzBinDigit8
, unsafeFromBinDigit8
, isOctDigit8
, isNzOctDigit8
, fromOctDigit8
, fromNzOctDigit8
, unsafeFromOctDigit8
, isUpHexDigit8
, isNzUpHexDigit8
, fromUpHexDigit8
, fromNzUpHexDigit8
, unsafeFromUpHexDigit8
, isLowHexDigit8
, isNzLowHexDigit8
, fromLowHexDigit8
, fromNzLowHexDigit8
, unsafeFromLowHexDigit8
, isHexDigit8
, isNzHexDigit8
, fromHexDigit8
, fromNzHexDigit8
, unsafeFromHexDigit8
) where
import Data.Checked
import Data.Function (on)
import Data.Char (ord, chr)
import Data.String (IsString(..))
import Data.Word (Word8)
import qualified Data.ByteString as BS
import qualified Data.ByteString.Lazy as BL
import qualified Data.Text as TS
import qualified Data.Text.Lazy as TL
import Data.Semigroup (Semigroup(..))
import Data.Monoid (Monoid(..))
import Data.CaseInsensitive (FoldCase(..))
import Data.Hashable (Hashable(..))
data IsAscii = IsAscii
instance Property IsAscii Word8 where
holds _ = (< 128)
instance Property IsAscii BS.ByteString where
holds _ = BS.all isAscii
instance Property IsAscii BL.ByteString where
holds _ = BL.all isAscii
instance Property IsAscii Char where
holds _ = (< 128) . ord
instance Property IsAscii α ⇒ Property IsAscii [α] where
holds _ = all isAscii
instance Property IsAscii TS.Text where
holds _ = TS.all isAscii
instance Property IsAscii TL.Text where
holds _ = TL.all isAscii
isAscii ∷ Property IsAscii v ⇒ v → Bool
isAscii = holds IsAscii
type Ascii α = Checked IsAscii α
instance Eq α ⇒ Eq (Ascii α) where
(==) = (==) `on` checked
instance Ord α ⇒ Ord (Ascii α) where
compare = compare `on` checked
instance Show α ⇒ Show (Ascii α) where
showsPrec p = showsPrec p . checked
instance Semigroup α ⇒ Semigroup (Ascii α) where
x <> y = trustMe $ checked x <> checked y
sconcat = trustMe . sconcat . fmap checked
stimes n = trustMe . stimes n . checked
instance Monoid α ⇒ Monoid (Ascii α) where
mempty = trustMe mempty
mappend x y = trustMe $ mappend (checked x) (checked y)
mconcat = trustMe . mconcat . fmap checked
instance IsString α ⇒ IsString (Ascii α) where
fromString s | isAscii s = trustMe $ fromString s
| otherwise = error $ "Not an ASCII string: " ++ show s
instance Hashable α ⇒ Hashable (Ascii α) where
#if MIN_VERSION_hashable(1,2,0)
hashWithSalt s = hashWithSalt s . checked
#else
hash = hash . checked
#endif
instance FoldCase (Ascii Char) where
foldCase = trustMap toLower
instance FoldCase (Ascii α) ⇒ FoldCase (Ascii [α]) where
foldCase = trustMap $ map $ checked . foldCase . trustThat IsAscii
instance FoldCase (Ascii BS.ByteString) where
foldCase = trustMap $ BS.map toLower8
instance FoldCase (Ascii BL.ByteString) where
foldCase = trustMap $ BL.map toLower8
instance FoldCase (Ascii TS.Text) where
foldCase = trustMap $ TS.map toLower
instance FoldCase (Ascii TL.Text) where
foldCase = trustMap $ TL.map toLower
maybeAscii ∷ Char → Maybe Word8
maybeAscii c | isAscii c = Just $ ascii c
| otherwise = Nothing
ascii ∷ Char → Word8
ascii = fromIntegral . ord
isControl ∷ Char → Bool
isControl c = w < 32 || w == 127
where w = ord c
isPrintable ∷ Char → Bool
isPrintable c = w >= 32 && w < 127
where w = ord c
isWhiteSpace ∷ Char → Bool
isWhiteSpace c = c == ' ' || (w >= 9 && w <= 13)
where w = ord c
isSpaceOrTab ∷ Char → Bool
isSpaceOrTab c = c == ' ' || c == '\t'
isLower ∷ Char → Bool
isLower c = c >= 'a' && c <= 'z'
isUpper ∷ Char → Bool
isUpper c = c >= 'A' && c <= 'Z'
toLower ∷ Char → Char
toLower c | isUpper c = chr (ord c + 32)
| otherwise = c
toUpper ∷ Char → Char
toUpper c | isLower c = chr (ord c 32)
| otherwise = c
isAlpha ∷ Char → Bool
isAlpha c = isUpper c || isLower c
isAlphaNum ∷ Char → Bool
isAlphaNum c = isDecDigit c || isAlpha c
isDecDigit ∷ Char → Bool
isDecDigit c = c >= '0' && c <= '9'
isNzDecDigit ∷ Char → Bool
isNzDecDigit c = c >= '1' && c <= '9'
fromDecDigit ∷ Num a ⇒ Char → Maybe a
fromDecDigit c | isDecDigit c = Just $ unsafeFromDecDigit c
| otherwise = Nothing
fromNzDecDigit ∷ Num a ⇒ Char → Maybe a
fromNzDecDigit c | isNzDecDigit c = Just $ unsafeFromDecDigit c
| otherwise = Nothing
unsafeFromDecDigit ∷ Num a ⇒ Char → a
unsafeFromDecDigit c = fromIntegral (ord c ord '0')
isBinDigit ∷ Char → Bool
isBinDigit c = c == '0' || c == '1'
isNzBinDigit ∷ Char → Bool
isNzBinDigit c = c == '1'
fromBinDigit ∷ Num a ⇒ Char → Maybe a
fromBinDigit c | isBinDigit c = Just $ unsafeFromBinDigit c
| otherwise = Nothing
fromNzBinDigit ∷ Num a ⇒ Char → Maybe a
fromNzBinDigit c | isNzBinDigit c = Just 1
| otherwise = Nothing
unsafeFromBinDigit ∷ Num a ⇒ Char → a
unsafeFromBinDigit = unsafeFromDecDigit
isOctDigit ∷ Char → Bool
isOctDigit c = c >= '0' && c <= '7'
isNzOctDigit ∷ Char → Bool
isNzOctDigit c = c >= '1' && c <= '7'
fromOctDigit ∷ Num a ⇒ Char → Maybe a
fromOctDigit c | isOctDigit c = Just $ unsafeFromOctDigit c
| otherwise = Nothing
fromNzOctDigit ∷ Num a ⇒ Char → Maybe a
fromNzOctDigit c | isNzOctDigit c = Just $ unsafeFromOctDigit c
| otherwise = Nothing
unsafeFromOctDigit ∷ Num a ⇒ Char → a
unsafeFromOctDigit = unsafeFromDecDigit
isLowAF ∷ Char → Bool
isLowAF c = c >= 'a' && c <= 'f'
fromLowAF ∷ Num a ⇒ Char → a
fromLowAF c = fromIntegral (ord c ord 'a' + 10)
isLowHexDigit ∷ Char → Bool
isLowHexDigit c = isDecDigit c || isLowAF c
isNzLowHexDigit ∷ Char → Bool
isNzLowHexDigit c = isNzDecDigit c || isLowAF c
fromLowHexDigit ∷ Num a ⇒ Char → Maybe a
fromLowHexDigit c | isDecDigit c = Just $ unsafeFromDecDigit c
| isLowAF c = Just $ fromLowAF c
| otherwise = Nothing
fromNzLowHexDigit ∷ Num a ⇒ Char → Maybe a
fromNzLowHexDigit c | isNzDecDigit c = Just $ unsafeFromDecDigit c
| isLowAF c = Just $ fromLowAF c
| otherwise = Nothing
unsafeFromLowHexDigit ∷ Num a ⇒ Char → a
unsafeFromLowHexDigit c | c < 'a' = unsafeFromDecDigit c
| otherwise = fromLowAF c
isUpAF ∷ Char → Bool
isUpAF c = c >= 'A' && c <= 'F'
fromUpAF ∷ Num a ⇒ Char → a
fromUpAF c = fromIntegral (ord c ord 'A' + 10)
isUpHexDigit ∷ Char → Bool
isUpHexDigit c = isDecDigit c || isUpAF c
isNzUpHexDigit ∷ Char → Bool
isNzUpHexDigit c = isNzDecDigit c || isUpAF c
fromUpHexDigit ∷ Num a ⇒ Char → Maybe a
fromUpHexDigit c | isDecDigit c = Just $ unsafeFromDecDigit c
| isUpAF c = Just $ fromUpAF c
| otherwise = Nothing
fromNzUpHexDigit ∷ Num a ⇒ Char → Maybe a
fromNzUpHexDigit c | isNzDecDigit c = Just $ unsafeFromDecDigit c
| isUpAF c = Just $ fromUpAF c
| otherwise = Nothing
unsafeFromUpHexDigit ∷ Num a ⇒ Char → a
unsafeFromUpHexDigit c | c < 'A' = unsafeFromDecDigit c
| otherwise = fromUpAF c
isHexDigit ∷ Char → Bool
isHexDigit c = isDecDigit c || isUpAF c || isLowAF c
isNzHexDigit ∷ Char → Bool
isNzHexDigit c = isNzDecDigit c || isUpAF c || isLowAF c
fromHexDigit ∷ Num a ⇒ Char → Maybe a
fromHexDigit c | isDecDigit c = Just $ unsafeFromDecDigit c
| isUpAF c = Just $ fromUpAF c
| isLowAF c = Just $ fromLowAF c
| otherwise = Nothing
fromNzHexDigit ∷ Num a ⇒ Char → Maybe a
fromNzHexDigit c | isNzDecDigit c = Just $ unsafeFromDecDigit c
| isUpAF c = Just $ fromUpAF c
| isLowAF c = Just $ fromLowAF c
| otherwise = Nothing
unsafeFromHexDigit ∷ Num a ⇒ Char → a
unsafeFromHexDigit c | c < 'A' = unsafeFromDecDigit c
| c < 'a' = fromUpAF c
| otherwise = fromLowAF c
isControl8 ∷ Word8 → Bool
isControl8 w = w < 32 || w == 127
isPrintable8 ∷ Word8 → Bool
isPrintable8 w = w >= 32 && w < 127
isWhiteSpace8 ∷ Word8 → Bool
isWhiteSpace8 w = w == ascii ' ' || w >= 9 && w <= 13
isSpaceOrTab8 ∷ Word8 → Bool
isSpaceOrTab8 w = w == ascii ' ' || w == ascii '\t'
isLower8 ∷ Word8 → Bool
isLower8 w = w >= ascii 'a' && w <= ascii 'z'
isUpper8 ∷ Word8 → Bool
isUpper8 w = w >= ascii 'A' && w <= ascii 'Z'
toLower8 ∷ Word8 → Word8
toLower8 w | isUpper8 w = w + 32
| otherwise = w
toUpper8 ∷ Word8 → Word8
toUpper8 w | isLower8 w = w 32
| otherwise = w
isAlpha8 ∷ Word8 → Bool
isAlpha8 w = isUpper8 w || isLower8 w
isAlphaNum8 ∷ Word8 → Bool
isAlphaNum8 w = isDecDigit8 w || isAlpha8 w
isDecDigit8 ∷ Word8 → Bool
isDecDigit8 w = w >= ascii '0' && w <= ascii '9'
isNzDecDigit8 ∷ Word8 → Bool
isNzDecDigit8 w = w >= ascii '1' && w <= ascii '9'
fromDecDigit8 ∷ Num a ⇒ Word8 → Maybe a
fromDecDigit8 w | isDecDigit8 w = Just $ unsafeFromDecDigit8 w
| otherwise = Nothing
fromNzDecDigit8 ∷ Num a ⇒ Word8 → Maybe a
fromNzDecDigit8 w | isNzDecDigit8 w = Just $ unsafeFromDecDigit8 w
| otherwise = Nothing
unsafeFromDecDigit8 ∷ Num a ⇒ Word8 → a
unsafeFromDecDigit8 w = fromIntegral (w ascii '0')
isBinDigit8 ∷ Word8 → Bool
isBinDigit8 w = w == ascii '0' || w == ascii '1'
isNzBinDigit8 ∷ Word8 → Bool
isNzBinDigit8 w = w == ascii '1'
fromBinDigit8 ∷ Num a ⇒ Word8 → Maybe a
fromBinDigit8 w | isBinDigit8 w = Just $ unsafeFromBinDigit8 w
| otherwise = Nothing
fromNzBinDigit8 ∷ Num a ⇒ Word8 → Maybe a
fromNzBinDigit8 w | isNzBinDigit8 w = Just 1
| otherwise = Nothing
unsafeFromBinDigit8 ∷ Num a ⇒ Word8 → a
unsafeFromBinDigit8 = unsafeFromDecDigit8
isOctDigit8 ∷ Word8 → Bool
isOctDigit8 w = w >= ascii '0' && w <= ascii '7'
isNzOctDigit8 ∷ Word8 → Bool
isNzOctDigit8 w = w >= ascii '1' && w <= ascii '7'
fromOctDigit8 ∷ Num a ⇒ Word8 → Maybe a
fromOctDigit8 w | isOctDigit8 w = Just $ unsafeFromOctDigit8 w
| otherwise = Nothing
fromNzOctDigit8 ∷ Num a ⇒ Word8 → Maybe a
fromNzOctDigit8 w | isNzOctDigit8 w = Just $ unsafeFromOctDigit8 w
| otherwise = Nothing
unsafeFromOctDigit8 ∷ Num a ⇒ Word8 → a
unsafeFromOctDigit8 = unsafeFromDecDigit8
isLowAF8 ∷ Word8 → Bool
isLowAF8 w = w >= ascii 'a' && w <= ascii 'f'
fromLowAF8 ∷ Num a ⇒ Word8 → a
fromLowAF8 w = fromIntegral (w ascii 'a' + 10)
isLowHexDigit8 ∷ Word8 → Bool
isLowHexDigit8 w = isDecDigit8 w || isLowAF8 w
isNzLowHexDigit8 ∷ Word8 → Bool
isNzLowHexDigit8 w = isNzDecDigit8 w || isLowAF8 w
fromLowHexDigit8 ∷ Num a ⇒ Word8 → Maybe a
fromLowHexDigit8 w | isDecDigit8 w = Just $ unsafeFromDecDigit8 w
| isLowAF8 w = Just $ fromLowAF8 w
| otherwise = Nothing
fromNzLowHexDigit8 ∷ Num a ⇒ Word8 → Maybe a
fromNzLowHexDigit8 w | isNzDecDigit8 w = Just $ unsafeFromDecDigit8 w
| isLowAF8 w = Just $ fromLowAF8 w
| otherwise = Nothing
unsafeFromLowHexDigit8 ∷ Num a ⇒ Word8 → a
unsafeFromLowHexDigit8 w | w < ascii 'a' = unsafeFromDecDigit8 w
| otherwise = fromLowAF8 w
isUpAF8 ∷ Word8 → Bool
isUpAF8 w = w >= ascii 'A' && w <= ascii 'F'
fromUpAF8 ∷ Num a ⇒ Word8 → a
fromUpAF8 w = fromIntegral (w ascii 'A' + 10)
isUpHexDigit8 ∷ Word8 → Bool
isUpHexDigit8 w = isDecDigit8 w || isUpAF8 w
isNzUpHexDigit8 ∷ Word8 → Bool
isNzUpHexDigit8 w = isNzDecDigit8 w || isUpAF8 w
fromUpHexDigit8 ∷ Num a ⇒ Word8 → Maybe a
fromUpHexDigit8 w | isDecDigit8 w = Just $ unsafeFromDecDigit8 w
| isUpAF8 w = Just $ fromUpAF8 w
| otherwise = Nothing
fromNzUpHexDigit8 ∷ Num a ⇒ Word8 → Maybe a
fromNzUpHexDigit8 w | isNzDecDigit8 w = Just $ unsafeFromDecDigit8 w
| isUpAF8 w = Just $ fromUpAF8 w
| otherwise = Nothing
unsafeFromUpHexDigit8 ∷ Num a ⇒ Word8 → a
unsafeFromUpHexDigit8 w | w < ascii 'A' = unsafeFromDecDigit8 w
| otherwise = fromUpAF8 w
isHexDigit8 ∷ Word8 → Bool
isHexDigit8 w = isDecDigit8 w || isUpAF8 w || isLowAF8 w
isNzHexDigit8 ∷ Word8 → Bool
isNzHexDigit8 w = isNzDecDigit8 w || isUpAF8 w || isLowAF8 w
fromHexDigit8 ∷ Num a ⇒ Word8 → Maybe a
fromHexDigit8 w | isDecDigit8 w = Just $ unsafeFromDecDigit8 w
| isUpAF8 w = Just $ fromUpAF8 w
| isLowAF8 w = Just $ fromLowAF8 w
| otherwise = Nothing
fromNzHexDigit8 ∷ Num a ⇒ Word8 → Maybe a
fromNzHexDigit8 w | isNzDecDigit8 w = Just $ unsafeFromDecDigit8 w
| isUpAF8 w = Just $ fromUpAF8 w
| isLowAF8 w = Just $ fromLowAF8 w
| otherwise = Nothing
unsafeFromHexDigit8 ∷ Num a ⇒ Word8 → a
unsafeFromHexDigit8 w | w < ascii 'A' = unsafeFromDecDigit8 w
| w < ascii 'a' = fromUpAF8 w
| otherwise = fromLowAF8 w