ascii-numbers (empty) → 1.0.0.0
raw patch · 6 files changed
+1795/−0 lines, 6 filesdep +ascii-casedep +ascii-chardep +ascii-numbers
Dependencies added: ascii-case, ascii-char, ascii-numbers, ascii-superset, base, bytestring, d10, hashable, hedgehog, invert, text
Files
- ascii-numbers.cabal +78/−0
- library/ASCII/Decimal.hs +346/−0
- library/ASCII/Hexadecimal.hs +559/−0
- library/DList.hs +21/−0
- license.txt +13/−0
- test/Main.hs +778/−0
+ ascii-numbers.cabal view
@@ -0,0 +1,78 @@+cabal-version: 3.0++name: ascii-numbers+version: 1.0.0.0+synopsis: ASCII representations of numbers+category: Data, Numeric, Text++description:+ This package provides functions for converting back and+ forth between numbers and their ASCII representations.++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++build-type: Simple++source-repository head+ type: git+ location: git://github.com/typeclasses/ascii.git++common base+ default-language: Haskell2010+ ghc-options: -Wall++ default-extensions:+ DeriveAnyClass+ DeriveDataTypeable+ DeriveGeneric+ DerivingStrategies+ FlexibleInstances+ LambdaCase+ NoImplicitPrelude+ StandaloneDeriving++ build-depends:+ ascii-case ^>= 1.0+ , ascii-char ^>= 1.0+ , ascii-superset ^>= 1.0.1+ , base >= 4.13 && < 4.17+ , bytestring ^>= 0.10 || ^>= 0.11+ , d10 ^>= 1.0.1+ , hashable >= 1.3 && < 1.5+ , text ^>= 1.2.4++library+ import: base+ hs-source-dirs: library++ exposed-modules:+ ASCII.Decimal+ , ASCII.Hexadecimal++ other-modules:+ DList++test-suite test-ascii-numbers+ import: base+ type: exitcode-stdio-1.0+ hs-source-dirs: test+ main-is: Main.hs++ build-depends:+ ascii-numbers+ , hedgehog ^>= 1.0.1 || ^>= 1.1+ , invert ^>= 1.0++ default-extensions:+ OverloadedStrings+ QuasiQuotes+ ScopedTypeVariables+ TemplateHaskell+ TypeApplications
+ library/ASCII/Decimal.hs view
@@ -0,0 +1,346 @@+module ASCII.Decimal+ (+ {- * Read/show for numeric strings -}+ {- ** Natural -} showNatural, readNatural,+ {- ** Integer -} showInteger, readInteger,+ {- ** Integral -} showIntegral, readIntegral,++ {- * The digit type -} D10 (..),++ {- * Decimal digit superset classes -}+ {- ** Of digit -} DigitSuperset (..),+ {- ** Of digit lists -} DigitStringSuperset (..),++ {- * Character/number conversions -}+ {- ** Natural -} naturalDigitMaybe, digitNatural,+ {- ** Integer -} integerDigitMaybe, digitInteger++ ) where++import qualified ASCII.Char as ASCII+import ASCII.Refinement (ASCII, asciiUnsafe, lift)+import ASCII.Superset (StringSuperset, fromChar, fromCharList, toCharListMaybe,+ toCharMaybe)++import Control.Monad ((<=<), (=<<))+import Data.Bifoldable (bifoldMap)+import Data.Bits (Bits, toIntegralSized)+import Data.Bool (Bool, (&&))+import Data.Function (id, (.))+import Data.Functor (fmap)+import Data.List.NonEmpty (NonEmpty, nonEmpty)+import Data.Maybe (Maybe (..), fromJust, isJust)+import Data.Monoid (mempty)+import Data.Ord (Ord (..))+import Data.Word (Word8)+import Numeric.Natural (Natural)+import Prelude (Integer, Integral, abs, fromEnum, fromInteger, fromIntegral,+ negate, quotRem, toEnum, toInteger, (*), (+), (-))++import qualified Data.Bool as Bool+import qualified Data.Char as Unicode+import qualified Data.List as List++import qualified Data.ByteString as BS+import qualified Data.ByteString.Builder as BSB+import qualified Data.ByteString.Lazy as LBS++import qualified Data.Text as T+import qualified Data.Text.Lazy as LT+import qualified Data.Text.Lazy.Builder as TB++import DList (DList)+import qualified DList++import D10.Safe (D10 (..))+import qualified D10.Safe as D10+++--- Show functions ---++{- |++Examples:++* @showNatural 0@ = @"0"@+* @showNatural 268@ = @"268"@++-}+showNatural :: DigitStringSuperset string => Natural -> string+showNatural =+ \case+ 0 -> fromDigitList [ D0 ]+ n -> fromDigitList (naturalList n)+ where+ naturalList :: Natural -> [D10]+ naturalList = DList.toList . r+ where+ r :: Natural -> DList D10+ r = \case+ 0 -> mempty+ n ->+ bifoldMap+ r+ (DList.singleton . toEnum . fromIntegral)+ (quotRem n 10)++{- |++Examples:++* @showInteger 0@ = @"0"@+* @showInteger 12@ = @"12"@+* @showInteger (negate 12)@ = @"-12"@++-}+showInteger :: StringSuperset string => Integer -> string+showInteger = fromCharList . integerList+ where+ integerList :: Integer -> [ASCII.Char]+ integerList =+ \case+ 0 -> [ ASCII.Digit0 ]+ n | n < 0 -> ASCII.HyphenMinus : nonNegativeIntegerList (abs n)+ n -> nonNegativeIntegerList n++ nonNegativeIntegerList :: Integer -> [ASCII.Char]+ nonNegativeIntegerList = DList.toList . r+ where+ r :: Integer -> DList ASCII.Char+ r = \case+ 0 -> mempty+ n ->+ bifoldMap+ r+ (DList.singleton . fromDigit . toEnum . fromInteger)+ (quotRem n 10)++showIntegral :: (Integral n, StringSuperset string) => n -> string+showIntegral = showInteger . toInteger+++--- Read functions ---++{- |++Examples:++* @readNatural "0"@ = @Just 0@+* @readNatural "268"@ = @Just 268@+* @readNatural "0004"@ = @Just 4@+* @readNatural ""@ = @Nothing@+* @readNatural "-4"@ = @Nothing@+* @readNatural "12345678901234567890"@ = @Just 12345678901234567890@++-}+readNatural :: DigitStringSuperset string => string -> Maybe Natural+readNatural = (Just . readNaturalDigits) <=< nonEmpty <=< toDigitListMaybe+ where+ readNaturalDigits :: NonEmpty D10 -> Natural+ readNaturalDigits = List.foldl' (\total x -> (10 * total) + fromIntegral (fromEnum x)) 0++{- |++Examples:++* @readInteger "0"@ = @Just 0@+* @readInteger "268"@ = @Just 268@+* @readInteger "0004"@ = @Just 4@+* @readInteger ""@ = @Nothing@+* @readInteger "-4"@ = @Just (-4)@+* @readInteger "12345678901234567890"@ = @Just 12345678901234567890@++-}+readInteger :: StringSuperset string => string -> Maybe Integer+readInteger = readIntegerCharList <=< toCharListMaybe+ where+ readIntegerCharList :: [ASCII.Char] -> Maybe Integer+ readIntegerCharList =+ \case+ ASCII.HyphenMinus : xs -> fmap negate (readNonNegative xs)+ xs -> readNonNegative xs++ readNonNegative :: [ASCII.Char] -> Maybe Integer+ readNonNegative = (Just . toInteger . readIntegerDigits) <=< nonEmpty <=< toDigitListMaybe++ readIntegerDigits :: NonEmpty D10 -> Integer+ readIntegerDigits = List.foldl' (\total x -> (10 * total) + fromIntegral (fromEnum x)) 0++{- |++Examples:++* @readIntegral "0"@ = @Just (0 :: Word8)@+* @readIntegral "175"@ = @Just (175 :: Word8)@+* @readIntegral "268"@ = @(Nothing :: Maybe Word8)@+* @readIntegral "0004"@ = @Just (4 :: Word8)@+* @readIntegral ""@ = @(Nothing :: Maybe Word8)@+* @readIntegral "-4"@ = @(Nothing :: Maybe Word8)@+* @readIntegral "12345678901234567890"@ = @(Nothing :: Maybe Word8)@++-}+readIntegral :: (StringSuperset string, Integral num, Bits num) => string -> Maybe num+readIntegral = toIntegralSized <=< readInteger+++--- Uninteresting monomorphic specializations of polymorphic functions ---++{- |++Examples:++* @naturalDigitMaybe 5@ = @Just Digit5@+* @naturalDigitMaybe 12@ = @Nothing@++-}+naturalDigitMaybe :: Natural -> Maybe D10+naturalDigitMaybe = D10.natD10Maybe++{- |++Examples:++* @integerDigitMaybe 5@ = @Just Digit5@+* @integerDigitMaybe 12@ = @Nothing@++-}+integerDigitMaybe :: Integer -> Maybe D10+integerDigitMaybe = D10.integerD10Maybe++digitNatural :: D10 -> Natural+digitNatural = D10.d10Nat++digitInteger :: D10 -> Integer+digitInteger = D10.d10Integer+++--- Classes ---++class DigitSuperset char+ where++ fromDigit :: D10 -> char++ isDigit :: char -> Bool+ isDigit = isJust . toDigitMaybe++ toDigitUnsafe :: char -> D10+ toDigitUnsafe = fromJust . toDigitMaybe++ toDigitMaybe :: char -> Maybe D10+ toDigitMaybe x = if isDigit x then Just (toDigitUnsafe x) else Nothing++ {-# minimal fromDigit, ((isDigit, toDigitUnsafe) | toDigitMaybe) #-}++class DigitStringSuperset string+ where++ fromDigitList :: [D10] -> string++ isDigitString :: string -> Bool+ isDigitString = isJust . toDigitListMaybe++ toDigitListUnsafe :: string -> [D10]+ toDigitListUnsafe = fromJust . toDigitListMaybe++ toDigitListMaybe :: string -> Maybe [D10]+ toDigitListMaybe x = if isDigitString x then Just (toDigitListUnsafe x) else Nothing++ {-# minimal fromDigitList, ((isDigitString, toDigitListUnsafe) | toDigitListMaybe) #-}+++--- DigitSuperset instances ---++instance DigitSuperset D10+ where+ isDigit _ = Bool.True+ fromDigit = id+ toDigitUnsafe = id+ toDigitMaybe = Just++instance DigitSuperset ASCII.Char+ where+ isDigit x = x >= ASCII.Digit0 && x <= ASCII.Digit9+ fromDigit = toEnum . (\x -> x + fromEnum ASCII.Digit0) . fromEnum+ toDigitUnsafe = toEnum . (\x -> x - fromEnum ASCII.Digit0) . fromEnum++instance DigitSuperset Unicode.Char+ where+ isDigit x = x >= '0' && x <= '9'+ fromDigit = Unicode.chr . (\x -> x + Unicode.ord '0') . fromEnum+ toDigitUnsafe = toEnum . (\x -> x - Unicode.ord '0') . Unicode.ord++instance DigitSuperset Word8+ where+ fromDigit x = fromChar (fromDigit x :: ASCII.Char)+ toDigitMaybe w = toDigitMaybe =<< (toCharMaybe w :: Maybe ASCII.Char)++instance DigitSuperset char => DigitSuperset (ASCII char)+ where+ isDigit = isDigit . lift+ fromDigit = asciiUnsafe . fromDigit+ toDigitUnsafe = toDigitUnsafe . lift+ toDigitMaybe = toDigitMaybe . lift+++--- DigitStringSuperset instances ---++instance DigitStringSuperset [D10]+ where+ isDigitString _ = Bool.True+ fromDigitList = id+ toDigitListUnsafe = id+ toDigitListMaybe = Just++instance DigitStringSuperset [ASCII.Char]+ where+ isDigitString = List.all isDigit+ fromDigitList = List.map fromDigit+ toDigitListUnsafe = List.map toDigitUnsafe++instance DigitStringSuperset [Unicode.Char]+ where+ isDigitString = List.all isDigit+ fromDigitList = List.map fromDigit+ toDigitListUnsafe = List.map toDigitUnsafe++instance DigitStringSuperset T.Text+ where+ isDigitString = T.all isDigit+ fromDigitList = T.pack . List.map fromDigit+ toDigitListUnsafe = List.map toDigitUnsafe . T.unpack++instance DigitStringSuperset LT.Text+ where+ isDigitString = LT.all isDigit+ fromDigitList = LT.pack . List.map fromDigit+ toDigitListUnsafe = List.map toDigitUnsafe . LT.unpack++instance DigitStringSuperset TB.Builder+ where+ fromDigitList = TB.fromLazyText . fromDigitList+ toDigitListMaybe = toDigitListMaybe . TB.toLazyText++instance DigitStringSuperset BS.ByteString+ where+ isDigitString = BS.all isDigit+ fromDigitList = BS.pack . List.map fromDigit+ toDigitListUnsafe = List.map toDigitUnsafe . BS.unpack++instance DigitStringSuperset LBS.ByteString+ where+ isDigitString = LBS.all isDigit+ fromDigitList = LBS.pack . List.map fromDigit+ toDigitListUnsafe = List.map toDigitUnsafe . LBS.unpack++instance DigitStringSuperset BSB.Builder+ where+ fromDigitList = BSB.lazyByteString . fromDigitList+ toDigitListMaybe = toDigitListMaybe . BSB.toLazyByteString++instance DigitStringSuperset char => DigitStringSuperset (ASCII char)+ where+ isDigitString = isDigitString . lift+ fromDigitList = asciiUnsafe . fromDigitList+ toDigitListUnsafe = toDigitListUnsafe . lift+ toDigitListMaybe = toDigitListMaybe . lift
+ library/ASCII/Hexadecimal.hs view
@@ -0,0 +1,559 @@+module ASCII.Hexadecimal+ (+ {- * Read/show for numeric strings -}+ {- ** Natural -} showNatural, readNatural,+ {- ** Integer -} showInteger, readInteger,+ {- ** Integral -} showIntegral, readIntegral,++ {- * Various digit types -} D16 (..), HexChar (..), HexLetter (..), HexCharBreakdown (..),++ {- * Monomorphic character conversions -}+ {- ** HexLetter ↔ D16 -} hexLetterD16, d16HexLetter,+ {- ** HexLetter ↔ HexChar -} letterHexChar, hexCharLetter,+ {- ** HexChar ↔ ASCII Char -} hexAsciiChar, asciiCharHex,+ {- ** HexChar ↔ D16 -} d16HexChar, hexCharD16,+ {- ** HexChar ↔ HexCharBreakdown -} breakDownHexChar, assembleHexChar,++ {- * Hexadecimal character superset classes -}+ {- * Of hex character -} HexCharSuperset (..),+ {- * Of hex character lists -} HexStringSuperset (..),++ {- * Character/number conversions -}+ {- ** Natural ↔ HexChar -} naturalHexCharMaybe, hexCharNatural, naturalHexCharUnsafe,+ {- ** Natural ↔ D16 -} naturalD16Maybe, d16Natural, naturalD16Unsafe,+ {- ** Integer ↔ HexChar -} integerHexCharMaybe, hexCharInteger, integerHexCharUnsafe,+ {- ** Integer ↔ D16 -} integerD16Maybe, d16Integer, integerD16Unsafe++ ) where++import ASCII.Case (Case (..))+import qualified ASCII.Char as ASCII+import qualified ASCII.Decimal as Dec+import ASCII.Refinement (ASCII, asciiUnsafe, lift)+import ASCII.Superset (StringSuperset, fromChar, fromCharList, toCharListMaybe,+ toCharMaybe)++import Control.Monad (guard, (<=<), (=<<))+import Data.Bifoldable (bifoldMap)+import Data.Bits (Bits, toIntegralSized)+import Data.Bool (Bool, (&&))+import Data.Data (Data)+import Data.Eq (Eq)+import Data.Function (id, ($), (.))+import Data.Functor (fmap)+import Data.Hashable (Hashable)+import Data.Maybe (Maybe (Just, Nothing), fromJust, isJust)+import Data.Monoid (mempty)+import Data.Ord (Ord (..))+import Data.Word (Word8)+import GHC.Generics (Generic)+import Numeric.Natural (Natural)+import Prelude (Bounded (..), Enum (..), Integer, Integral, abs, fromEnum,+ fromInteger, fromIntegral, negate, quotRem, toEnum, toInteger,+ (*), (+), (-))+import Text.Show (Show)++import qualified Data.Bool as Bool+import qualified Data.Char as Unicode+import qualified Data.List as List++import Data.List.NonEmpty (NonEmpty, nonEmpty)++import qualified DList++import qualified Data.ByteString as BS+import qualified Data.ByteString.Builder as BSB+import qualified Data.ByteString.Lazy as LBS++import qualified Data.Text as T+import qualified Data.Text.Lazy as LT+import qualified Data.Text.Lazy.Builder as TB++--- Types ---++-- | A whole number between /0/ and /15/+data D16+ = D0 -- ^ Zero+ | D1 -- ^ One+ | D2 -- ^ Two+ | D3 -- ^ Three+ | D4 -- ^ Four+ | D5 -- ^ Five+ | D6 -- ^ Six+ | D7 -- ^ Seven+ | D8 -- ^ Eight+ | D9 -- ^ Nine+ | D10 -- ^ Ten (A)+ | D11 -- ^ Eleven (B)+ | D12 -- ^ Twelve (C)+ | D13 -- ^ Thirteen (D)+ | D14 -- ^ Fourteen (E)+ | D15 -- ^ Fifteen (F)+ deriving stock (Bounded, Enum, Eq, Ord, Show, Data, Generic)+ deriving anyclass Hashable++-- | Letters used as hexadecimal digits above 9, without a notion of case.+data HexLetter =+ LetterA -- ^ 10+ | LetterB -- ^ 11+ | LetterC -- ^ 12+ | LetterD -- ^ 13+ | LetterE -- ^ 14+ | LetterF -- ^ 15+ deriving stock (Bounded, Enum, Eq, Ord, Show, Data, Generic)+ deriving anyclass Hashable++{- | The subset of ASCII used to represent hexadecimal numbers:++* 'ASCII.Char.Digit0' to 'ASCII.Char.Digit9'+* 'ASCII.Char.CapitalLetterA' to 'ASCII.Char.CapitalLetterF'+* 'ASCII.Char.SmallLetterA' to 'ASCII.Char.SmallLetterF'+-}+data HexChar =+ Digit0 | Digit1 | Digit2 | Digit3 | Digit4+ | Digit5 | Digit6 | Digit7 | Digit8 | Digit9+ | CapitalLetterA | CapitalLetterB | CapitalLetterC+ | CapitalLetterD | CapitalLetterE | CapitalLetterF+ | SmallLetterA | SmallLetterB | SmallLetterC+ | SmallLetterD | SmallLetterE | SmallLetterF+ deriving stock (Bounded, Enum, Eq, Ord, Show, Data, Generic)+ deriving anyclass Hashable++data HexCharBreakdown = HexDigit Dec.D10 | HexLetter Case HexLetter+ deriving stock (Eq, Ord, Show, Data, Generic)+ deriving anyclass Hashable++-- | Behaves the same as 'HexChar'+instance Enum HexCharBreakdown+ where+ fromEnum = fromEnum . assembleHexChar+ toEnum = breakDownHexChar . toEnum++-- | Behaves the same as 'HexChar'+instance Bounded HexCharBreakdown+ where+ minBound = breakDownHexChar minBound+ maxBound = breakDownHexChar maxBound+++--- Monomorphic conversions between the character types ---++breakDownHexChar :: HexChar -> HexCharBreakdown+breakDownHexChar =+ \case+ x | x <= Digit9 -> HexDigit (toEnum (fromEnum x))+ x | x <= CapitalLetterF -> HexLetter UpperCase (toEnum (fromEnum x - 10))+ x -> HexLetter LowerCase (toEnum (fromEnum x - 16))++assembleHexChar :: HexCharBreakdown -> HexChar+assembleHexChar =+ \case+ HexDigit x -> toEnum (fromEnum x)+ HexLetter UpperCase x -> toEnum (fromEnum x + 10)+ HexLetter LowerCase x -> toEnum (fromEnum x + 16)++d16HexChar :: Case -> D16 -> HexChar+d16HexChar c =+ toEnum+ .+ case c of+ UpperCase -> fromEnum+ LowerCase -> \case+ x | x <= D9 -> fromEnum x+ x -> fromEnum x + 6++hexCharD16 :: HexChar -> D16+hexCharD16 =+ \case+ x | x < SmallLetterA -> toEnum (fromEnum x)+ x -> toEnum (fromEnum x - 6)++hexAsciiChar :: HexChar -> ASCII.Char+hexAsciiChar =+ toEnum+ .+ \case+ x | x <= Digit9 -> fromEnum ASCII.Digit0 + fromEnum x+ x | x <= CapitalLetterF -> fromEnum ASCII.CapitalLetterA + fromEnum x - 10+ x -> fromEnum ASCII.SmallLetterA + fromEnum x - 16++asciiCharHex :: ASCII.Char -> Maybe HexChar+asciiCharHex =+ \case+ x | x >= ASCII.Digit0 && x <= ASCII.Digit9 ->+ Just $ toEnum $+ fromEnum x - fromEnum ASCII.Digit0++ x | x >= ASCII.CapitalLetterA && x <= ASCII.CapitalLetterF ->+ Just $ toEnum $+ fromEnum x + 10 - fromEnum ASCII.CapitalLetterA++ x | x >= ASCII.SmallLetterA && x <= ASCII.SmallLetterF ->+ Just $ toEnum $+ fromEnum x + 16 - fromEnum ASCII.SmallLetterA++ _ -> Nothing++hexLetterD16 :: HexLetter -> D16+hexLetterD16 = toEnum . (\x -> x + 10) . fromEnum++d16HexLetter :: D16 -> Maybe HexLetter+d16HexLetter x =+ do+ guard (x >= D10)+ Just (toEnum (fromEnum x - 10))++letterHexChar :: Case -> HexLetter -> HexChar+letterHexChar = \case+ UpperCase -> toEnum . (\x -> x + 10) . fromEnum+ LowerCase -> toEnum . (\x -> x + 16) . fromEnum++hexCharLetter :: HexChar -> Maybe HexLetter+hexCharLetter = \case+ x | x <= Digit9 -> Nothing+ x | x <= CapitalLetterF -> Just (toEnum (fromEnum x - 10))+ x -> Just (toEnum (fromEnum x - 16))+++--- Monomorphic character/number conversions ---++naturalHexCharMaybe :: Case -> Natural -> Maybe HexChar+naturalHexCharMaybe =+ \case+ UpperCase -> \case+ x | x <= 15 -> Just (toEnum (fromIntegral x))+ _ -> Nothing+ LowerCase -> \case+ x | x <= 9 -> Just (toEnum (fromIntegral x))+ x | x <= 15 -> Just (toEnum (fromIntegral x + 6))+ _ -> Nothing++naturalHexCharUnsafe :: Case -> Natural -> HexChar+naturalHexCharUnsafe =+ \case+ UpperCase -> \x -> toEnum (fromIntegral x)+ LowerCase -> \case+ x | x <= 9 -> toEnum (fromIntegral x)+ x -> toEnum (fromIntegral x + 6)++hexCharNatural :: HexChar -> Natural+hexCharNatural =+ fromIntegral+ .+ \case+ x | x > 15 -> x - 6+ x -> x+ .+ fromEnum++integerHexCharMaybe :: Case -> Integer -> Maybe HexChar+integerHexCharMaybe =+ \case+ UpperCase -> \case+ x | x < 0 -> Nothing+ x | x <= 15 -> Just (toEnum (fromIntegral x))+ _ -> Nothing+ LowerCase -> \case+ x | x < 0 -> Nothing+ x | x <= 9 -> Just (toEnum (fromIntegral x))+ x | x <= 15 -> Just (toEnum (fromIntegral x + 6))+ _ -> Nothing++integerHexCharUnsafe :: Case -> Integer -> HexChar+integerHexCharUnsafe =+ \case+ UpperCase -> \x -> toEnum (fromIntegral x)+ LowerCase -> \case+ x | x <= 9 -> toEnum (fromIntegral x)+ x -> toEnum (fromIntegral x + 6)++hexCharInteger :: HexChar -> Integer+hexCharInteger =+ fromIntegral+ .+ \case+ x | x > 15 -> x - 6+ x -> x+ .+ fromEnum++naturalD16Maybe :: Natural -> Maybe D16+naturalD16Maybe =+ \case+ x | x <= 15 -> Just (toEnum (fromIntegral x))+ _ -> Nothing++d16Natural :: D16 -> Natural+d16Natural = fromIntegral . fromEnum++integerD16Maybe :: Integer -> Maybe D16+integerD16Maybe =+ \case+ x | x < 0 -> Nothing+ x | x <= 15 -> Just (toEnum (fromInteger x))+ _ -> Nothing++d16Integer :: D16 -> Integer+d16Integer = toInteger . fromEnum++naturalD16Unsafe :: Natural -> D16+naturalD16Unsafe = toEnum . fromIntegral++integerD16Unsafe :: Integer -> D16+integerD16Unsafe = toEnum . fromIntegral+++--- Classes ---++class HexCharSuperset char+ where++ fromHexChar :: HexChar -> char++ isHexChar :: char -> Bool+ isHexChar = isJust . toHexCharMaybe++ toHexCharUnsafe :: char -> HexChar+ toHexCharUnsafe = fromJust . toHexCharMaybe++ toHexCharMaybe :: char -> Maybe HexChar+ toHexCharMaybe x = if isHexChar x then Just (toHexCharUnsafe x) else Nothing++ {-# minimal fromHexChar, ((isHexChar, toHexCharUnsafe) | toHexCharMaybe) #-}++class HexStringSuperset string+ where++ fromHexCharList :: [HexChar] -> string++ isHexString :: string -> Bool+ isHexString = isJust . toHexCharListMaybe++ toHexCharListUnsafe :: string -> [HexChar]+ toHexCharListUnsafe = fromJust . toHexCharListMaybe++ toHexCharListMaybe :: string -> Maybe [HexChar]+ toHexCharListMaybe x = if isHexString x then Just (toHexCharListUnsafe x) else Nothing++ {-# minimal fromHexCharList, ((isHexString, toHexCharListUnsafe) | toHexCharListMaybe) #-}+++--- Show functions ---++{- |++Examples:++* @showNatural LowerCase 12@ = @"c"@+* @showNatural UpperCase (256 + 12)@ = @"10C"@+* @showNatural UpperCase 0@ = @"0"@++-}+showNatural :: HexStringSuperset string => Case -> Natural -> string+showNatural =+ \c -> \case+ 0 -> fromHexCharList [ Digit0 ]+ n -> fromHexCharList (fmap (d16HexChar c) (naturalList n))+ where+ naturalList :: Natural -> [D16]+ naturalList = DList.toList . r+ where+ r = \case+ 0 -> mempty+ n ->+ bifoldMap+ r+ (DList.singleton . naturalD16Unsafe)+ (quotRem n 16)++{- |++Examples:++* @showInteger LowerCase 12@ = @"c"@+* @showInteger LowerCase (negate 12)@ = @"-c"@+* @showInteger UpperCase (256 + 12)@ = @"10C"@+* @showInteger UpperCase (negate (256 + 12))@ = @"-10C"@+* @showInteger UpperCase 0@ = @"0"@++-}+showInteger :: StringSuperset string => Case -> Integer -> string+showInteger = \c -> fromCharList . integerList c+ where+ integerList :: Case -> Integer -> [ASCII.Char]+ integerList c =+ \case+ 0 -> [ ASCII.Digit0 ]+ n | n < 0 -> ASCII.HyphenMinus : nonNegativeIntegerList c (abs n)+ n -> nonNegativeIntegerList c n++ nonNegativeIntegerList :: Case -> Integer -> [ASCII.Char]+ nonNegativeIntegerList c = DList.toList . r+ where+ r = \case+ 0 -> mempty+ n ->+ bifoldMap+ r+ (DList.singleton . fromHexChar . integerHexCharUnsafe c)+ (quotRem n 16)++showIntegral :: (StringSuperset string, Integral number) => Case -> number -> string+showIntegral c = showInteger c . toInteger+++--- Read functions ---++{- |++Examples:++* @readNatural "5"@ = @Just 5@+* @readNatural "-5"@ = @Nothing@+* @readNatural "1f"@ = @Just 31@+* @readNatural "1F"@ = @Just 31@+* @readNatural "xa"@ = @Nothing@+* @readNatural ""@ = @Nothing@++-}+readNatural :: HexStringSuperset string => string -> Maybe Natural+readNatural = (Just . readNaturalDigits) <=< nonEmpty <=< (Just . fmap hexCharD16) <=< toHexCharListMaybe+ where+ readNaturalDigits :: NonEmpty D16 -> Natural+ readNaturalDigits = List.foldl' (\total x -> (16 * total) + d16Natural x) 0++{- |++Examples:++* @readInteger "5"@ = @Just 5@+* @readInteger "-5"@ = @Just (-5)@+* @readInteger "1f"@ = @Just 31@+* @readInteger "1F"@ = @Just 31@+* @readInteger "xa"@ = @Nothing@+* @readInteger ""@ = @Nothing@+* @readInteger "-"@ = @Nothing@++-}+readInteger :: StringSuperset string => string -> Maybe Integer+readInteger = readIntegerCharList <=< toCharListMaybe+ where+ readIntegerCharList :: [ASCII.Char] -> Maybe Integer+ readIntegerCharList =+ \case+ ASCII.HyphenMinus : xs -> fmap negate (readNonNegative xs)+ xs -> readNonNegative xs++ readNonNegative :: [ASCII.Char] -> Maybe Integer+ readNonNegative = (Just . toInteger . readIntegerDigits) <=< nonEmpty <=< (Just . fmap hexCharD16) <=< toHexCharListMaybe++ readIntegerDigits :: NonEmpty D16 -> Integer+ readIntegerDigits = List.foldl' (\total x -> (16 * total) + d16Integer x) 0++{- |++Examples:++* @readIntegral "0014"@ = @Just (20 :: Word8)@+* @readIntegral ""@ = @(Nothing :: Maybe Word8)@+* @readIntegral "-4"@ = @(Nothing :: Maybe Word8)@+* @readIntegral "1234"@ = @(Nothing :: Maybe Word8)@++-}+readIntegral :: (StringSuperset string, Integral number, Bits number) => string -> Maybe number+readIntegral = toIntegralSized <=< readInteger+++--- HexCharSuperset instances ---++instance HexCharSuperset HexChar+ where+ isHexChar _ = Bool.True+ fromHexChar = id+ toHexCharUnsafe = id+ toHexCharMaybe = Just++instance HexCharSuperset ASCII.Char+ where+ fromHexChar = hexAsciiChar+ toHexCharMaybe = asciiCharHex++instance HexCharSuperset Unicode.Char+ where+ fromHexChar = fromChar . fromHexChar+ toHexCharMaybe = toHexCharMaybe <=< toCharMaybe++instance HexCharSuperset Word8+ where+ fromHexChar x = fromChar (fromHexChar x :: ASCII.Char)+ toHexCharMaybe w = toHexCharMaybe =<< (toCharMaybe w :: Maybe ASCII.Char)++instance HexCharSuperset char => HexCharSuperset (ASCII char)+ where+ isHexChar = isHexChar . lift+ fromHexChar = asciiUnsafe . fromHexChar+ toHexCharUnsafe = toHexCharUnsafe . lift+ toHexCharMaybe = toHexCharMaybe . lift+++--- HexStringSuperset instances ---++instance HexStringSuperset [HexChar]+ where+ fromHexCharList = id+ isHexString _ = Bool.True+ toHexCharListUnsafe = id+ toHexCharListMaybe = Just++instance HexStringSuperset [ASCII.Char]+ where+ fromHexCharList = List.map fromHexChar+ isHexString = List.all isHexChar+ toHexCharListUnsafe = List.map toHexCharUnsafe++instance HexStringSuperset [Unicode.Char]+ where+ fromHexCharList = List.map fromHexChar+ isHexString = List.all isHexChar+ toHexCharListUnsafe = List.map toHexCharUnsafe++instance HexStringSuperset T.Text+ where+ fromHexCharList = T.pack . List.map fromHexChar+ isHexString = T.all isHexChar+ toHexCharListUnsafe = List.map toHexCharUnsafe . T.unpack++instance HexStringSuperset LT.Text+ where+ fromHexCharList = LT.pack . List.map fromHexChar+ isHexString = LT.all isHexChar+ toHexCharListUnsafe = List.map toHexCharUnsafe . LT.unpack++instance HexStringSuperset TB.Builder+ where+ fromHexCharList = TB.fromLazyText . fromHexCharList+ toHexCharListMaybe = toHexCharListMaybe . TB.toLazyText++instance HexStringSuperset BS.ByteString+ where+ fromHexCharList = BS.pack . List.map fromHexChar+ isHexString = BS.all isHexChar+ toHexCharListUnsafe = List.map toHexCharUnsafe . BS.unpack++instance HexStringSuperset LBS.ByteString+ where+ fromHexCharList = LBS.pack . List.map fromHexChar+ isHexString = LBS.all isHexChar+ toHexCharListUnsafe = List.map toHexCharUnsafe . LBS.unpack++instance HexStringSuperset BSB.Builder+ where+ fromHexCharList = BSB.lazyByteString . fromHexCharList+ toHexCharListMaybe = toHexCharListMaybe . BSB.toLazyByteString++instance HexStringSuperset char => HexStringSuperset (ASCII char)+ where+ isHexString = isHexString . lift+ fromHexCharList = asciiUnsafe . fromHexCharList+ toHexCharListUnsafe = toHexCharListUnsafe . lift+ toHexCharListMaybe = toHexCharListMaybe . lift
+ library/DList.hs view
@@ -0,0 +1,21 @@+module DList where++import Data.Function ((.), id)+import Data.Monoid (Monoid (mempty))+import Data.Semigroup (Semigroup ((<>)))++newtype DList a = DList ([a] -> [a])++toList :: DList a -> [a]+toList (DList f) = f []++singleton :: a -> DList a+singleton x = DList (x :)++instance Semigroup (DList a)+ where+ DList f <> DList g = DList (f . g)++instance Monoid (DList a)+ where+ mempty = DList id
+ license.txt view
@@ -0,0 +1,13 @@+Copyright 2022 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.
+ test/Main.hs view
@@ -0,0 +1,778 @@+module Main (main) where++import ASCII.Case (Case (..))+import qualified ASCII.Char as ASCII+import qualified ASCII.Decimal as Dec+import qualified ASCII.Hexadecimal as Hex++import Control.Applicative (liftA2)+import Control.Monad (Monad (..), when)+import Data.Bool (not)+import Data.Eq (Eq)+import Data.Foldable (for_)+import Data.Function (fix, ($), (.))+import Data.List (map, splitAt)+import Data.Maybe (Maybe (..))+import Data.String (String)+import Data.Tuple (uncurry)+import Data.Word (Word8)+import Numeric.Natural (Natural)+import Prelude (Bounded (..), Enum (..), Integer, negate, (+), (-))+import System.Exit (exitFailure)+import System.IO (IO)+import Text.Show (Show)++import qualified Data.ByteString as BS+import qualified Data.ByteString.Lazy as LBS+import qualified Data.List as List+import qualified Data.Text as T+import qualified Data.Text.Lazy as LT+import qualified Invert as I++import Hedgehog (Gen, MonadTest, Property, PropertyT, checkParallel, discover,+ forAll, property, withTests, (===))+import qualified Hedgehog.Gen as Gen+import qualified Hedgehog.Range as Range++main :: IO ()+main = checkParallel $$(discover) >>= \ok -> when (not ok) exitFailure++prop_showNatural_12 :: Property+prop_showNatural_12 = withTests 1 $ property $+ Dec.showNatural 12 === ("12" :: T.Text)++prop_showNatural_268 :: Property+prop_showNatural_268 = withTests 1 $ property $+ Dec.showNatural 268 === ("268" :: String)++prop_showInteger_12 :: Property+prop_showInteger_12 = withTests 1 $ property $+ Dec.showInteger 12 === ("12" :: T.Text)++prop_showInteger_minus12 :: Property+prop_showInteger_minus12 = withTests 1 $ property $+ Dec.showInteger (negate 12) === ("-12" :: LT.Text)++prop_showInteger_268 :: Property+prop_showInteger_268 = withTests 1 $ property $+ Dec.showInteger 268 === ("268" :: LT.Text)++prop_showInteger_minus268 :: Property+prop_showInteger_minus268 = withTests 1 $ property $+ Dec.showInteger (negate 268) === ("-268" :: LT.Text)++prop_showNatural_0_to_9 :: Property+prop_showNatural_0_to_9 = withTests 1 $ property $+ T.unwords (map Dec.showNatural [0..9]) === ("0 1 2 3 4 5 6 7 8 9" :: T.Text)++prop_showNatural_10_to_99 :: Property+prop_showNatural_10_to_99 = withTests 1 $ property $+ let+ ne f xs = case xs of [] -> []; _ -> f xs+ groupsOf n = fix $ \r -> ne $ \xs -> let (x, ys) = splitAt n xs in x : r ys+ res :: [T.Text]+ res = map T.unwords $ groupsOf 10 $ map Dec.showNatural [10..99]+ in+ res ===+ [ "10 11 12 13 14 15 16 17 18 19"+ , "20 21 22 23 24 25 26 27 28 29"+ , "30 31 32 33 34 35 36 37 38 39"+ , "40 41 42 43 44 45 46 47 48 49"+ , "50 51 52 53 54 55 56 57 58 59"+ , "60 61 62 63 64 65 66 67 68 69"+ , "70 71 72 73 74 75 76 77 78 79"+ , "80 81 82 83 84 85 86 87 88 89"+ , "90 91 92 93 94 95 96 97 98 99"+ ]++prop_showNaturalHex_0_to_f_lower :: Property+prop_showNaturalHex_0_to_f_lower = withTests 1 $ property $+ T.unwords (List.map (Hex.showNatural LowerCase) [0..15])+ === "0 1 2 3 4 5 6 7 8 9 a b c d e f"++prop_showNaturalHex_0_to_f_upper :: Property+prop_showNaturalHex_0_to_f_upper = withTests 1 $ property $+ T.unwords (List.map (Hex.showNatural UpperCase) [0..15])+ === "0 1 2 3 4 5 6 7 8 9 A B C D E F"++prop_showNaturalHex_10_to_ff :: Property+prop_showNaturalHex_10_to_ff = withTests 1 $ property $+ let+ ne f xs = case xs of [] -> []; _ -> f xs+ groupsOf n = fix $ \r -> ne $ \xs -> let (x, ys) = splitAt n xs in x : r ys+ res :: [LT.Text]+ res = map LT.unwords $ groupsOf 16 $ map (Hex.showNatural LowerCase) [16..255]+ in+ res ===+ [ "10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f"+ , "20 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f"+ , "30 31 32 33 34 35 36 37 38 39 3a 3b 3c 3d 3e 3f"+ , "40 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f"+ , "50 51 52 53 54 55 56 57 58 59 5a 5b 5c 5d 5e 5f"+ , "60 61 62 63 64 65 66 67 68 69 6a 6b 6c 6d 6e 6f"+ , "70 71 72 73 74 75 76 77 78 79 7a 7b 7c 7d 7e 7f"+ , "80 81 82 83 84 85 86 87 88 89 8a 8b 8c 8d 8e 8f"+ , "90 91 92 93 94 95 96 97 98 99 9a 9b 9c 9d 9e 9f"+ , "a0 a1 a2 a3 a4 a5 a6 a7 a8 a9 aa ab ac ad ae af"+ , "b0 b1 b2 b3 b4 b5 b6 b7 b8 b9 ba bb bc bd be bf"+ , "c0 c1 c2 c3 c4 c5 c6 c7 c8 c9 ca cb cc cd ce cf"+ , "d0 d1 d2 d3 d4 d5 d6 d7 d8 d9 da db dc dd de df"+ , "e0 e1 e2 e3 e4 e5 e6 e7 e8 e9 ea eb ec ed ee ef"+ , "f0 f1 f2 f3 f4 f5 f6 f7 f8 f9 fa fb fc fd fe ff"+ ]++prop_toDigitListMaybe :: Property+prop_toDigitListMaybe = withTests 1 $ property $+ Dec.toDigitListMaybe ("846" :: T.Text) === Just [Dec.D8, Dec.D4, Dec.D6]++prop_toDigitListMaybe_fail :: Property+prop_toDigitListMaybe_fail = withTests 1 $ property $+ Dec.toDigitListMaybe ("84a6" :: T.Text) === Nothing++prop_showNatural_0 :: Property+prop_showNatural_0 = withTests 1 $ property $+ Dec.showNatural 0 === ("0" :: T.Text)++prop_showInteger_0 :: Property+prop_showInteger_0 = withTests 1 $ property $+ Dec.showInteger 0 === ("0" :: T.Text)++prop_readNatural_0 :: Property+prop_readNatural_0 = withTests 1 $ property $+ Dec.readNatural ("0" :: T.Text) === Just 0++prop_readNatural_268 :: Property+prop_readNatural_268 = withTests 1 $ property $+ Dec.readNatural ("268" :: BS.ByteString) === Just 268++prop_readNatural_0004 :: Property+prop_readNatural_0004 = withTests 1 $ property $+ Dec.readNatural ("0004" :: T.Text) === Just 4++prop_readNatural_empty :: Property+prop_readNatural_empty = withTests 1 $ property $+ Dec.readNatural ("" :: T.Text) === Nothing++prop_readNatural_minus4 :: Property+prop_readNatural_minus4 = withTests 1 $ property $+ Dec.readNatural ("-4" :: BS.ByteString) === Nothing++prop_readNatural_big :: Property+prop_readNatural_big = withTests 1 $ property $+ Dec.readNatural ("12345678901234567890" :: T.Text) === Just 12345678901234567890++prop_readInteger_0 :: Property+prop_readInteger_0 = withTests 1 $ property $+ Dec.readInteger ("0" :: T.Text) === Just 0++prop_readInteger_268 :: Property+prop_readInteger_268 = withTests 1 $ property $+ Dec.readInteger ("268" :: T.Text) === Just 268++prop_readInteger_0004 :: Property+prop_readInteger_0004 = withTests 1 $ property $+ Dec.readInteger ("0004" :: T.Text) === Just 4++prop_readInteger_empty :: Property+prop_readInteger_empty = withTests 1 $ property $+ Dec.readInteger ("" :: T.Text) === Nothing++prop_readInteger_minus4 :: Property+prop_readInteger_minus4 = withTests 1 $ property $+ Dec.readInteger ("-4" :: BS.ByteString) === Just (-4)++prop_readInteger_minus :: Property+prop_readInteger_minus = withTests 1 $ property $+ Dec.readInteger ("-" :: T.Text) === Nothing++prop_readInteger_big :: Property+prop_readInteger_big = withTests 1 $ property $+ Dec.readInteger ("12345678901234567890" :: BS.ByteString) === Just 12345678901234567890++prop_readIntegral_word8_0 :: Property+prop_readIntegral_word8_0 = withTests 1 $ property $+ Dec.readIntegral ("0" :: T.Text) === Just (0 :: Word8)++prop_readIntegral_word8_175 :: Property+prop_readIntegral_word8_175 = withTests 1 $ property $+ Dec.readIntegral ("175" :: T.Text) === Just (175 :: Word8)++prop_readIntegral_word8_268 :: Property+prop_readIntegral_word8_268 = withTests 1 $ property $+ Dec.readIntegral ("268" :: T.Text) === (Nothing :: Maybe Word8)++prop_readIntegral_word8_0004 :: Property+prop_readIntegral_word8_0004 = withTests 1 $ property $+ Dec.readIntegral ("0004" :: T.Text) === Just (4 :: Word8)++prop_readIntegral_word8_empty :: Property+prop_readIntegral_word8_empty = withTests 1 $ property $+ Dec.readIntegral ("" :: T.Text) === (Nothing :: Maybe Word8)++prop_readIntegral_word8_minus4 :: Property+prop_readIntegral_word8_minus4 = withTests 1 $ property $+ Dec.readIntegral ("-4" :: T.Text) === (Nothing :: Maybe Word8)++prop_readIntegral_word8_big :: Property+prop_readIntegral_word8_big = withTests 1 $ property $+ Dec.readIntegral ("12345678901234567890" :: T.Text) === (Nothing :: Maybe Word8)++prop_readIntegral_natural_4 :: Property+prop_readIntegral_natural_4 = withTests 1 $ property $+ Dec.readIntegral ("4" :: T.Text) === Just (4 :: Natural)++prop_readIntegral_natural_minus4 :: Property+prop_readIntegral_natural_minus4 = withTests 1 $ property $+ Dec.readIntegral ("-4" :: T.Text) === (Nothing :: Maybe Natural)++prop_naturalDigitMaybe_5 :: Property+prop_naturalDigitMaybe_5 = withTests 1 $ property $+ Dec.naturalDigitMaybe 5 === Just Dec.D5++prop_naturalDigitMaybe_12 :: Property+prop_naturalDigitMaybe_12 = withTests 1 $ property $+ Dec.naturalDigitMaybe 12 === Nothing++prop_integerDigitMaybe_5 :: Property+prop_integerDigitMaybe_5 = withTests 1 $ property $+ Dec.integerDigitMaybe 5 === Just Dec.D5++prop_integerDigitMaybe_12 :: Property+prop_integerDigitMaybe_12 = withTests 1 $ property $+ Dec.integerDigitMaybe 12 === Nothing++checkEnumBounded :: forall a f. (MonadTest f, Enum a, Bounded a, Eq a, Show a) => [a] -> f ()+checkEnumBounded xs =+ do+ [minBound .. maxBound] === xs+ List.map toEnum [0 .. List.length xs - 1] === xs+ List.map fromEnum xs === [0 .. List.length xs - 1]++prop_D16_enumBounded :: Property+prop_D16_enumBounded = withTests 1 $ property $+ checkEnumBounded+ [ Hex.D0, Hex.D1, Hex.D2, Hex.D3+ , Hex.D4, Hex.D5, Hex.D6, Hex.D7+ , Hex.D8, Hex.D9, Hex.D10, Hex.D11+ , Hex.D12, Hex.D13, Hex.D14, Hex.D15+ ]++prop_HexLetter_enumBounded :: Property+prop_HexLetter_enumBounded = withTests 1 $ property $+ checkEnumBounded+ [ Hex.LetterA, Hex.LetterB, Hex.LetterC+ , Hex.LetterD, Hex.LetterE, Hex.LetterF+ ]++prop_HexChar_enumBounded :: Property+prop_HexChar_enumBounded = withTests 1 $ property $+ checkEnumBounded+ [ Hex.Digit0, Hex.Digit1, Hex.Digit2, Hex.Digit3, Hex.Digit4+ , Hex.Digit5, Hex.Digit6, Hex.Digit7, Hex.Digit8, Hex.Digit9+ , Hex.CapitalLetterA, Hex.CapitalLetterB, Hex.CapitalLetterC+ , Hex.CapitalLetterD, Hex.CapitalLetterE, Hex.CapitalLetterF+ , Hex.SmallLetterA, Hex.SmallLetterB, Hex.SmallLetterC+ , Hex.SmallLetterD, Hex.SmallLetterE, Hex.SmallLetterF+ ]++prop_HexCharBreakdown_enumBounded :: Property+prop_HexCharBreakdown_enumBounded = withTests 1 $ property $+ checkEnumBounded+ [ Hex.HexDigit Dec.D0+ , Hex.HexDigit Dec.D1+ , Hex.HexDigit Dec.D2+ , Hex.HexDigit Dec.D3+ , Hex.HexDigit Dec.D4+ , Hex.HexDigit Dec.D5+ , Hex.HexDigit Dec.D6+ , Hex.HexDigit Dec.D7+ , Hex.HexDigit Dec.D8+ , Hex.HexDigit Dec.D9+ , Hex.HexLetter UpperCase Hex.LetterA+ , Hex.HexLetter UpperCase Hex.LetterB+ , Hex.HexLetter UpperCase Hex.LetterC+ , Hex.HexLetter UpperCase Hex.LetterD+ , Hex.HexLetter UpperCase Hex.LetterE+ , Hex.HexLetter UpperCase Hex.LetterF+ , Hex.HexLetter LowerCase Hex.LetterA+ , Hex.HexLetter LowerCase Hex.LetterB+ , Hex.HexLetter LowerCase Hex.LetterC+ , Hex.HexLetter LowerCase Hex.LetterD+ , Hex.HexLetter LowerCase Hex.LetterE+ , Hex.HexLetter LowerCase Hex.LetterF+ ]++every :: (Enum a, Bounded a) => [a]+every = [minBound .. maxBound]++functionEq :: (MonadTest f, Eq a, Show a) => [t] -> (t -> a) -> (t -> a) -> f ()+functionEq xs f g =+ for_ xs $ \x ->+ f x === g x++prop_hexLetterD16 :: Property+prop_hexLetterD16 = withTests 1 $ property $+ functionEq every Hex.hexLetterD16 $ \case+ Hex.LetterA -> Hex.D10+ Hex.LetterB -> Hex.D11+ Hex.LetterC -> Hex.D12+ Hex.LetterD -> Hex.D13+ Hex.LetterE -> Hex.D14+ Hex.LetterF -> Hex.D15++prop_d16HexLetter :: Property+prop_d16HexLetter = withTests 1 $ property $+ functionEq every Hex.d16HexLetter $+ I.injection I.linearSearchLazy every Hex.hexLetterD16++prop_letterHexChar :: Property+prop_letterHexChar = withTests 1 $ property $+ functionEq (liftA2 (,) every every) (uncurry Hex.letterHexChar) $ \case+ (UpperCase, Hex.LetterA) -> Hex.CapitalLetterA+ (UpperCase, Hex.LetterB) -> Hex.CapitalLetterB+ (UpperCase, Hex.LetterC) -> Hex.CapitalLetterC+ (UpperCase, Hex.LetterD) -> Hex.CapitalLetterD+ (UpperCase, Hex.LetterE) -> Hex.CapitalLetterE+ (UpperCase, Hex.LetterF) -> Hex.CapitalLetterF+ (LowerCase, Hex.LetterA) -> Hex.SmallLetterA+ (LowerCase, Hex.LetterB) -> Hex.SmallLetterB+ (LowerCase, Hex.LetterC) -> Hex.SmallLetterC+ (LowerCase, Hex.LetterD) -> Hex.SmallLetterD+ (LowerCase, Hex.LetterE) -> Hex.SmallLetterE+ (LowerCase, Hex.LetterF) -> Hex.SmallLetterF++prop_hexCharLetter :: Property+prop_hexCharLetter = withTests 1 $ property $+ functionEq every Hex.hexCharLetter $ \case+ Hex.CapitalLetterA -> Just Hex.LetterA+ Hex.CapitalLetterB -> Just Hex.LetterB+ Hex.CapitalLetterC -> Just Hex.LetterC+ Hex.CapitalLetterD -> Just Hex.LetterD+ Hex.CapitalLetterE -> Just Hex.LetterE+ Hex.CapitalLetterF -> Just Hex.LetterF+ Hex.SmallLetterA -> Just Hex.LetterA+ Hex.SmallLetterB -> Just Hex.LetterB+ Hex.SmallLetterC -> Just Hex.LetterC+ Hex.SmallLetterD -> Just Hex.LetterD+ Hex.SmallLetterE -> Just Hex.LetterE+ Hex.SmallLetterF -> Just Hex.LetterF+ _ -> Nothing++prop_hexAsciiChar :: Property+prop_hexAsciiChar = withTests 1 $ property $+ functionEq every Hex.hexAsciiChar $ \case+ Hex.Digit0 -> ASCII.Digit0+ Hex.Digit1 -> ASCII.Digit1+ Hex.Digit2 -> ASCII.Digit2+ Hex.Digit3 -> ASCII.Digit3+ Hex.Digit4 -> ASCII.Digit4+ Hex.Digit5 -> ASCII.Digit5+ Hex.Digit6 -> ASCII.Digit6+ Hex.Digit7 -> ASCII.Digit7+ Hex.Digit8 -> ASCII.Digit8+ Hex.Digit9 -> ASCII.Digit9+ Hex.CapitalLetterA -> ASCII.CapitalLetterA+ Hex.CapitalLetterB -> ASCII.CapitalLetterB+ Hex.CapitalLetterC -> ASCII.CapitalLetterC+ Hex.CapitalLetterD -> ASCII.CapitalLetterD+ Hex.CapitalLetterE -> ASCII.CapitalLetterE+ Hex.CapitalLetterF -> ASCII.CapitalLetterF+ Hex.SmallLetterA -> ASCII.SmallLetterA+ Hex.SmallLetterB -> ASCII.SmallLetterB+ Hex.SmallLetterC -> ASCII.SmallLetterC+ Hex.SmallLetterD -> ASCII.SmallLetterD+ Hex.SmallLetterE -> ASCII.SmallLetterE+ Hex.SmallLetterF -> ASCII.SmallLetterF++prop_asciiCharHex :: Property+prop_asciiCharHex = withTests 1 $ property $+ functionEq every Hex.asciiCharHex $+ I.injection I.linearSearchLazy every Hex.hexAsciiChar++prop_d16HexChar :: Property+prop_d16HexChar = withTests 1 $ property $+ functionEq (liftA2 (,) every every) (uncurry Hex.d16HexChar) $ \case+ (_, Hex.D0) -> Hex.Digit0+ (_, Hex.D1) -> Hex.Digit1+ (_, Hex.D2) -> Hex.Digit2+ (_, Hex.D3) -> Hex.Digit3+ (_, Hex.D4) -> Hex.Digit4+ (_, Hex.D5) -> Hex.Digit5+ (_, Hex.D6) -> Hex.Digit6+ (_, Hex.D7) -> Hex.Digit7+ (_, Hex.D8) -> Hex.Digit8+ (_, Hex.D9) -> Hex.Digit9+ (UpperCase, Hex.D10) -> Hex.CapitalLetterA+ (UpperCase, Hex.D11) -> Hex.CapitalLetterB+ (UpperCase, Hex.D12) -> Hex.CapitalLetterC+ (UpperCase, Hex.D13) -> Hex.CapitalLetterD+ (UpperCase, Hex.D14) -> Hex.CapitalLetterE+ (UpperCase, Hex.D15) -> Hex.CapitalLetterF+ (LowerCase, Hex.D10) -> Hex.SmallLetterA+ (LowerCase, Hex.D11) -> Hex.SmallLetterB+ (LowerCase, Hex.D12) -> Hex.SmallLetterC+ (LowerCase, Hex.D13) -> Hex.SmallLetterD+ (LowerCase, Hex.D14) -> Hex.SmallLetterE+ (LowerCase, Hex.D15) -> Hex.SmallLetterF++prop_hexCharD16 :: Property+prop_hexCharD16 = withTests 1 $ property $+ functionEq every Hex.hexCharD16 $ \case+ Hex.Digit0 -> Hex.D0+ Hex.Digit1 -> Hex.D1+ Hex.Digit2 -> Hex.D2+ Hex.Digit3 -> Hex.D3+ Hex.Digit4 -> Hex.D4+ Hex.Digit5 -> Hex.D5+ Hex.Digit6 -> Hex.D6+ Hex.Digit7 -> Hex.D7+ Hex.Digit8 -> Hex.D8+ Hex.Digit9 -> Hex.D9+ Hex.CapitalLetterA -> Hex.D10+ Hex.CapitalLetterB -> Hex.D11+ Hex.CapitalLetterC -> Hex.D12+ Hex.CapitalLetterD -> Hex.D13+ Hex.CapitalLetterE -> Hex.D14+ Hex.CapitalLetterF -> Hex.D15+ Hex.SmallLetterA -> Hex.D10+ Hex.SmallLetterB -> Hex.D11+ Hex.SmallLetterC -> Hex.D12+ Hex.SmallLetterD -> Hex.D13+ Hex.SmallLetterE -> Hex.D14+ Hex.SmallLetterF -> Hex.D15++prop_breakDownHexChar :: Property+prop_breakDownHexChar = withTests 1 $ property $+ functionEq every Hex.breakDownHexChar $ \case+ Hex.Digit0 -> Hex.HexDigit Dec.D0+ Hex.Digit1 -> Hex.HexDigit Dec.D1+ Hex.Digit2 -> Hex.HexDigit Dec.D2+ Hex.Digit3 -> Hex.HexDigit Dec.D3+ Hex.Digit4 -> Hex.HexDigit Dec.D4+ Hex.Digit5 -> Hex.HexDigit Dec.D5+ Hex.Digit6 -> Hex.HexDigit Dec.D6+ Hex.Digit7 -> Hex.HexDigit Dec.D7+ Hex.Digit8 -> Hex.HexDigit Dec.D8+ Hex.Digit9 -> Hex.HexDigit Dec.D9+ Hex.CapitalLetterA -> Hex.HexLetter UpperCase Hex.LetterA+ Hex.CapitalLetterB -> Hex.HexLetter UpperCase Hex.LetterB+ Hex.CapitalLetterC -> Hex.HexLetter UpperCase Hex.LetterC+ Hex.CapitalLetterD -> Hex.HexLetter UpperCase Hex.LetterD+ Hex.CapitalLetterE -> Hex.HexLetter UpperCase Hex.LetterE+ Hex.CapitalLetterF -> Hex.HexLetter UpperCase Hex.LetterF+ Hex.SmallLetterA -> Hex.HexLetter LowerCase Hex.LetterA+ Hex.SmallLetterB -> Hex.HexLetter LowerCase Hex.LetterB+ Hex.SmallLetterC -> Hex.HexLetter LowerCase Hex.LetterC+ Hex.SmallLetterD -> Hex.HexLetter LowerCase Hex.LetterD+ Hex.SmallLetterE -> Hex.HexLetter LowerCase Hex.LetterE+ Hex.SmallLetterF -> Hex.HexLetter LowerCase Hex.LetterF++prop_assembleHexChar :: Property+prop_assembleHexChar = withTests 1 $ property $+ functionEq every Hex.assembleHexChar $+ I.bijection I.linearSearchLazy every Hex.breakDownHexChar++prop_hexCharNatural :: Property+prop_hexCharNatural = withTests 1 $ property $+ functionEq every Hex.hexCharNatural $ \case+ Hex.Digit0 -> 0+ Hex.Digit1 -> 1+ Hex.Digit2 -> 2+ Hex.Digit3 -> 3+ Hex.Digit4 -> 4+ Hex.Digit5 -> 5+ Hex.Digit6 -> 6+ Hex.Digit7 -> 7+ Hex.Digit8 -> 8+ Hex.Digit9 -> 9+ Hex.CapitalLetterA -> 10+ Hex.CapitalLetterB -> 11+ Hex.CapitalLetterC -> 12+ Hex.CapitalLetterD -> 13+ Hex.CapitalLetterE -> 14+ Hex.CapitalLetterF -> 15+ Hex.SmallLetterA -> 10+ Hex.SmallLetterB -> 11+ Hex.SmallLetterC -> 12+ Hex.SmallLetterD -> 13+ Hex.SmallLetterE -> 14+ Hex.SmallLetterF -> 15++prop_naturalHexCharMaybe :: Property+prop_naturalHexCharMaybe = withTests 1 $ property $+ functionEq (liftA2 (,) every [0 .. 20]) (uncurry Hex.naturalHexCharMaybe) $ \case+ (_, 0) -> Just Hex.Digit0+ (_, 1) -> Just Hex.Digit1+ (_, 2) -> Just Hex.Digit2+ (_, 3) -> Just Hex.Digit3+ (_, 4) -> Just Hex.Digit4+ (_, 5) -> Just Hex.Digit5+ (_, 6) -> Just Hex.Digit6+ (_, 7) -> Just Hex.Digit7+ (_, 8) -> Just Hex.Digit8+ (_, 9) -> Just Hex.Digit9+ (UpperCase, 10) -> Just Hex.CapitalLetterA+ (UpperCase, 11) -> Just Hex.CapitalLetterB+ (UpperCase, 12) -> Just Hex.CapitalLetterC+ (UpperCase, 13) -> Just Hex.CapitalLetterD+ (UpperCase, 14) -> Just Hex.CapitalLetterE+ (UpperCase, 15) -> Just Hex.CapitalLetterF+ (LowerCase, 10) -> Just Hex.SmallLetterA+ (LowerCase, 11) -> Just Hex.SmallLetterB+ (LowerCase, 12) -> Just Hex.SmallLetterC+ (LowerCase, 13) -> Just Hex.SmallLetterD+ (LowerCase, 14) -> Just Hex.SmallLetterE+ (LowerCase, 15) -> Just Hex.SmallLetterF+ _ -> Nothing++prop_hexCharInteger :: Property+prop_hexCharInteger = withTests 1 $ property $+ functionEq every Hex.hexCharInteger $ \case+ Hex.Digit0 -> 0+ Hex.Digit1 -> 1+ Hex.Digit2 -> 2+ Hex.Digit3 -> 3+ Hex.Digit4 -> 4+ Hex.Digit5 -> 5+ Hex.Digit6 -> 6+ Hex.Digit7 -> 7+ Hex.Digit8 -> 8+ Hex.Digit9 -> 9+ Hex.CapitalLetterA -> 10+ Hex.CapitalLetterB -> 11+ Hex.CapitalLetterC -> 12+ Hex.CapitalLetterD -> 13+ Hex.CapitalLetterE -> 14+ Hex.CapitalLetterF -> 15+ Hex.SmallLetterA -> 10+ Hex.SmallLetterB -> 11+ Hex.SmallLetterC -> 12+ Hex.SmallLetterD -> 13+ Hex.SmallLetterE -> 14+ Hex.SmallLetterF -> 15++prop_integerHexCharMaybe :: Property+prop_integerHexCharMaybe = withTests 1 $ property $+ functionEq (liftA2 (,) every [-4 .. 20]) (uncurry Hex.integerHexCharMaybe) $ \case+ (_, 0) -> Just Hex.Digit0+ (_, 1) -> Just Hex.Digit1+ (_, 2) -> Just Hex.Digit2+ (_, 3) -> Just Hex.Digit3+ (_, 4) -> Just Hex.Digit4+ (_, 5) -> Just Hex.Digit5+ (_, 6) -> Just Hex.Digit6+ (_, 7) -> Just Hex.Digit7+ (_, 8) -> Just Hex.Digit8+ (_, 9) -> Just Hex.Digit9+ (UpperCase, 10) -> Just Hex.CapitalLetterA+ (UpperCase, 11) -> Just Hex.CapitalLetterB+ (UpperCase, 12) -> Just Hex.CapitalLetterC+ (UpperCase, 13) -> Just Hex.CapitalLetterD+ (UpperCase, 14) -> Just Hex.CapitalLetterE+ (UpperCase, 15) -> Just Hex.CapitalLetterF+ (LowerCase, 10) -> Just Hex.SmallLetterA+ (LowerCase, 11) -> Just Hex.SmallLetterB+ (LowerCase, 12) -> Just Hex.SmallLetterC+ (LowerCase, 13) -> Just Hex.SmallLetterD+ (LowerCase, 14) -> Just Hex.SmallLetterE+ (LowerCase, 15) -> Just Hex.SmallLetterF+ _ -> Nothing++prop_naturalD16Maybe :: Property+prop_naturalD16Maybe = withTests 1 $ property $+ functionEq [0 .. 20] Hex.naturalD16Maybe $+ I.injection I.linearSearchLazy every Hex.d16Natural++prop_integerD16Maybe :: Property+prop_integerD16Maybe = withTests 1 $ property $+ functionEq [-4 .. 20] Hex.integerD16Maybe $+ I.injection I.linearSearchLazy every Hex.d16Integer++prop_naturalD16Unsafe :: Property+prop_naturalD16Unsafe = withTests 1 $ property $+ functionEq [0 .. 15]+ (Just . Hex.naturalD16Unsafe)+ Hex.naturalD16Maybe++prop_integerD16Unsafe :: Property+prop_integerD16Unsafe = withTests 1 $ property $+ functionEq [0 .. 15]+ (Just . Hex.integerD16Unsafe)+ Hex.integerD16Maybe++prop_naturalHexCharUnsafe :: Property+prop_naturalHexCharUnsafe = withTests 1 $ property $+ functionEq (liftA2 (,) every [0 .. 15])+ (Just . uncurry Hex.naturalHexCharUnsafe)+ (uncurry Hex.naturalHexCharMaybe)++prop_integerHexCharUnsafe :: Property+prop_integerHexCharUnsafe = withTests 1 $ property $+ functionEq (liftA2 (,) every [0 .. 15])+ (Just . uncurry Hex.integerHexCharUnsafe)+ (uncurry Hex.integerHexCharMaybe)++prop_hex_showNatural_lower_12 :: Property+prop_hex_showNatural_lower_12 = withTests 1 $ property $+ Hex.showNatural LowerCase 12 === ("c" :: LBS.ByteString)++prop_hex_showNatural_upper_10C :: Property+prop_hex_showNatural_upper_10C = withTests 1 $ property $+ Hex.showNatural UpperCase (256 + 12) === ("10C" :: BS.ByteString)++prop_hex_showNatural_upper_0 :: Property+prop_hex_showNatural_upper_0 = withTests 1 $ property $+ Hex.showNatural UpperCase 0 === ("0" :: LBS.ByteString)++prop_hex_showInteger_lower_12 :: Property+prop_hex_showInteger_lower_12 = withTests 1 $ property $+ Hex.showInteger LowerCase 12 === ("c" :: T.Text)++prop_hex_showInteger_lower_minus12 :: Property+prop_hex_showInteger_lower_minus12 = withTests 1 $ property $+ Hex.showInteger LowerCase (negate 12) === ("-c" :: LT.Text)++prop_hex_showInteger_upper_10C :: Property+prop_hex_showInteger_upper_10C = withTests 1 $ property $+ Hex.showInteger UpperCase (256 + 12) === ("10C" :: String)++prop_hex_showInteger_upper_minus10C :: Property+prop_hex_showInteger_upper_minus10C = withTests 1 $ property $+ Hex.showInteger UpperCase (negate (256 + 12)) === ("-10C" :: BS.ByteString)++prop_hex_showInteger_upper_0 :: Property+prop_hex_showInteger_upper_0 = withTests 1 $ property $+ Hex.showInteger UpperCase 0 === ("0" :: String)++prop_hex_readNatural_5 :: Property+prop_hex_readNatural_5 = withTests 1 $ property $+ Hex.readNatural ("5" :: String) === Just 5++prop_hex_readNatural_minus5 :: Property+prop_hex_readNatural_minus5 = withTests 1 $ property $+ Hex.readNatural ("-5" :: T.Text) === Nothing++prop_hex_readNatural_1f :: Property+prop_hex_readNatural_1f = withTests 1 $ property $+ Hex.readNatural ("1f" :: BS.ByteString) === Just 31++prop_hex_readNatural_1F :: Property+prop_hex_readNatural_1F = withTests 1 $ property $+ Hex.readNatural ("1F" :: LT.Text) === Just 31++prop_hex_readNatural_xa :: Property+prop_hex_readNatural_xa = withTests 1 $ property $+ Hex.readNatural ("xa" :: String) === Nothing++prop_hex_readNatural_empty :: Property+prop_hex_readNatural_empty = withTests 1 $ property $+ Hex.readNatural ("" :: T.Text) === Nothing++prop_hex_readInteger_5 :: Property+prop_hex_readInteger_5 = withTests 1 $ property $+ Hex.readInteger ("5" :: T.Text) === Just 5++prop_hex_readInteger_minus5 :: Property+prop_hex_readInteger_minus5 = withTests 1 $ property $+ Hex.readInteger ("-5" :: T.Text) === Just (-5)++prop_hex_readInteger_1f :: Property+prop_hex_readInteger_1f = withTests 1 $ property $+ Hex.readInteger ("1f" :: LT.Text) === Just 31++prop_hex_readInteger_1F :: Property+prop_hex_readInteger_1F = withTests 1 $ property $+ Hex.readInteger ("1F" :: LT.Text) === Just 31++prop_hex_readInteger_xa :: Property+prop_hex_readInteger_xa = withTests 1 $ property $+ Hex.readInteger ("xa" :: String) === Nothing++prop_hex_readInteger_empty :: Property+prop_hex_readInteger_empty = withTests 1 $ property $+ Hex.readInteger ("" :: String) === Nothing++prop_hex_readInteger_minus :: Property+prop_hex_readInteger_minus = withTests 1 $ property $+ Hex.readInteger ("-" :: String) === Nothing++prop_hex_readIntegral_word8_0014 :: Property+prop_hex_readIntegral_word8_0014 = withTests 1 $ property $+ Hex.readIntegral ("0014" :: String) === Just (20 :: Word8)++prop_hex_readIntegral_word8_empty :: Property+prop_hex_readIntegral_word8_empty = withTests 1 $ property $+ Hex.readIntegral ("" :: String) === (Nothing :: Maybe Word8)++prop_hex_readIntegral_word8_minus4 :: Property+prop_hex_readIntegral_word8_minus4 = withTests 1 $ property $+ Hex.readIntegral ("-4" :: String) === (Nothing :: Maybe Word8)++prop_hex_readIntegral_word8_1234 :: Property+prop_hex_readIntegral_word8_1234 = withTests 1 $ property $+ Hex.readIntegral ("1234" :: String) === (Nothing :: Maybe Word8)++checkReadShow :: forall string number f.+ (Monad f, Eq number, Show number, Eq string, Show string) =>+ Gen number -> (number -> string) -> (string -> Maybe number) -> PropertyT f ()+checkReadShow g s r =+ do+ x <- forAll g+ r (s x) === Just x++prop_readShow_dec_integer_text :: Property+prop_readShow_dec_integer_text = property $+ checkReadShow @T.Text @Integer genInteger Dec.showInteger Dec.readInteger++prop_readShow_dec_integer_string :: Property+prop_readShow_dec_integer_string = property $+ checkReadShow @String @Integer genInteger Dec.showInteger Dec.readInteger++prop_readShow_dec_integer_byteString :: Property+prop_readShow_dec_integer_byteString = property $+ checkReadShow @BS.ByteString @Integer genInteger Dec.showInteger Dec.readInteger++prop_readShow_dec_natural :: Property+prop_readShow_dec_natural = property $+ checkReadShow @T.Text @Natural genNatural Dec.showNatural Dec.readNatural++prop_readShow_dec_word8 :: Property+prop_readShow_dec_word8 = property $+ checkReadShow @T.Text @Word8 genWord8 Dec.showIntegral Dec.readIntegral++prop_readShow_hex_integer_text :: Property+prop_readShow_hex_integer_text = property $ do+ c <- forAll genCase+ checkReadShow @T.Text @Integer genInteger (Hex.showInteger c) Hex.readInteger++prop_readShow_hex_integer_string :: Property+prop_readShow_hex_integer_string = property $ do+ c <- forAll genCase+ checkReadShow @String @Integer genInteger (Hex.showInteger c) Hex.readInteger++prop_readShow_hex_integer_byteString :: Property+prop_readShow_hex_integer_byteString = property $ do+ c <- forAll genCase+ checkReadShow @BS.ByteString @Integer genInteger (Hex.showInteger c) Hex.readInteger++prop_readShow_hex_natural :: Property+prop_readShow_hex_natural = property $ do+ c <- forAll genCase+ checkReadShow @T.Text @Natural genNatural (Hex.showNatural c) Hex.readNatural++prop_readShow_hex_word8 :: Property+prop_readShow_hex_word8 = property $ do+ c <- forAll genCase+ checkReadShow @T.Text @Word8 genWord8 (Hex.showIntegral c) Hex.readIntegral++genNatural :: Gen Natural+genNatural = Gen.integral (Range.exponential 0 10000)++genInteger :: Gen Integer+genInteger = Gen.integral (Range.exponentialFrom 0 (-10000) 10000)++genWord8 :: Gen Word8+genWord8 = Gen.integral (Range.linear minBound maxBound)++genCase :: Gen Case+genCase = Gen.element [UpperCase, LowerCase]