ascii 0.0.5.2 → 1.7.0.2
raw patch · 12 files changed
Files
- Data/Ascii.hs +0/−61
- Data/Ascii/Blaze.hs +0/−27
- Data/Ascii/ByteString.hs +0/−75
- Data/Ascii/Word8.hs +0/−148
- LICENSE +0/−30
- Setup.hs +0/−3
- ascii.cabal +72/−38
- changelog.md +305/−0
- library/ASCII.hs +872/−0
- license.txt +13/−0
- readme.md +69/−0
- test/Main.hs +148/−0
− Data/Ascii.hs
@@ -1,61 +0,0 @@-module Data.Ascii- ( -- * Datatypes- Ascii- , CIAscii- , AsciiBuilder- -- * Construction- -- ** Safe- , fromByteString- , fromChars- , fromText- -- ** Unsafe- , unsafeFromByteString- , unsafeFromString- , unsafeFromText- -- * Extraction- , toByteString- , toString- , toText- -- * Case insensitive- , toCIAscii- , fromCIAscii- , ciToByteString- -- * Builder- , toAsciiBuilder- , fromAsciiBuilder- , unsafeFromBuilder- , toBuilder- -- * Character-level functions and predicates- , fromChar- , toChar- , ascii- , isAscii- , isControl- , isPrintable- , isWhiteSpace- , isSpaceOrTab- , isLower- , isUpper- , toLower- , toUpper- , isAlpha- , isDigit- , isAlphaNum- , fromDigit- , unsafeFromDigit- , fromOctDigit- , unsafeFromOctDigit- , isUpHexDigit- , fromUpHexDigit- , unsafeFromUpHexDigit- , isLowHexDigit- , fromLowHexDigit- , unsafeFromLowHexDigit- , isHexDigit- , fromHexDigit- , unsafeFromHexDigit- ) where--import Data.Ascii.Blaze-import Data.Ascii.ByteString-import Data.Ascii.Word8
− Data/Ascii/Blaze.hs
@@ -1,27 +0,0 @@-{-# LANGUAGE GeneralizedNewtypeDeriving #-}--module Data.Ascii.Blaze where--import Data.Ascii.ByteString---- base-import Data.Monoid (Monoid)-import Data.Semigroup (Semigroup)---- blaze-builder-import qualified Blaze.ByteString.Builder as Blaze--newtype AsciiBuilder = AsciiBuilder (Blaze.Builder)- deriving (Semigroup, Monoid)--unsafeFromBuilder :: Blaze.Builder -> AsciiBuilder-unsafeFromBuilder = AsciiBuilder--toBuilder :: AsciiBuilder -> Blaze.Builder-toBuilder (AsciiBuilder b) = b--toAsciiBuilder :: Ascii -> AsciiBuilder-toAsciiBuilder (Ascii bs) = AsciiBuilder $ Blaze.fromByteString bs--fromAsciiBuilder :: AsciiBuilder -> Ascii-fromAsciiBuilder (AsciiBuilder b) = Ascii $ Blaze.toByteString b
− Data/Ascii/ByteString.hs
@@ -1,75 +0,0 @@-{-# LANGUAGE DeriveDataTypeable, GeneralizedNewtypeDeriving #-}--module Data.Ascii.ByteString where---- base-import Data.Data (Data)-import Data.Typeable (Typeable)-import Data.String (IsString (..))-import qualified Data.Char as C-import Data.Monoid (Monoid)-import Data.Semigroup (Semigroup)---- bytestring-import qualified Data.ByteString as S-import qualified Data.ByteString.Char8 as S8-import Data.ByteString (ByteString)---- case-insensitive-import Data.CaseInsensitive (FoldCase, CI, mk, original)---- hashable-import Data.Hashable (Hashable)---- text-import Data.Text (Text)-import qualified Data.Text as T-import qualified Data.Text.Encoding as TE--newtype Ascii = Ascii ByteString- deriving (Show, Eq, Read, Ord, Data, Typeable, IsString, FoldCase, Hashable, Semigroup, Monoid)--type CIAscii = CI Ascii--fromByteString :: ByteString -> Maybe Ascii-fromByteString bs- | S.all (< 128) bs = Just $ Ascii bs- | otherwise = Nothing---- | Renamed to avoid clash with 'fromString'-fromChars :: String -> Maybe Ascii-fromChars s- | all C.isAscii s = Just $ Ascii $ S8.pack s- | otherwise = Nothing--fromText :: Text -> Maybe Ascii-fromText t- | T.all C.isAscii t = Just $ Ascii $ TE.encodeUtf8 t- | otherwise = Nothing--unsafeFromByteString :: ByteString -> Ascii-unsafeFromByteString = Ascii--unsafeFromString :: String -> Ascii-unsafeFromString = Ascii . S8.pack--unsafeFromText :: Text -> Ascii-unsafeFromText = Ascii . TE.encodeUtf8--toCIAscii :: Ascii -> CIAscii-toCIAscii = mk--fromCIAscii :: CIAscii -> Ascii-fromCIAscii = original--toByteString :: Ascii -> ByteString-toByteString (Ascii bs) = bs--toString :: Ascii -> String-toString (Ascii bs) = S8.unpack bs--toText :: Ascii -> Text-toText (Ascii bs) = TE.decodeUtf8 bs--ciToByteString :: CIAscii -> ByteString-ciToByteString = toByteString . original
− Data/Ascii/Word8.hs
@@ -1,148 +0,0 @@-{-# LANGUAGE CPP #-}--module Data.Ascii.Word8 where---- base-import Data.Word (Word8)-import qualified Data.Char as C--fromChar :: Char -> Maybe Word8-fromChar c = if i < 128 then Just (fromIntegral i) else Nothing- where i = C.ord c--toChar :: Word8 -> Char-toChar = C.chr . fromIntegral---- | Unsafe version of 'fromChar'-ascii :: Char -> Word8-ascii = fromIntegral . C.ord-{-# INLINE ascii #-}--isAscii :: Word8 -> Bool-isAscii = (< 128)--isControl :: Word8 -> Bool-isControl w = w < 32 || w == 127--isPrintable :: Word8 -> Bool-isPrintable w = w >= 32 && w < 127--isWhiteSpace :: Word8 -> Bool-isWhiteSpace w = w == ascii ' ' || w >= 9 && w <= 13--isSpaceOrTab :: Word8 -> Bool-isSpaceOrTab w = w == ascii ' ' || w == ascii '\t'--isLower :: Word8 -> Bool-isLower w = w >= ascii 'a' && w <= ascii 'z'--isUpper :: Word8 -> Bool-isUpper w = w >= ascii 'A' && w <= ascii 'Z'--toLower :: Word8 -> Word8-toLower w | isUpper w = w + 32- | otherwise = w--toUpper :: Word8 -> Word8-toUpper w | isLower w = w - 32- | otherwise = w--isAlpha :: Word8 -> Bool-isAlpha w = isUpper w || isLower w--isDigit :: Word8 -> Bool-isDigit w = w >= ascii '0' && w <= ascii '9'--isAlphaNum :: Word8 -> Bool-isAlphaNum w = isDigit w || isAlpha w--fromDigit :: Num a => Word8 -> Maybe a-fromDigit w | isDigit w = Just $ unsafeFromDigit w- | otherwise = Nothing-#if __GLASGOW_HASKELL__ >= 700-{-# INLINABLE fromDigit #-}-#endif--unsafeFromDigit :: Num a => Word8 -> a-unsafeFromDigit w = fromIntegral (w - ascii '0')-{-# INLINE unsafeFromDigit #-}--isOctDigit :: Word8 -> Bool-isOctDigit w = w >= ascii '0' && w <= ascii '7'--fromOctDigit :: Num a => Word8 -> Maybe a-fromOctDigit w | isOctDigit w = Just $ unsafeFromOctDigit w- | otherwise = Nothing-#if __GLASGOW_HASKELL__ >= 700-{-# INLINABLE fromOctDigit #-}-#endif--unsafeFromOctDigit :: Num a => Word8 -> a-unsafeFromOctDigit = unsafeFromDigit-{-# INLINE unsafeFromOctDigit #-}--isLowAF :: Word8 -> Bool-isLowAF w = w >= ascii 'a' && w <= ascii 'f'-{-# INLINE isLowAF #-}--fromLowAF :: Num a => Word8 -> a-fromLowAF w = fromIntegral (w - ascii 'a' + 10)-{-# INLINE fromLowAF #-}--isLowHexDigit :: Word8 -> Bool-isLowHexDigit w = isDigit w || isLowAF w--fromLowHexDigit :: Num a => Word8 -> Maybe a-fromLowHexDigit w | isDigit w = Just $ unsafeFromDigit w- | isLowAF w = Just $ fromLowAF w- | otherwise = Nothing-#if __GLASGOW_HASKELL__ >= 700-{-# INLINABLE fromLowHexDigit #-}-#endif--unsafeFromLowHexDigit :: Num a => Word8 -> a-unsafeFromLowHexDigit w | w < ascii 'a' = unsafeFromDigit w- | otherwise = fromLowAF w-{-# INLINE unsafeFromLowHexDigit #-}--isUpAF :: Word8 -> Bool-isUpAF w = w >= ascii 'A' && w <= ascii 'F'-{-# INLINE isUpAF #-}--fromUpAF :: Num a => Word8 -> a-fromUpAF w = fromIntegral (w - ascii 'A' + 10)-{-# INLINE fromUpAF #-}--isUpHexDigit :: Word8 -> Bool-isUpHexDigit w = isDigit w || isUpAF w--fromUpHexDigit :: Num a => Word8 -> Maybe a-fromUpHexDigit w | isDigit w = Just $ unsafeFromDigit w- | isUpAF w = Just $ fromUpAF w- | otherwise = Nothing-#if __GLASGOW_HASKELL__ >= 700-{-# INLINABLE fromUpHexDigit #-}-#endif--unsafeFromUpHexDigit :: Num a => Word8 -> a-unsafeFromUpHexDigit w | w < ascii 'A' = unsafeFromDigit w- | otherwise = fromUpAF w-{-# INLINE unsafeFromUpHexDigit #-}--isHexDigit :: Word8 -> Bool-isHexDigit w = isDigit w || isUpAF w || isLowAF w--fromHexDigit :: Num a => Word8 -> Maybe a-fromHexDigit w | isDigit w = Just $ unsafeFromDigit w- | isUpAF w = Just $ fromUpAF w- | isLowAF w = Just $ fromLowAF w- | otherwise = Nothing-#if __GLASGOW_HASKELL__ >= 700-{-# INLINABLE fromHexDigit #-}-#endif--unsafeFromHexDigit :: Num a => Word8 -> a-unsafeFromHexDigit w | w < ascii 'A' = unsafeFromDigit w- | w < ascii 'a' = fromUpAF w- | otherwise = fromLowAF w-{-# INLINE unsafeFromHexDigit #-}
− LICENSE
@@ -1,30 +0,0 @@-Copyright Michael Snoyman 2011, Typeclass Consulting LLC 2018--All rights reserved.--Redistribution and use in source and binary forms, with or without-modification, are permitted provided that the following conditions are met:-- * Redistributions of source code must retain the above copyright- notice, this list of conditions and the following disclaimer.-- * Redistributions in binary form must reproduce the above- copyright notice, this list of conditions and the following- disclaimer in the documentation and/or other materials provided- with the distribution.-- * Neither the name of Michael Snoyman nor the names of other- contributors may be used to endorse or promote products derived- from this software without specific prior written permission.--THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS-"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT-LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR-A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT-OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,-SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT-LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,-DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY-THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE-OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
− Setup.hs
@@ -1,3 +0,0 @@-#!/usr/bin/env runhaskell-import Distribution.Simple-main = defaultMain
ascii.cabal view
@@ -1,40 +1,74 @@-Name: ascii-Version: 0.0.5.2-Synopsis: Type-safe, bytestring-based ASCII values-Description: Type-safe, bytestring-based ASCII values.-License: BSD3-License-file: LICENSE-Author: Michael Snoyman-Maintainer: Chris Martin, Julie Moronuki-Stability: Stable-Category: Data-Homepage: https://github.com/typeclasses/ascii-Bug-Reports: https://github.com/typeclasses/ascii/issues-Build-type: Simple-Cabal-version: >= 1.6-Tested-with: GHC == 8.4.3- , GHC == 8.2.2- , GHC == 7.10.3- , GHC == 7.8.4- , GHC == 7.6.3- , GHC == 7.4.2- , GHC == 7.2.2- , GHC == 7.0.4+cabal-version: 3.0 -Source-Repository head- Type: git- Location: git://github.com/typeclasses/ascii.git+name: ascii+version: 1.7.0.2+synopsis: The ASCII character set and encoding+category: Data, Text -Library- Exposed-modules: Data.Ascii- , Data.Ascii.Blaze- , Data.Ascii.ByteString- , Data.Ascii.Word8- Build-depends: base >= 4 && < 5- , bytestring >= 0.9 && < 0.11- , text >= 0.11 && < 1.3- , blaze-builder >= 0.2.1.4 && < 0.5- , case-insensitive >= 0.2 && < 1.3- , hashable >= 1.0 && < 1.3- , semigroups- Ghc-options: -Wall+description:+ This package provides a variety of ways to work with ASCII text.++license: Apache-2.0+license-file: license.txt++author: Chris Martin+maintainer: Chris Martin, Julie Moronuki++homepage: https://github.com/typeclasses/ascii+bug-reports: https://github.com/typeclasses/ascii/issues++extra-source-files: *.md++source-repository head+ type: git+ location: git://github.com/typeclasses/ascii.git++common base+ default-language: GHC2021+ ghc-options: -Wall+ default-extensions: NoImplicitPrelude+ build-depends:+ , ascii-caseless == 0.0.0.*+ , ascii-char == 1.0.1.*+ , ascii-group == 1.0.0.*+ , ascii-case == 1.0.1.*+ , ascii-numbers == 1.2.0.*+ , ascii-predicates == 1.0.1.*+ , ascii-superset == 1.3.0.*+ , ascii-th == 1.2.0.*+ , base ^>= 4.16 || ^>= 4.17 || ^>= 4.18 || ^>= 4.19+ , bytestring ^>= 0.11.4 || ^>= 0.12+ , text ^>= 1.2.5 || ^>= 2.0 || ^>= 2.1++library+ import: base+ hs-source-dirs: library+ exposed-modules: ASCII+ reexported-modules:+ , ASCII.Case+ , ASCII.Caseless+ , ASCII.CaseRefinement+ , ASCII.Char+ , ASCII.Decimal+ , ASCII.Group+ , ASCII.Hexadecimal+ , ASCII.Isomorphism+ , ASCII.Lists+ , ASCII.ListsAndPredicates+ , ASCII.Predicates+ , ASCII.QuasiQuoters+ , ASCII.Refinement+ , ASCII.Superset+ , ASCII.Superset.Text+ , ASCII.TemplateHaskell+ , ASCII.Word4++test-suite test-ascii+ import: base+ type: exitcode-stdio-1.0+ hs-source-dirs: test+ main-is: Main.hs+ default-extensions: OverloadedStrings QuasiQuotes+ build-depends:+ , ascii+ , hspec ^>= 2.9.7 || ^>= 2.10 || ^>= 2.11
+ changelog.md view
@@ -0,0 +1,305 @@+### 1.7.0.2 (2025-01-20)++Version bumps++### 1.7.0.1 (2023-06-26)++Upgrade language to GHC2021++### 1.7.0.0 (2023-03-01)++Rename `toAsciiCharMaybe` to `toCharMaybe`++Add `toCharListMaybe`++### 1.6.0.0 (2023-02-08)++Raise `ascii-superset` to `1.3`. This removes the `ASCII.Lift` module.++Raise `ascii-numbers` to `1.2`.++From the `ASCII` module, the `Lift` class and `lift` function are removed.++The removed `lift` function is replaced with the `lift` function from+`ASCII.Refinement`. If you were using `lift` specialized as+`ASCII a -> a`, then this is not a breaking change. Otherwise, migrate+by using one the new functions below.++```haskell+fromChar :: FromChar char => Char -> char+fromCharList :: FromString string => [Char] -> string+fromDigit :: DigitSuperset char => Digit -> char+fromDigitList :: DigitStringSuperset string => [Digit] -> string+fromHexChar :: HexCharSuperset char => HexChar -> char+fromHexCharList :: HexStringSuperset string => [HexChar] -> string++forgetCase :: ASCII'case letterCase superset -> ASCII superset+```++### 1.5.4.0 (2023-02-08)++Raise `ascii-superset` to `1.2.7`++Adds module `ASCII.Superset.Text`++Added to the `ASCII` module:++- Class `ToText`+- Functions `toStrictText`, `toLazyText`, `toUnicodeCharList`++### 1.5.3.0 (2023-02-07)++Raise `ascii-superset` to `1.2.6`++Added class `StringSupersetConversion` and the following function:++```haskell+convertRefinedString ::+ StringSupersetConversion a b => ASCII a -> ASCII b+```++### 1.5.2.0 (2023-01-25)++New functions: `asciiByteStringToText` and `asciiByteStringToTextLazy`++### 1.5.1.0 (2023-01-06)++Raise `ascii-superset` version to `1.2.5`. This adds a new instance:++```haskell+instance Lift (ASCII'case letterCase superset) (ASCII superset)+```++### 1.5.0.0 (2023-01-06)++Raise `ascii-th` version to `1.2.0`. This changes the constraints on `lower` and+`upper` quasi-quotations in an expression context. Previously, the constraint+was `FromString`. The constraints are now `ToCasefulString 'LowerCase` and+`ToCasefulString 'UpperCase` respectively. This expands the range of types+inhabited by lower/uppercase quotes to include `ASCII'lower` and `ASCII'upper`,+which were previously not able to be expressed using quasi-quotations.++### 1.4.2.0 (2023-01-05)++Raise `ascii-superset` version from `1.2.0` to `1.2.4`. This adds classes+`ToCasefulChar` and `ToCasefulString` to the `ASCII.Superset` module. It also+adds some instances for the various other superset classes.++### 1.4.1.1 (2023-01-05)++Change test suite from `hedgehog` to `hspec`++### 1.4.1.0 (2023-01-05)++Raise `ascii-char` version to `1.0.1`. This adds `Word8` conversions to the+`ASCII.Char` module.++### 1.4.0.0 (2023-01-03)++Additions to the `ASCII` module: `disregardCase`, `ASCII'case`, `ASCII'upper`,+`ASCII'lower`, `KnownCase (..)`, `refineCharToCase`, `refineStringToCase`++Update `ascii-superset` to `1.2.0`. This adds `CharSuperset (toCaseChar)`,+`StringSuperset (toCaseString)`, `refineCharToCase`, and `refineStringToCase`.++The constraint on `toCaseChar` is relaxed from `CharIso` to `CharSuperset`.+The constraint on `toCaseString` is relaxed from `StringIso` to `StringSuperset`.++### 1.3.1.0 (2023-01-03)++Update `ascii-th` to `1.1.1`.++This adds, most notably, to the `ASCII.QuasiQuoters` module.+The new quasi-quoters are `caseless`, `lower`, and `upper`.+These are also re-exported from the `ASCII` module.++### 1.3.0.0 (2023-01-03)++Update `ascii-superset` to `1.1.0`.++This adds several classes to the `ASCII.Superset` module: `ToChar`, `FromChar`,+`ToString`, `FromString`, `ToCaselessChar`, and `ToCaselessString`.++This is a breaking change because these are superclasses of the existing+`CharSuperset` and `StringSuperset` classes, and they take methods from them.++### 1.2.6.0 (2023-01-02)++Update `ascii-superset` to `1.0.2`. This adds the `ASCII.CaseRefinement` module.++### 1.2.5.0 (2023-01-02)++Add the `ASCII.Caseless` module (re-exported from the `ascii-caseless` package)++Additions to the `ASCII` module:++* `CaselessChar`++### 1.2.4.1 (2022-12-30)++Metadata changes only++### 1.2.4.0 (2022-12-23)++Bump version of `ascii-case` to `1.0.1`. This adds the following function to the+`ASCII.Case` module:++```haskell+opposite :: Case -> Case+```++### 1.2.3.0 (2022-05-04)++Add `isVisible :: Char -> Bool`. Visible characters include all print characters+other than `Space`.++### 1.2.2.0 (2022-04-29)++Add `type UnicodeChar = Data.Char.Char` type alias to `ASCII` module++### 1.2.1.0 (2022-04-29)++New polymorphic narrowing functions:++* `toAsciiCharMaybe :: CharSuperset char => char -> Maybe Char`+* `toDigitMaybe :: DigitSuperset char => char -> Maybe Digit`+* `toHexCharMaybe :: HexCharSuperset char => char -> Maybe HexChar`++New monomorphic character conversion functions:++* `digitToWord8 :: Digit -> Word8`+* `word8ToDigitMaybe :: Word8 -> Maybe Digit`+* `word8ToDigitUnsafe :: Word8 -> Digit`+* `digitToChar :: Digit -> Char`+* `charToDigitMaybe :: Char -> Maybe Digit`+* `charToDigitUnsafe :: Char -> Digit`+* `digitToUnicode :: Digit -> Unicode.Char`+* `unicodeToDigitMaybe :: Unicode.Char -> Maybe Digit`+* `unicodeToDigitUnsafe :: Unicode.Char -> Digit`+* `hexCharToWord8 :: HexChar -> Word8`+* `word8ToHexCharMaybe :: Word8 -> Maybe HexChar`+* `word8ToHexCharUnsafe :: Word8 -> HexChar`+* `hexCharToChar :: HexChar -> Char`+* `charToHexCharMaybe :: Char -> Maybe HexChar`+* `charToHexCharUnsafe :: Char -> HexChar`+* `hexCharToUnicode :: HexChar -> Unicode.Char`+* `unicodeToHexCharMaybe :: Unicode.Char -> Maybe HexChar`+* `unicodeToHexCharUnsafe :: Unicode.Char -> HexChar`++### 1.2.0.0 (2022-04-20)++Update to `ascii-numbers` version `1.1.0`. The major change is that there are+now `Lift` instances for `Digit` and `HexChar`.++### 1.1.3.0++Added functions `digitString` and `hexCharString`++### 1.1.2.0++Add dependency on `ascii-numbers`++New modules:++* `ASCII.Decimal`+* `ASCII.Hexadecimal`++New types:++* `Digit`+* `HexChar`++New classes:++* `DigitSuperset`+* `DigitStringSuperset`+* `HexCharSuperset`+* `HexStringSuperset`++New functions:++* `showIntegralDecimal`+* `showIntegralHexadecimal`+* `readIntegralDecimal`+* `readIntegralHexadecimal`++* `showNaturalDigits`+* `readNaturalDigits`+* `showNaturalHexChars`+* `readNaturalHexChars`++* `showNaturalDecimal`+* `showNaturalHexadecimal`+* `readNaturalDecimal`+* `readNaturalHexadecimal`++Dropped support for old versions:++* Drop support for `base` 4.11 (GHC 8.4)+* Drop support for `base` 4.12 (GHC 8.6)++### 1.1.1.4++Switch test-suite over to `hedgehog`++### 1.1.1.2++Support GHC 9.2++### 1.1.1.0++New functions:++ - `isAlphaNum`+ - `isLetter`+ - `isDigit`+ - `isOctDigit`+ - `isHexDigit`+ - `isSpace`+ - `isPunctuation`+ - `isSymbol`++### 1.1.0.0++The dependency on the 'data-ascii' package is removed, and the following modules+are no longer re-exported:++ - `Data.Ascii`+ - `Data.Ascii.Blaze`+ - `Data.Ascii.ByteString`+ - `Data.Ascii.Word8`++### 1.0.1.6++Add a test suite++Raise `text` lower bound to 1.2.3++### 1.0.1.4++Support GHC 9.0++### 1.0.1.2++Support `bytestring-0.11`++### 1.0.1.0++New functions:++ - `byteStringToUnicodeStringMaybe`+ - `unicodeStringToByteStringMaybe`+ - `byteListToUnicodeStringMaybe`+ - `unicodeStringToByteListMaybe`+ - `convertCharMaybe`+ - `convertCharOrFail`+ - `convertStringMaybe`+ - `convertStringOrFail`++### 1.0.0.2++Support GHC 8.10++### 1.0.0.0++Completely redesigned the library
+ library/ASCII.hs view
@@ -0,0 +1,872 @@+{-| The __American Standard Code for Information Interchange__ (ASCII) comprises+a set of 128 characters, each represented by 7 bits. 33 of these characters are+/'Control' codes/; a few of these are still in use, but most are obsolete relics+of the early days of computing. The other 95 are /'Printable' characters/ such+as letters and numbers, mostly corresponding to the keys on an American English+keyboard.++Nowadays instead of ASCII we typically work with text using an encoding such as+UTF-8 that can represent the entire Unicode character set, which includes over a+hundred thousand characters and is not limited to the symbols of any particular+writing system or culture. However, ASCII is still relevant to network+protocols; for example, we can see it in the specification of+<https://www.rfc-editor.org/rfc/rfc9110.html#name-syntax-notation HTTP>.++There is a convenient relationship between ASCII and Unicode: the ASCII+characters are the first 128 characters of the much larger Unicode character set.+The <https://www.unicode.org/charts/PDF/U0000.pdf C0 Controls and Basic Latin>+section of the Unicode standard contains a list of all the ASCII characters.+You may also find this list replicated in the "ASCII.Char" module; each ASCII+character corresponds to a constructor of the 'ASCII.Char' type.++We do not elaborate on the semantics of the control characters here,+because this information is both obsolete and restricted by copyright law.+It is described by a document entitled+/"Coded Character Sets - 7-Bit American National Standard Code for Information Interchange (7-Bit ASCII)"/,+published by American National Standards Institute (ANSI) and available for purchase+<https://webstore.ansi.org/Standards/INCITS/INCITS1986R2012 on their website>.+-}+module ASCII+ (+ {- * @Char@ -}++ {- ** ASCII -}+ {- $char -} Char,++ {- ** Unicode -}+ UnicodeChar,++ {- ** Case-insensitive -}+ {- $caselessChar -} CaselessChar,++ {- * Character classifications -}++ {- ** Print/control groups -}+ {- $groups -} Group (..), charGroup, inGroup,++ {- ** Upper/lower case -}+ {- $case -} Case (..), letterCase, isCase, toCaseChar, toCaseString,+ disregardCase, refineCharToCase, refineStringToCase,++ {- ** Letters -}+ isLetter,++ {- ** Letters and numbers -}+ isAlphaNum,++ {- ** Decimal digits -}+ {- $digit -} isDigit, Digit,++ {- ** Hexadecimal digits -}+ {- $hexchar -} isHexDigit, HexChar,++ {- ** Octal digits -}+ isOctDigit,++ {- ** Spaces and symbols -}+ isSpace, isPunctuation, isSymbol, isVisible,++ {- * Monomorphic character conversions -}++ {- $monomorphicConversions -}++ {- ** @ASCII.Char@ ↔ @Int@ -}+ {- $intConversions -}+ charToInt, intToCharMaybe, intToCharUnsafe,++ {- ** @ASCII.Char@ ↔ @Word8@ -}+ {- $word8Conversions -}+ charToWord8, word8ToCharMaybe, word8ToCharUnsafe,++ {- ** @ASCII.Char@ ↔ @UnicodeChar@ -}+ {- $unicodeCharConversions -}+ charToUnicode, unicodeToCharMaybe, unicodeToCharUnsafe,++ {- * Monomorphic digit conversions -}++ {- ** @Digit@ ↔ @Word8@ -}+ {- $digitWord8Conversions -}+ digitToWord8, word8ToDigitMaybe, word8ToDigitUnsafe,++ {- ** @Digit@ ↔ @ASCII.Char@ -}+ {- $digitCharConversions -}+ digitToChar, charToDigitMaybe, charToDigitUnsafe,++ {- ** @Digit@ ↔ @UnicodeChar@ -}+ {- $digitUnicodeConversions -}+ digitToUnicode, unicodeToDigitMaybe, unicodeToDigitUnsafe,++ {- ** @HexChar@ ↔ @Word8@ -}+ {- $hexCharWord8Conversions -}+ hexCharToWord8, word8ToHexCharMaybe, word8ToHexCharUnsafe,++ {- ** @HexChar@ ↔ @ASCII.Char@ -}+ {- $hexCharCharConversions -}+ hexCharToChar, charToHexCharMaybe, charToHexCharUnsafe,++ {- ** @HexChar@ ↔ @UnicodeChar@ -}+ {- $hexCharUnicodeConversions -}+ hexCharToUnicode, unicodeToHexCharMaybe, unicodeToHexCharUnsafe,++ {- * Monomorphic string conversions -}++ {- ** @ASCII.Char@ ↔ @String@ -}+ {- $unicodeStringConversions -}+ charListToUnicodeString, unicodeStringToCharListMaybe,+ unicodeStringToCharListUnsafe,++ {- ** @ASCII.Char@ ↔ @Text@ -}+ {- $textConversions -}+ charListToText, textToCharListMaybe, textToCharListUnsafe,++ {- ** @ASCII.Char@ ↔ @ByteString@ -}+ {- $byteStringConversions -}+ charListToByteString, byteStringToCharListMaybe,+ byteStringToCharListUnsafe,++ {- ** @ASCII ByteString@ -> @Text@ -}+ asciiByteStringToText, asciiByteStringToTextLazy,++ {- * Monomorphic conversions between ASCII supersets -}++ {- $monoSupersetConversions -}++ {- ** @ByteString@ ↔ @String@ -}+ byteStringToUnicodeStringMaybe, unicodeStringToByteStringMaybe,++ {- ** @[Word8]@ ↔ @String@ -}+ byteListToUnicodeStringMaybe, unicodeStringToByteListMaybe,++ {- * Monomorphic numeric string conversions -}++ {- ** @Natural@ ↔ @[Digit]@ -}+ showNaturalDigits, readNaturalDigits,++ {- ** @Natural@ ↔ @[HexChar]@ -}+ showNaturalHexChars, readNaturalHexChars,++ {- * Refinement types -}+ {- $refinement -} ASCII,+ ASCII'case, ASCII'upper, ASCII'lower, KnownCase (..),++ {- * Polymorphic conversions -}++ {- ** Narrowing -}+ toCharMaybe, toCharListMaybe, toDigitMaybe, toHexCharMaybe,++ {- ** Validate -}+ validateChar, validateString,++ {- ** Widening -}+ {- $lift -} lift,+ {- $toText -} toStrictText, toLazyText, toUnicodeCharList,+ {- $fromChar -} fromChar, fromCharList,+ {- $fromDigit -} fromDigit, fromDigitList,+ {- $fromHexChar -} fromHexChar, fromHexCharList,+ {- $forgetCase -} forgetCase,++ {- ** Convert -}+ {- $supersetConversions -}+ convertCharMaybe, convertCharOrFail, convertStringMaybe,+ convertStringOrFail, convertRefinedString,++ {- ** Integral strings -}+ {- $numbers -}+ showIntegralDecimal, showIntegralHexadecimal,+ readIntegralDecimal, readIntegralHexadecimal,++ {- ** Natural strings -}+ showNaturalDecimal, showNaturalHexadecimal,+ readNaturalDecimal, readNaturalHexadecimal,++ {- ** Single-digit strings -}+ digitString, hexCharString,++ {- * Classes -}++ {- ** Supersets of ASCII -}+ CharSuperset, StringSuperset,+ StringSupersetConversion, ToText,++ {- ** Equivalents to ASCII -}+ CharIso, StringIso,++ {- ** Supersets of numeric characters -}+ DigitSuperset, DigitStringSuperset, HexCharSuperset, HexStringSuperset,++ {- * Quasi-quoters -}+ char, string, caseless, lower, upper,+ )+ where++import ASCII.Case (Case (..))+import ASCII.CaseRefinement (KnownCase (..), ASCII'case, ASCII'upper, ASCII'lower, refineCharToCase, refineStringToCase, forgetCase)+import ASCII.Caseless (CaselessChar)+import ASCII.Char (Char)+import ASCII.Decimal (Digit, DigitStringSuperset, DigitSuperset, fromDigit, fromDigitList)+import ASCII.Group (Group (..))+import ASCII.Hexadecimal (HexChar, HexCharSuperset, HexStringSuperset, fromHexChar, fromHexCharList)+import ASCII.Isomorphism (CharIso, StringIso)+import ASCII.QuasiQuoters (char, string, caseless, lower, upper)+import ASCII.Refinement (ASCII, lift, validateChar, validateString)+import ASCII.Superset (CharSuperset, StringSuperset, toCharMaybe, toCharListMaybe, fromChar, fromCharList)+import ASCII.SupersetConversion (StringSupersetConversion)+import ASCII.Superset.Text (ToText (..))++import Control.Monad ((>=>))+import Control.Monad.Fail (MonadFail)+import Data.Bits (Bits)+import Data.Bool (Bool (..))+import Data.Foldable (any)+import Data.Function ((.))+import Data.Int (Int)+import Data.Maybe (Maybe, maybe)+import Data.Word (Word8)+import Numeric.Natural (Natural)+import Prelude (Integral)++import qualified ASCII.Case+import qualified ASCII.Caseless+import qualified ASCII.Decimal+import qualified ASCII.Group+import qualified ASCII.Hexadecimal+import qualified ASCII.Isomorphism+import qualified ASCII.Predicates+import qualified ASCII.Superset+import qualified ASCII.SupersetConversion as SupersetConversion++import qualified Data.ByteString as BS+import qualified Data.ByteString.Lazy as LBS+import qualified Data.Char as Unicode+import qualified Data.String as Unicode+import qualified Data.Text as Text+import qualified Data.Text.Encoding as Text+import qualified Data.Text.Lazy as LText+import qualified Data.Text.Lazy.Encoding as LText++{- $char++See also: "ASCII.Char" -}++{- $caselessChar++See also: "ASCII.Caseless" -}++{-| A character in the full range of Unicode++ASCII 'Char' is a subset of this type. Convert using 'charToUnicode' and+'unicodeToCharMaybe'. -}+type UnicodeChar = Unicode.Char++{- $groups++ASCII characters are broadly categorized into two groups: /control codes/ and+/printable characters/.++See also: "ASCII.Group" -}++{-| Determine which group a particular character belongs to++@+charGroup CapitalLetterA == Printable++charGroup EndOfTransmission == Control+@ -}+charGroup :: CharIso char => char -> Group+charGroup = ASCII.Group.charGroup . ASCII.Isomorphism.toChar++{-| Test whether a character belongs to a particular ASCII group++@+not (inGroup Printable EndOfTransmission)++inGroup Control EndOfTransmission++map (inGroup Printable) ([-1, 5, 65, 97, 127, 130] :: [Int])+ == [False, False, True, True, False, False]+@ -}+inGroup :: CharSuperset char => Group -> char -> Bool+inGroup g = maybe False (ASCII.Group.inGroup g) . ASCII.Superset.toCharMaybe++{- $case++/Case/ is a property of letters. /A-Z/ are /upper case/ letters, and /a-z/ are+/lower case/ letters. No other ASCII characters have case.++See also: "ASCII.Case" -}++{-| Determines whether a character is an ASCII letter, and if so, whether it is+ upper or lower case++@+map letterCase [SmallLetterA, CapitalLetterA, ExclamationMark]+ == [Just LowerCase, Just UpperCase, Nothing]++map letterCase ([string|Hey!|] :: [ASCII Word8])+ == [Just UpperCase, Just LowerCase, Just LowerCase, Nothing]+@ -}+letterCase :: CharSuperset char => char -> Maybe Case+letterCase = ASCII.Superset.toCharMaybe >=> ASCII.Case.letterCase++{-| Determines whether a character is an ASCII letter of a particular case++@+map (isCase UpperCase) [SmallLetterA, CapitalLetterA, ExclamationMark]+ == [False, True, False]++map (isCase UpperCase) ([string|Hey!|] :: [ASCII Word8])+ == [True, False, False, False]++map (isCase UpperCase) ([-1, 65, 97, 150] :: [Int])+ == [False, True, False, False]+@ -}+isCase :: CharSuperset char => Case -> char -> Bool+isCase c = maybe False (ASCII.Case.isCase c) . ASCII.Superset.toCharMaybe++{-| Maps a letter character to its upper/lower case equivalent++@+toCaseChar UpperCase SmallLetterA == CapitalLetterA++( [char|a|] :: ASCII Word8) == asciiUnsafe 97+(toCaseChar UpperCase [char|a|] :: ASCII Word8) == asciiUnsafe 65+@ -}+toCaseChar :: CharSuperset char => Case -> char -> char+toCaseChar = ASCII.Superset.toCaseChar++{-| Maps each of the characters in a string to its upper/lower case equivalent++@+toCaseString UpperCase [CapitalLetterH, SmallLetterE, SmallLetterY, ExclamationMark]+ == [CapitalLetterH, CapitalLetterE, CapitalLetterY, ExclamationMark]++(toCaseString UpperCase [string|Hey!|] :: ASCII Text) == asciiUnsafe "HEY!"+@ -}+toCaseString :: StringSuperset string => Case -> string -> string+toCaseString = ASCII.Superset.toCaseString++{-| Convert from ASCII character to caseless ASCII character, discarding the+ case if the character is a letter -}+disregardCase :: Char -> CaselessChar+disregardCase = ASCII.Caseless.disregardCase++{- $monomorphicConversions++These are a few simple monomorphic functions to convert between ASCII and types+representing some other character set.++This is not intended to be an exhaustive list of all possible conversions. For+more options, see "ASCII.Superset". -}++{- $intConversions++These functions convert between the ASCII 'Char' type and 'Int'. -}++{-|++@+map charToInt [Null, CapitalLetterA, SmallLetterA, Delete] == [0, 65, 97, 127]+@ -}+charToInt :: Char -> Int+charToInt = ASCII.Superset.fromChar++intToCharMaybe :: Int -> Maybe Char+intToCharMaybe = ASCII.Superset.toCharMaybe++intToCharUnsafe :: Int -> Char+intToCharUnsafe = ASCII.Superset.toCharUnsafe++{- $word8Conversions++These functions convert between the ASCII 'Char' type and 'Word8'. -}++{-|++@+map charToWord8 [Null, CapitalLetterA, SmallLetterA, Delete] == [0, 65, 97, 127]+@ -}+charToWord8 :: Char -> Word8+charToWord8 = ASCII.Superset.fromChar++word8ToCharMaybe :: Word8 -> Maybe Char+word8ToCharMaybe = ASCII.Superset.toCharMaybe++word8ToCharUnsafe :: Word8 -> Char+word8ToCharUnsafe = ASCII.Superset.toCharUnsafe++{- $unicodeCharConversions++These functions convert between the ASCII 'Char' type and the 'UnicodeChar'+type. -}++charToUnicode :: Char -> UnicodeChar+charToUnicode = ASCII.Superset.fromChar++unicodeToCharMaybe :: UnicodeChar -> Maybe Char+unicodeToCharMaybe = ASCII.Superset.toCharMaybe++unicodeToCharUnsafe :: UnicodeChar -> Char+unicodeToCharUnsafe = ASCII.Superset.toCharUnsafe++{- $digitWord8Conversions++These functions convert between the ASCII 'Digit' type and ASCII digits in their+byte encoding.++These conversions do /not/ correspond to the numeric interpretations of 'Digit'+and 'Word8'. For example, 'digitToWord8' 'ASCII.Decimal.Digit0' is 48, not 0. -}++digitToWord8 :: Digit -> Word8+digitToWord8 = ASCII.Decimal.fromDigit++word8ToDigitMaybe :: Word8 -> Maybe Digit+word8ToDigitMaybe = ASCII.Decimal.toDigitMaybe++word8ToDigitUnsafe :: Word8 -> Digit+word8ToDigitUnsafe = ASCII.Decimal.toDigitUnsafe++{- $digitCharConversions++These functions convert between the ASCII 'Digit' type and the ASCII 'Char'+type. -}++digitToChar :: Digit -> Char+digitToChar = ASCII.Decimal.fromDigit++charToDigitMaybe :: Char -> Maybe Digit+charToDigitMaybe = ASCII.Decimal.toDigitMaybe++charToDigitUnsafe :: Char -> Digit+charToDigitUnsafe = ASCII.Decimal.toDigitUnsafe++{- $digitUnicodeConversions++These functions convert between the ASCII 'Digit' type and the 'UnicodeChar'+type. -}++digitToUnicode :: Digit -> UnicodeChar+digitToUnicode = ASCII.Decimal.fromDigit++unicodeToDigitMaybe :: UnicodeChar -> Maybe Digit+unicodeToDigitMaybe = ASCII.Decimal.toDigitMaybe++unicodeToDigitUnsafe :: UnicodeChar -> Digit+unicodeToDigitUnsafe = ASCII.Decimal.toDigitUnsafe+++{- $hexCharWord8Conversions++These functions convert between the ASCII 'HexChar' type and ASCII characters in+their byte encoding.++These conversions do /not/ correspond to the numeric interpretations of+'HexChar' and 'Word8'. For example, 'hexCharToWord8'+'ASCII.Hexadecimal.CapitalLetterA' is 65, not 10. -}++hexCharToWord8 :: HexChar -> Word8+hexCharToWord8 = ASCII.Hexadecimal.fromHexChar++word8ToHexCharMaybe :: Word8 -> Maybe HexChar+word8ToHexCharMaybe = ASCII.Hexadecimal.toHexCharMaybe++word8ToHexCharUnsafe :: Word8 -> HexChar+word8ToHexCharUnsafe = ASCII.Hexadecimal.toHexCharUnsafe++{- $hexCharCharConversions++These functions convert between the ASCII 'HexChar' type and the ASCII 'Char'+type. -}++hexCharToChar :: HexChar -> Char+hexCharToChar = ASCII.Hexadecimal.fromHexChar++charToHexCharMaybe :: Char -> Maybe HexChar+charToHexCharMaybe = ASCII.Hexadecimal.toHexCharMaybe++charToHexCharUnsafe :: Char -> HexChar+charToHexCharUnsafe = ASCII.Hexadecimal.toHexCharUnsafe++{- $hexCharUnicodeConversions++These functions convert between the ASCII 'HexChar' type and the 'UnicodeChar'+type. -}++hexCharToUnicode :: HexChar -> UnicodeChar+hexCharToUnicode = ASCII.Hexadecimal.fromHexChar++unicodeToHexCharMaybe :: UnicodeChar -> Maybe HexChar+unicodeToHexCharMaybe = ASCII.Hexadecimal.toHexCharMaybe++unicodeToHexCharUnsafe :: UnicodeChar -> HexChar+unicodeToHexCharUnsafe = ASCII.Hexadecimal.toHexCharUnsafe++{- $unicodeStringConversions++These functions convert between @['Char']@ (a list of ASCII characters) and+'Unicode.String' (a list of Unicode characters). -}++charListToUnicodeString :: [Char] -> Unicode.String+charListToUnicodeString = ASCII.Superset.fromCharList++unicodeStringToCharListMaybe :: Unicode.String -> Maybe [Char]+unicodeStringToCharListMaybe = ASCII.Superset.toCharListMaybe++unicodeStringToCharListUnsafe :: Unicode.String -> [Char]+unicodeStringToCharListUnsafe = ASCII.Superset.toCharListUnsafe++{- $textConversions++These functions convert between @['Char']@ and 'Text.Text'. -}++{-|++@+charListToText [CapitalLetterH, SmallLetterI, ExclamationMark] == "Hi!"+@ -}+charListToText :: [Char] -> Text.Text+charListToText = ASCII.Superset.fromCharList++textToCharListMaybe :: Text.Text -> Maybe [Char]+textToCharListMaybe = ASCII.Superset.toCharListMaybe++textToCharListUnsafe :: Text.Text -> [Char]+textToCharListUnsafe = ASCII.Superset.toCharListUnsafe++{- $byteStringConversions++These functions convert between @['Char']@ and 'BS.ByteString'. -}++charListToByteString :: [Char] -> BS.ByteString+charListToByteString = ASCII.Superset.fromCharList++byteStringToCharListMaybe :: BS.ByteString -> Maybe [Char]+byteStringToCharListMaybe = ASCII.Superset.toCharListMaybe++byteStringToCharListUnsafe :: BS.ByteString -> [Char]+byteStringToCharListUnsafe = ASCII.Superset.toCharListUnsafe++asciiByteStringToText :: ASCII BS.ByteString -> Text.Text+asciiByteStringToText = Text.decodeUtf8 . ASCII.Refinement.lift++asciiByteStringToTextLazy :: ASCII LBS.ByteString -> LText.Text+asciiByteStringToTextLazy = LText.decodeUtf8 . ASCII.Refinement.lift++{- $refinement++See also: "ASCII.Refinement", "ASCII.CaseRefinement" -}++{- $lift++See also: "ASCII.Refinement" -}++{- $toText++See also: "ASCII.Superset.ToText" -}++{- $fromChar++See also: "ASCII.Superset" -}++{- $fromDigit++See also: "ASCII.Decimal" -}++{- $fromHexChar++See also: "ASCII.Hexadecimal" -}++{- $forgetCase++See also: "ASCII.CaseRefinement" -}++{- $supersetConversions++These functions all convert from one ASCII-superset type to another, failing if+any of the characters in the input is outside the ASCII character set. -}++convertCharMaybe :: (CharSuperset char1, CharSuperset char2) => char1 -> Maybe char2+convertCharMaybe = ASCII.Superset.convertCharMaybe++convertCharOrFail :: (CharSuperset char1, CharSuperset char2, MonadFail context) => char1 -> context char2+convertCharOrFail = ASCII.Superset.convertCharOrFail++convertStringMaybe :: (StringSuperset string1, StringSuperset string2) => string1 -> Maybe string2+convertStringMaybe = ASCII.Superset.convertStringMaybe++convertStringOrFail :: (StringSuperset string1, StringSuperset string2, MonadFail context) => string1 -> context string2+convertStringOrFail = ASCII.Superset.convertStringOrFail++{- $monoSupersetConversions++These functions are all specializations of 'convertStringMaybe'.+They convert a string from one ASCII-superset type to another.++@+ASCII.byteListToUnicodeStringMaybe [0x48, 0x54, 0x54, 0x50] == Just \"HTTP"+@++If any of the characters in the input is outside the ASCII character set, the+result is 'Nothing'.++@+ASCII.byteListToUnicodeStringMaybe [0x48, 0x54, 0x54, 0x80] == Nothing+@ -}+byteStringToUnicodeStringMaybe :: BS.ByteString -> Maybe Unicode.String+byteStringToUnicodeStringMaybe = convertStringMaybe++unicodeStringToByteStringMaybe :: Unicode.String -> Maybe BS.ByteString+unicodeStringToByteStringMaybe = convertStringMaybe++byteListToUnicodeStringMaybe :: [Word8] -> Maybe Unicode.String+byteListToUnicodeStringMaybe = convertStringMaybe++unicodeStringToByteListMaybe :: Unicode.String -> Maybe [Word8]+unicodeStringToByteListMaybe = convertStringMaybe++{-| Returns True for ASCII letters:++- 'ASCII.Char.SmallLetterA' to 'ASCII.Char.SmallLetterZ'+- 'ASCII.Char.CapitalLetterA' to 'ASCII.Char.CapitalLetterZ' -}+isLetter :: CharSuperset char => char -> Bool+isLetter x = any ASCII.Predicates.isLetter (convertCharMaybe x)++{-| Returns True for the characters from 'ASCII.Char.Digit0' to+'ASCII.Char.Digit9'. -}+isDigit :: CharSuperset char => char -> Bool+isDigit x = any ASCII.Predicates.isDigit (convertCharMaybe x)++{-| Returns True for the characters from 'ASCII.Char.Digit0' to+'ASCII.Char.Digit7'. -}+isOctDigit :: CharSuperset char => char -> Bool+isOctDigit x = any ASCII.Predicates.isOctDigit (convertCharMaybe x)++{-| Returns True for characters in any of the following ranges:++- 'ASCII.Char.Digit0' to 'ASCII.Char.Digit9'+- 'ASCII.Char.CapitalLetterA' to 'ASCII.Char.CapitalLetterF'+- 'ASCII.Char.SmallLetterA' to 'ASCII.Char.SmallLetterF' -}+isHexDigit :: CharSuperset char => char -> Bool+isHexDigit x = any ASCII.Predicates.isHexDigit (convertCharMaybe x)++{-| Returns True for the following characters:++- 'ASCII.Char.Space'+- 'ASCII.Char.HorizontalTab'+- 'ASCII.Char.LineFeed'+- 'ASCII.Char.VerticalTab'+- 'ASCII.Char.FormFeed'+- 'ASCII.Char.CarriageReturn' -}+isSpace :: CharSuperset char => char -> Bool+isSpace x = any ASCII.Predicates.isSpace (convertCharMaybe x)++{-| Returns True if the character is either an ASCII letter ('isLetter') or an+ASCII digit ('isDigit'). -}+isAlphaNum :: CharSuperset char => char -> Bool+isAlphaNum x = any ASCII.Predicates.isAlphaNum (convertCharMaybe x)++{-| Returns True for the following characters:++- 'ASCII.Char.ExclamationMark'+- 'ASCII.Char.QuotationMark'+- 'ASCII.Char.NumberSign'+- 'ASCII.Char.PercentSign'+- 'ASCII.Char.Ampersand'+- 'ASCII.Char.Apostrophe'+- 'ASCII.Char.LeftParenthesis'+- 'ASCII.Char.RightParenthesis'+- 'ASCII.Char.Asterisk'+- 'ASCII.Char.Comma'+- 'ASCII.Char.HyphenMinus'+- 'ASCII.Char.FullStop'+- 'ASCII.Char.Slash'+- 'ASCII.Char.Colon'+- 'ASCII.Char.Semicolon'+- 'ASCII.Char.QuestionMark'+- 'ASCII.Char.AtSign'+- 'ASCII.Char.LeftSquareBracket'+- 'ASCII.Char.Backslash'+- 'ASCII.Char.RightSquareBracket'+- 'ASCII.Char.Underscore'+- 'ASCII.Char.LeftCurlyBracket'+- 'ASCII.Char.RightCurlyBracket' -}+isPunctuation :: CharSuperset char => char -> Bool+isPunctuation x = any ASCII.Predicates.isPunctuation (convertCharMaybe x)++{-| Returns True for the following characters:++- 'ASCII.Char.DollarSign'+- 'ASCII.Char.PlusSign'+- 'ASCII.Char.LessThanSign'+- 'ASCII.Char.EqualsSign'+- 'ASCII.Char.GreaterThanSign'+- 'ASCII.Char.Caret'+- 'ASCII.Char.GraveAccent'+- 'ASCII.Char.VerticalLine'+- 'ASCII.Char.Tilde' -}+isSymbol :: CharSuperset char => char -> Bool+isSymbol x = any ASCII.Predicates.isSymbol (convertCharMaybe x)++{- |Returns True for visible characters++This includes all print characters except 'ASCII.Char.Space'. -}+isVisible :: CharSuperset char => char -> Bool+isVisible x = any ASCII.Predicates.isVisible (convertCharMaybe x)++{- $numbers++See also: "ASCII.Decimal" and "ASCII.Hexadecimal" -}++{-| Gives the ASCII string representation of an integer in decimal (base 10)+ notation, using digits 'ASCII.Char.Digit0' through 'ASCII.Char.Digit9',+ leading with 'ASCII.Char.HyphenMinus' for negative numbers++For example, @'showIntegralDecimal' (-512 :: 'Prelude.Integer')@ = @"-512"@. -}+showIntegralDecimal :: (Integral n, StringSuperset string) => n -> string+showIntegralDecimal = ASCII.Decimal.showIntegral++{-| Gives the ASCII string representation of an integer in hexadecimal (base 16)+ notation++The characters 'ASCII.Char.Digit0' through 'ASCII.Char.Digit9' represent digits+0 though 9. The representation of digits 10 to 15 is determined by the value of+'Case' parameter: 'UpperCase' means 'ASCII.Char.CapitalLetterA' to+'ASCII.Char.CapitalLetterF', and 'LowerCase' means 'ASCII.Char.SmallLetterA' to+'ASCII.Char.SmallLetterF'. For negative numbers, the resulting string begins+with 'ASCII.Char.HyphenMinus'.++@+'showIntegralHexadecimal' 'UpperCase' ('Prelude.negate' (256 + 12) :: 'Prelude.Integer') == "-10C"+@ -}+showIntegralHexadecimal :: (Integral n, StringSuperset string) =>+ Case -> n -> string+showIntegralHexadecimal = ASCII.Hexadecimal.showIntegral++{-| Roughly the inverse of 'showIntegralDecimal'++* Leading zeroes are accepted, as in @"0074"@ and @"-0074"@++Conditions where the result is 'Data.Maybe.Nothing':++* If the input is empty+* If the input contains any other extraneous characters+* If the resulting number would be outside the range supported by the 'Integral'+ (determined by its 'Bits' instance) -}+readIntegralDecimal :: (StringSuperset string, Integral number, Bits number) =>+ string -> Maybe number+readIntegralDecimal = ASCII.Decimal.readIntegral++{-| Roughly the inverse of 'showIntegralHexadecimal'++* Upper and lower case letters are treated equally+* Leading zeroes are accepted, as in @"006a"@ and @"-006a"@++Conditions where the result is 'Data.Maybe.Nothing':++* If the input is empty+* If the input contains any other extraneous characters+* If the resulting number would be outside the range supported by the 'Integral'+ (determined by its 'Bits' instance) -}+readIntegralHexadecimal :: (StringSuperset string, Integral number, Bits number) =>+ string -> Maybe number+readIntegralHexadecimal = ASCII.Hexadecimal.readIntegral++{-| Gives the ASCII string representation of an natural number in decimal+ (base 10) notation, using digits 'ASCII.Char.Digit0' through 'ASCII.Char.Digit9'++@+'showNaturalDecimal' 512 == @"512"+@ -}+showNaturalDecimal :: DigitStringSuperset string => Natural -> string+showNaturalDecimal = ASCII.Decimal.showNatural++{-| Gives the ASCII string representation of an integer in hexadecimal (base 16)+ notation++Characters 'ASCII.Char.Digit0' through 'ASCII.Char.Digit9' represent digits 0+though 9. The representation of digits 10 to 15 is determined by the value of+'Case' parameter: 'UpperCase' means 'ASCII.Char.CapitalLetterA' to+'ASCII.Char.CapitalLetterF', and 'LowerCase' means 'ASCII.Char.SmallLetterA' to+'ASCII.Char.SmallLetterF'.++@+'showNaturalHexadecimal' 'UpperCase' (256 + 12) == "10C"+@ -}+showNaturalHexadecimal :: HexStringSuperset string => Case -> Natural -> string+showNaturalHexadecimal = ASCII.Hexadecimal.showNatural++{-| Roughly the inverse of 'showNaturalDecimal'++* Leading zeroes are accepted, as in @"0074"@++Conditions where the result is 'Data.Maybe.Nothing':++* If the input is empty+* If the input contains any other extraneous characters -}+readNaturalDecimal :: DigitStringSuperset string => string -> Maybe Natural+readNaturalDecimal = ASCII.Decimal.readNatural++{-| Roughly the inverse of 'showNaturalHexadecimal'++* Upper and lower case letters are treated equally+* Leading zeroes are accepted, as in @"006a"@++Conditions where the result is 'Data.Maybe.Nothing':++* If the input is empty+* If the input contains any other extraneous characters -}+readNaturalHexadecimal :: HexStringSuperset string => string -> Maybe Natural+readNaturalHexadecimal = ASCII.Hexadecimal.readNatural++{- $digit++See also: "ASCII.Decimal" -}++{- $hexchar++See also: "ASCII.Hexadecimal" -}++{-| Specialization of 'showNaturalDecimal'++See also: 'showIntegralDecimal' -}+showNaturalDigits :: Natural -> [Digit]+showNaturalDigits = showNaturalDecimal++{-| Specialization of 'readNaturalDecimal'++See also: 'readIntegralDecimal' -}+readNaturalDigits :: [Digit] -> Maybe Natural+readNaturalDigits = readNaturalDecimal++{-| Specialization of 'showNaturalHexadecimal'++See also: 'showIntegralHexadecimal' -}++showNaturalHexChars :: Case -> Natural -> [HexChar]+showNaturalHexChars = showNaturalHexadecimal++{-| Specialization of 'readNaturalHexadecimal'++See also: 'readIntegralHexadecimal' -}+readNaturalHexChars :: [HexChar] -> Maybe Natural+readNaturalHexChars = readNaturalHexadecimal++{-| A string containing a single digit character 0-9 -}+digitString :: DigitStringSuperset string => Digit -> string+digitString x = ASCII.Decimal.fromDigitList [x]++{-| A string containing a single hexadecimal digit character+ 0-9, A-F, or a-f -}+hexCharString :: HexStringSuperset string => HexChar -> string+hexCharString x = ASCII.Hexadecimal.fromHexCharList [x]++toDigitMaybe :: DigitSuperset char => char -> Maybe Digit+toDigitMaybe = ASCII.Decimal.toDigitMaybe++toHexCharMaybe :: HexCharSuperset char => char -> Maybe HexChar+toHexCharMaybe = ASCII.Hexadecimal.toHexCharMaybe++{-| For example, this function can convert @ASCII ByteString@+ to @ASCII Text@ and vice versa -}+convertRefinedString ::+ StringSupersetConversion a b => ASCII a -> ASCII b+convertRefinedString = SupersetConversion.convertRefinedString
+ license.txt view
@@ -0,0 +1,13 @@+Copyright 2021 Mission Valley Software LLC++Licensed under the Apache License, Version 2.0 (the "License");+you may not use this file except in compliance with the License.+You may obtain a copy of the License at++ http://www.apache.org/licenses/LICENSE-2.0++Unless required by applicable law or agreed to in writing, software+distributed under the License is distributed on an "AS IS" BASIS,+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.+See the License for the specific language governing permissions and+limitations under the License.
+ readme.md view
@@ -0,0 +1,69 @@+## What is ASCII?++The *American Standard Code for Information Interchange* (ASCII) comprises a set+of 128 characters, each represented by 7 bits. 33 of these characters are+"control codes"; a few of these are still in use, but most are obsolete relics+of the early days of computing. The other 95 are "printable characters" such as+letters and numbers, mostly corresponding to the keys on an American English+keyboard.++Nowadays instead of ASCII we typically work with text using an encoding such as+UTF-8 that can represent the entire Unicode character set, which includes over a+hundred thousand characters and is not limited to the symbols of any particular+writing system or culture. However, ASCII is still relevant to network+protocols; for example, we can see it in the specification of [HTTP].++There is a convenient relationship between ASCII and Unicode: the ASCII+characters are the first 128 characters of the much larger Unicode character+set. The [C0 Controls and Basic Latin][unicode] section of the Unicode standard+contains a list of all the ASCII characters.++## Haskell packages++This repository contains the main API, the [`ASCII`][ascii] module in the+`ascii` package, which is an amalgamation of smaller packages in other+repositories.++ * If you only need the ASCII [`Char`][char] type, you can use the+ `ascii-char` package, which is minimal so that it can be kept stable.++ * The `ascii-group` package defines the [`Group`][group] type (`Control` and+ `Printable`), and the `ascii-case` package defines the [`Case`][case] type+ (`UpperCase` and `LowerCase`). These package are also small and stable.++ * The `ascii-predicates` package provides [additional ways of categorizing+ characters][predicates] similar to what you can find in [the `base`+ package][base].++ * For case-insensitivity, use the `ascii-caseless` package.++ * The `ascii-superset` package defines [`CharSuperset` and+ `StringSuperset`][superset] classes to generalize types that represent+ characters and strings, respectively, in character sets larger than ASCII.+ It also defines the [`ASCII`][refinement] type constructor, which is used+ to indicate that a value from some ASCII superset is confined to ASCII.++ * The `ascii-numbers` package provides utilities for working with numbers+ represented using ASCII digits 0-9, ASCII letters A-F to represent+ hexadecimal digits 10-15, and the `HyphenMinus` character for negation.++ * The `ascii-th` package provides a [quasi-quoter][qq] that allows one to+ safely and conveniently express ASCII string literals. The generated+ expressions are polymorphic and can take the form of any type belonging to+ the `StringSuperset` class, including `[ASCII.Char]`, [`String`][string],+ [`ByteString`][bytestring], and [`Text`][text].++ [HTTP]: https://www.rfc-editor.org/rfc/rfc9110.html#name-syntax-notation+ [unicode]: https://www.unicode.org/charts/PDF/U0000.pdf+ [ascii]: https://hackage.haskell.org/package/ascii/docs/ASCII.html+ [char]: https://hackage.haskell.org/package/ascii-char/docs/ASCII-Char.html+ [group]: https://hackage.haskell.org/package/ascii-group/docs/ASCII-Group.html+ [case]: https://hackage.haskell.org/package/ascii-case/docs/ASCII-Case.html+ [predicates]: https://hackage.haskell.org/package/ascii-predicates/docs/ASCII-ListsAndPredicates.html+ [base]: https://hackage.haskell.org/package/base/docs/Data-Char.html+ [superset]: https://hackage.haskell.org/package/ascii-superset/docs/ASCII-Superset.html+ [refinement]: https://hackage.haskell.org/package/ascii-superset/docs/ASCII-Refinement.html+ [qq]: https://hackage.haskell.org/package/ascii-th/docs/ASCII-QuasiQuoters.html+ [string]: https://hackage.haskell.org/package/base/docs/Data-String.html+ [bytestring]: https://hackage.haskell.org/package/bytestring+ [text]: https://hackage.haskell.org/package/text
+ test/Main.hs view
@@ -0,0 +1,148 @@+module Main (main) where++import ASCII++import ASCII.Char (Char (..))+import ASCII.Refinement (asciiUnsafe)++import Data.Bool (Bool (..))+import Data.Function (($))+import Data.Int (Int)+import Data.List (map)+import Data.Maybe (Maybe (..))+import Data.Text (Text)+import Data.Word (Word8)+import Prelude (enumFromTo, maxBound, minBound)+import System.IO (IO)++import Test.Hspec (describe, hspec, it, shouldBe)++main :: IO ()+main = hspec $ do++ describe "charGroup" $ do+ let c ~> g = charGroup c `shouldBe` g++ it "A is printable" $ CapitalLetterA ~> Printable+ it "end-of-transmission is control" $ EndOfTransmission ~> Control++ describe "inGroup" $ do++ describe "tests Char" $ do+ it "end-of-transmission is not printable" $+ inGroup Printable EndOfTransmission `shouldBe` False+ it "end-of-transmission is control" $+ inGroup Control EndOfTransmission `shouldBe` True++ describe "tests Int" $ do+ let i ~> b = inGroup Printable (i :: Int) `shouldBe` b++ it "-1 is not printable (isn't anything)" $ (-1) ~> False+ it "5 is not printable" $ 5 ~> False+ it "65 is printable" $ 65 ~> True+ it "97 is printable" $ 97 ~> True+ it "127 is not printable" $ 127 ~> False+ it "128 is not printable (isn't anything)" $ 128 ~> False++ describe "letterCase" $ do+ let ch ~> ca = letterCase ch `shouldBe` ca++ describe "works with Char" $ do+ it "a is lower" $ SmallLetterA ~> Just LowerCase+ it "A is upper" $ CapitalLetterA ~> Just UpperCase+ it "! has no case" $ ExclamationMark ~> Nothing++ it "works with ASCII Word8" $ do+ map letterCase ([string|Hey!|] :: [ASCII Word8]) `shouldBe`+ [Just UpperCase, Just LowerCase, Just LowerCase, Nothing]++ describe "isCase" $ do++ describe "works with Char" $ do+ let c ~> b = isCase UpperCase c `shouldBe` b++ it "a is not upper" $ SmallLetterA ~> False+ it "A is upper" $ CapitalLetterA ~> True+ it "! is not upper" $ ExclamationMark ~> False++ it "works with ASCII Word8" $ do+ map (isCase UpperCase) ([string|Hey!|] :: [ASCII Word8])+ `shouldBe` [True, False, False, False]++ describe "works with Int" $ do+ let i ~> b = isCase UpperCase (i :: Int) `shouldBe` b++ it "-1 is not upper (isn't anything)" $ (-1) ~> False+ it "65 is upper" $ 65 ~> True+ it "97 is not upper" $ 97 ~> False+ it "128 is not upper (isn't anything)" $ 128 ~> False++ describe "toCaseChar" $ do++ describe "works with Char" $ do+ it "a to upper is A" $ toCaseChar UpperCase SmallLetterA+ `shouldBe` CapitalLetterA++ describe "works with ASCII Word8" $ do+ it "a to upper is 65" $ toCaseChar UpperCase ([char|a|] :: ASCII Word8)+ `shouldBe` (asciiUnsafe 65 :: ASCII Word8)++ describe "toCaseString" $ do+ it "converts each Char to a case" $ do+ let check a b = toCaseString UpperCase a `shouldBe` b+ check [ CapitalLetterH, SmallLetterE, SmallLetterY, ExclamationMark ]+ [ CapitalLetterH, CapitalLetterE, CapitalLetterY, ExclamationMark ]++ it "works with ASCII Text" $+ (toCaseString UpperCase [string|Hey!|] :: ASCII Text)+ `shouldBe` asciiUnsafe "HEY!"++ describe "charToInt" $ do+ let c ~> i = charToInt c `shouldBe` i++ it "Null is 0" $ Null ~> 0+ it "A is 65" $ CapitalLetterA ~> 65+ it "a is 97" $ SmallLetterA ~> 97+ it "Delete is 127" $ Delete ~> 127++ describe "charToWord8" $ do+ let c ~> i = charToWord8 c `shouldBe` i++ it "Null is 0" $ Null ~> 0+ it "A is 65" $ CapitalLetterA ~> 65+ it "a is 97" $ SmallLetterA ~> 97+ it "Delete is 127" $ Delete ~> 127++ describe "charListToText" $ do+ it "packs a list of Char into Text" $+ charListToText [CapitalLetterH, SmallLetterI, ExclamationMark]+ `shouldBe` "Hi!"++ describe "fromChar" $ do+ it "converts Char to Word8" $ (fromChar CapitalLetterA :: Word8) `shouldBe` 65++ describe "fromCharList" $ do+ it "converts [Char] to Text" $+ (fromCharList [CapitalLetterH, SmallLetterI, ExclamationMark] :: Text)+ `shouldBe` "Hi!"++ describe "byteListToUnicodeStringMaybe" $ do+ it "converts [Word8] to String" $+ ASCII.byteListToUnicodeStringMaybe [0x48, 0x54, 0x54, 0x50]+ `shouldBe` Just "HTTP"+ it "can fail" $ ASCII.byteListToUnicodeStringMaybe [0x48, 0x54, 0x54, 0x80]+ `shouldBe` Nothing++ describe "digitString" $ do+ it "converts Digit to a single character of Text" $ do+ let f = digitString :: Digit -> Text+ map f (enumFromTo minBound maxBound) `shouldBe`+ ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9"]++ describe "hexCharString" $ do+ it "converts HexChar to a single character of Text" $ do+ let f = hexCharString :: HexChar -> Text+ map f (enumFromTo minBound maxBound) `shouldBe`+ [ "0", "1", "2", "3", "4", "5", "6", "7", "8", "9"+ , "A", "B", "C", "D", "E", "F"+ , "a", "b", "c", "d", "e", "f" ]