packages feed

ttc 0.3.0.0 → 0.4.0.0

raw patch · 7 files changed

+433/−47 lines, 7 filesdep ~template-haskellPVP ok

version bump matches the API change (PVP)

Dependency ranges changed: template-haskell

API changes (from Hackage documentation)

+ Data.TTC: renderBSB :: Render a => a -> Builder
+ Data.TTC: renderSBS :: Render a => a -> ShortByteString
+ Data.TTC: renderTLB :: Render a => a -> Builder
- Data.TTC: parseEnum' :: (Bounded a, Enum a, Render a, Textual t) => String -> Bool -> Bool -> t -> Either String a
+ Data.TTC: parseEnum' :: (Bounded a, Enum a, Render a, Textual t, Textual e) => String -> Bool -> Bool -> t -> Either e a

Files

CHANGELOG.md view
@@ -24,6 +24,22 @@  [KaC]: <https://keepachangelog.com/en/1.0.0/> +## 0.4.0.0 (2021-03-27)++### Breaking++* Add support for GHC 9+* Add `renderTLB`, `renderBSB`, and `renderSBS` functions+* Use `Textual` error messages for `parseEnum'`++### Non-Breaking++* Add `@since` annotations+* Rename Git default branch to `main`+* Use GitHub Actions instead of Travis CI+* Add Cabal tests to GitHub Actions+* Add [stan](https://hackage.haskell.org/package/stan) static analysis+ ## 0.3.0.0 (2020-11-03)  ### Breaking
LICENSE view
@@ -1,6 +1,6 @@ The MIT License -Copyright (c) 2019-2020 Travis Cardwell+Copyright (c) 2019-2021 Travis Cardwell  Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal
README.md view
@@ -1,6 +1,6 @@ # TTC: Textual Type Classes -[![Build Status](https://travis-ci.com/ExtremaIS/ttc-haskell.svg?branch=master)](https://travis-ci.com/ExtremaIS/ttc-haskell)+[![GitHub CI](https://github.com/ExtremaIS/ttc-haskell/workflows/CI/badge.svg?branch=main)](https://github.com/ExtremaIS/ttc-haskell/actions) [![Hackage](https://img.shields.io/hackage/v/ttc.svg)](https://hackage.haskell.org/package/ttc) [![Stackage LTS](https://stackage.org/package/ttc/badge/lts)](https://stackage.org/package/ttc) [![Stackage Nightly](https://stackage.org/package/ttc/badge/nightly)](https://stackage.org/nightly/package/ttc)@@ -100,7 +100,7 @@  ```haskell instance TTC.Parse Username where-  parse = TTC.asT $ \t-> first TTC.fromS $ do+  parse = TTC.asT $ \t -> first TTC.fromS $ do     unless (T.all isAsciiLower t) $ Left "username has invalid character(s)"     let len = T.length t     when (len < 3) $ Left "username has fewer than 3 characters"@@ -212,7 +212,7 @@ * Hackage: <https://hackage.haskell.org/package/ttc> * Stackage: <https://stackage.org/package/ttc> * GitHub: <https://github.com/ExtremaIS/ttc-haskell>-* Travis CI: <https://travis-ci.com/ExtremaIS/ttc-haskell>+* GitHub Actions CI: <https://github.com/ExtremaIS/ttc-haskell/actions>  ### Dependencies @@ -223,7 +223,7 @@  ### Releases -All releases are tagged in the `master` branch.  Release tags are signed using+All releases are tagged in the `main` branch.  Release tags are signed using the [`security@extrema.is` GPG key](http://keys.gnupg.net/pks/lookup?op=vindex&fingerprint=on&search=0x1D484E4B4705FADF). 
src/Data/TTC.hs view
@@ -2,7 +2,7 @@ -- | -- Module      : Data.TTC -- Description : textual type classes--- Copyright   : Copyright (c) 2019-2020 Travis Cardwell+-- Copyright   : Copyright (c) 2019-2021 Travis Cardwell -- License     : MIT -- -- TTC, an initialism of /Textual Type Classes/, is a library that provides@@ -16,9 +16,14 @@ -- @ ------------------------------------------------------------------------------ +{-# LANGUAGE CPP #-} {-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE TemplateHaskell #-} +#if __GLASGOW_HASKELL__ >= 900+{-# LANGUAGE ExplicitForAll #-}+#endif+ module Data.TTC   ( -- * Textual     Textual@@ -61,6 +66,9 @@   , renderTL   , renderBS   , renderBSL+  , renderTLB+  , renderBSB+  , renderSBS     -- ** Render Utilities   , renderWithShow     -- * Parse@@ -97,6 +105,7 @@   , readsEnum   , readsWithParse     -- ** Constant Validation+    -- $ParseValid   , valid   , validOf   , mkValid@@ -153,23 +162,37 @@ -- writing instances.  Adding support for additional data types would require -- changing the class definition itself.  This is the price paid for having -- only one type variable instead of two.+--+-- @since 0.1.0.0 class Textual t where   -- | Convert to a 'String'+  --+  -- @since 0.1.0.0   toS :: t -> String    -- | Convert to strict 'T.Text'+  --+  -- @since 0.1.0.0   toT :: t -> T.Text    -- | Convert to lazy 'TL.Text'+  --+  -- @since 0.1.0.0   toTL :: t -> TL.Text    -- | Convert to a strict 'BS.ByteString'+  --+  -- @since 0.1.0.0   toBS :: t -> BS.ByteString    -- | Convert to a lazy 'BS.ByteString'+  --+  -- @since 0.1.0.0   toBSL :: t -> BSL.ByteString    -- | Convert between any supported textual data types+  --+  -- @since 0.1.0.0   convert :: Textual t' => t' -> t  instance Textual String where@@ -242,6 +265,7 @@   {-# INLINE toBSL #-}   {-# INLINE convert #-} +------------------------------------------------------------------------------ -- $TextualTo -- -- These functions are equivalent to 'convert', but they specify the type@@ -255,30 +279,41 @@ -- in cases where the type is ambiguous.  -- | Convert from a 'String'+--+-- @since 0.1.0.0 fromS :: Textual t => String -> t fromS = convert {-# INLINE fromS #-}  -- | Convert from strict 'T.Text'+--+-- @since 0.1.0.0 fromT :: Textual t => T.Text -> t fromT = convert {-# INLINE fromT #-}  -- | Convert from lazy 'TL.Text'+--+-- @since 0.1.0.0 fromTL :: Textual t => TL.Text -> t fromTL = convert {-# INLINE fromTL #-}  -- | Convert from a strict 'BS.ByteString'+--+-- @since 0.1.0.0 fromBS :: Textual t => BS.ByteString -> t fromBS = convert {-# INLINE fromBS #-}  -- | Convert from a lazy 'BSL.ByteString'+--+-- @since 0.1.0.0 fromBSL :: Textual t => BSL.ByteString -> t fromBSL = convert {-# INLINE fromBSL #-} +------------------------------------------------------------------------------ -- $TextualAs -- -- These functions are used to convert a 'Textual' argument of a function to a@@ -286,30 +321,41 @@ -- definitions.  -- | Convert an argument to a 'String'+--+-- @since 0.1.0.0 asS :: Textual t => (String -> a) -> t -> a asS f = f . convert {-# INLINE asS #-}  -- | Convert an argument to strict 'T.Text'+--+-- @since 0.1.0.0 asT :: Textual t => (T.Text -> a) -> t -> a asT f = f . convert {-# INLINE asT #-}  -- | Convert an argument to lazy 'TL.Text'+--+-- @since 0.1.0.0 asTL :: Textual t => (TL.Text -> a) -> t -> a asTL f = f . convert {-# INLINE asTL #-}  -- | Convert an argument to a strict 'BS.ByteString'+--+-- @since 0.1.0.0 asBS :: Textual t => (BS.ByteString -> a) -> t -> a asBS f = f . convert {-# INLINE asBS #-}  -- | Convert an argument to a lazy 'BSL.ByteString'+--+-- @since 0.1.0.0 asBSL :: Textual t => (BSL.ByteString -> a) -> t -> a asBSL f = f . convert {-# INLINE asBSL #-} +------------------------------------------------------------------------------ -- $TextualOther -- -- These functions are used to convert to/from the following other textual@@ -320,26 +366,38 @@ -- * 'SBS.ShortByteString' (@SBS@)  -- | Convert to a @Text@ 'TLB.Builder'+--+-- @since 0.1.0.0 toTLB :: Textual t => t -> TLB.Builder toTLB = TLB.fromLazyText . convert  -- | Convert from a @Text@ 'TLB.Builder'+--+-- @since 0.1.0.0 fromTLB :: Textual t => TLB.Builder -> t fromTLB = convert . TLB.toLazyText  -- | Convert to a @ByteString@ 'BSB.Builder'+--+-- @since 0.1.0.0 toBSB :: Textual t => t -> BSB.Builder toBSB = BSB.lazyByteString . convert  -- | Convert from a @ByteString@ 'BSB.Builder'+--+-- @since 0.1.0.0 fromBSB :: Textual t => BSB.Builder -> t fromBSB = convert . BSB.toLazyByteString  -- | Convert to a 'SBS.ShortByteString'+--+-- @since 0.1.0.0 toSBS :: Textual t => t -> SBS.ShortByteString toSBS = SBS.toShort . convert  -- | Convert from a 'SBS.ShortByteString'+--+-- @since 0.1.0.0 fromSBS :: Textual t => SBS.ShortByteString -> t fromSBS = convert . SBS.fromShort @@ -353,9 +411,12 @@ -- basic data types are available in "Data.TTC.Instances". -- -- See the @uname@ and @prompt@ example programs in the @examples@ directory.+--+-- @since 0.1.0.0 class Render a where   render :: Textual t => a -> t +------------------------------------------------------------------------------ -- $RenderSpecific -- -- These functions are equivalent to 'render', but they specify the type being@@ -363,33 +424,67 @@ -- where the type is ambiguous.  -- | Render to a 'String'+--+-- @since 0.1.0.0 renderS :: Render a => a -> String renderS = render {-# INLINE renderS #-}  -- | Render to strict 'T.Text'+--+-- @since 0.1.0.0 renderT :: Render a => a -> T.Text renderT = render {-# INLINE renderT #-}  -- | Render to lazy 'TL.Text'+--+-- @since 0.1.0.0 renderTL :: Render a => a -> TL.Text renderTL = render {-# INLINE renderTL #-}  -- | Render to a strict 'BS.ByteString'+--+-- @since 0.1.0.0 renderBS :: Render a => a -> BS.ByteString renderBS = render {-# INLINE renderBS #-}  -- | Render to a lazy 'BSL.ByteString'+--+-- @since 0.1.0.0 renderBSL :: Render a => a -> BSL.ByteString renderBSL = render {-# INLINE renderBSL #-} +-- | Render to a @Text@ 'TLB.Builder'+--+-- @since 0.4.0.0+renderTLB :: Render a => a -> TLB.Builder+renderTLB = TLB.fromLazyText . renderTL+{-# INLINE renderTLB #-}++-- | Render to a @ByteString@ 'BSB.Builder'+--+-- @since 0.4.0.0+renderBSB :: Render a => a -> BSB.Builder+renderBSB = BSB.lazyByteString . renderBSL+{-# INLINE renderBSB #-}++-- | Render to a 'SBS.ShortByteString'+--+-- @since 0.4.0.0+renderSBS :: Render a => a -> SBS.ShortByteString+renderSBS = SBS.toShort . renderBS+{-# INLINE renderSBS #-}++------------------------------------------------------------------------------ -- $RenderUtils  -- | Render a value to a textual data type using the 'Show' instance+--+-- @since 0.1.0.0 renderWithShow :: (Show a, Textual t) => a -> t renderWithShow = convert . show {-# INLINE renderWithShow #-}@@ -404,15 +499,20 @@ -- basic data types are available in "Data.TTC.Instances". -- -- See the @uname@ and @prompt@ example programs in the @examples@ directory.+--+-- @since 0.3.0.0 class Parse a where   parse :: (Textual t, Textual e) => t -> Either e a  -- This function is equivalent to 'parse' with the error type fixed to -- 'String', used internally when the error is ignored.+--+-- @since 0.3.0.0 parse' :: (Parse a, Textual t) => t -> Either String a parse' = parse {-# INLINE parse' #-} +------------------------------------------------------------------------------ -- $ParseSpecific -- -- These functions are equivalent to 'parse', but they specify the type being@@ -420,30 +520,41 @@ -- where the type is ambiguous.  -- | Parse from a 'String'+--+-- @since 0.3.0.0 parseS :: (Parse a, Textual e) => String -> Either e a parseS = parse {-# INLINE parseS #-}  -- | Parse from strict 'T.Text'+--+-- @since 0.3.0.0 parseT :: (Parse a, Textual e) => T.Text -> Either e a parseT = parse {-# INLINE parseT #-}  -- | Parse from lazy 'TL.Text'+--+-- @since 0.3.0.0 parseTL :: (Parse a, Textual e) => TL.Text -> Either e a parseTL = parse {-# INLINE parseTL #-}  -- | Parse from a strict 'BS.ByteString'+--+-- @since 0.3.0.0 parseBS :: (Parse a, Textual e) => BS.ByteString -> Either e a parseBS = parse {-# INLINE parseBS #-}  -- | Parse from a lazy 'BSL.ByteString'+--+-- @since 0.3.0.0 parseBSL :: (Parse a, Textual e) => BSL.ByteString -> Either e a parseBSL = parse {-# INLINE parseBSL #-} +------------------------------------------------------------------------------ -- $ParseMaybe -- -- The 'parseMaybe' function parses to a 'Maybe' type instead of an 'Either'@@ -452,35 +563,48 @@ -- annotations in cases where the type is ambiguous.  -- | Parse to a 'Maybe' type+--+-- @since 0.3.0.0 parseMaybe :: (Parse a, Textual t) => t -> Maybe a parseMaybe = either (const Nothing) Just . parse' {-# INLINE parseMaybe #-}  -- | Parse from a 'String' to a 'Maybe' type+--+-- @since 0.3.0.0 parseMaybeS :: Parse a => String -> Maybe a parseMaybeS = parseMaybe {-# INLINE parseMaybeS #-}  -- | Parse from strict 'T.Text' to a 'Maybe' type+--+-- @since 0.3.0.0 parseMaybeT :: Parse a => T.Text -> Maybe a parseMaybeT = parseMaybe {-# INLINE parseMaybeT #-}  -- | Parse from lazy 'TL.Text' to a 'Maybe' type+--+-- @since 0.3.0.0 parseMaybeTL :: Parse a => TL.Text -> Maybe a parseMaybeTL = parseMaybe {-# INLINE parseMaybeTL #-}  -- | Parse from a strict 'BS.ByteString' to a 'Maybe' type+--+-- @since 0.3.0.0 parseMaybeBS :: Parse a => BS.ByteString -> Maybe a parseMaybeBS = parseMaybe {-# INLINE parseMaybeBS #-}  -- | Parse from a lazy 'BSL.ByteString' to a 'Maybe' type+--+-- @since 0.3.0.0 parseMaybeBSL :: Parse a => BSL.ByteString -> Maybe a parseMaybeBSL = parseMaybe {-# INLINE parseMaybeBSL #-} +------------------------------------------------------------------------------ -- $ParseUnsafe -- -- The 'parseUnsafe' function raises an exception on error instead of using an@@ -490,35 +614,48 @@ -- in cases where the type is ambiguous.  -- | Unsafely parse+--+-- @since 0.1.0.0 parseUnsafe :: (Parse a, Textual t) => t -> a parseUnsafe = either (error . ("parseUnsafe: " ++)) id . parse {-# INLINE parseUnsafe #-}  -- | Unsafely parse to a 'String'+--+-- @since 0.1.0.0 parseUnsafeS :: Parse a => String -> a parseUnsafeS = parseUnsafe {-# INLINE parseUnsafeS #-}  -- | Unsafely parse to strict 'T.Text'+--+-- @since 0.1.0.0 parseUnsafeT :: Parse a => T.Text -> a parseUnsafeT = parseUnsafe {-# INLINE parseUnsafeT #-}  -- | Unsafely parse to lazy 'TL.Text'+--+-- @since 0.1.0.0 parseUnsafeTL :: Parse a => TL.Text -> a parseUnsafeTL = parseUnsafe {-# INLINE parseUnsafeTL #-}  -- | Unsafely parse to a strict 'BS.ByteString'+--+-- @since 0.1.0.0 parseUnsafeBS :: Parse a => BS.ByteString -> a parseUnsafeBS = parseUnsafe {-# INLINE parseUnsafeBS #-}  -- | Unsafely parse to a lazy 'BSL.ByteString'+--+-- @since 0.1.0.0 parseUnsafeBSL :: Parse a => BSL.ByteString -> a parseUnsafeBSL = parseUnsafe {-# INLINE parseUnsafeBSL #-} +------------------------------------------------------------------------------ -- $ParseUtils  -- | Parse a value in an enumeration@@ -527,6 +664,8 @@ -- the implementation uses a linear algorithm. -- -- See the @enum@ example program in the @examples@ directory.+--+-- @since 0.1.0.0 parseEnum   :: (Bounded a, Enum a, Render a, Textual t)   => Bool        -- ^ case-insensitive when 'True'@@ -540,7 +679,7 @@     in  case [v | v <- [minBound ..], t' `match` norm (render v)] of           [v] -> Right v           []  -> Left invalidError-          _   -> Left ambiguousError+          _vs -> Left ambiguousError   where     norm :: T.Text -> T.Text     norm = if allowCI then T.toLower else id@@ -548,24 +687,31 @@     match :: T.Text -> T.Text -> Bool     match = if allowPrefix then T.isPrefixOf else (==) --- | Parse a value in an enumeration, with 'String' error messages+-- | Parse a value in an enumeration, with 'Textual' error messages -- -- The following English error messages are returned: -- -- * \"invalid {name}\" when there are no matches -- * \"ambiguous {name}\" when there is more than one match+--+-- @since 0.4.0.0 parseEnum'-  :: (Bounded a, Enum a, Render a, Textual t)-  => String           -- ^ name to include in error messages-  -> Bool             -- ^ case-insensitive when 'True'-  -> Bool             -- ^ accept unique prefixes when 'True'-  -> t                -- ^ textual input to parse-  -> Either String a  -- ^ error or parsed value+  :: (Bounded a, Enum a, Render a, Textual t, Textual e)+  => String      -- ^ name to include in error messages+  -> Bool        -- ^ case-insensitive when 'True'+  -> Bool        -- ^ accept unique prefixes when 'True'+  -> t           -- ^ textual input to parse+  -> Either e a  -- ^ error or parsed value parseEnum' name allowCI allowPrefix =-    parseEnum allowCI allowPrefix ("invalid " ++ name) ("ambiguous " ++ name)+    parseEnum+      allowCI allowPrefix+      (fromS $ "invalid " ++ name)+      (fromS $ "ambiguous " ++ name) {-# INLINEABLE parseEnum' #-}  -- | Parse a value using the 'Read' instance+--+-- @since 0.1.0.0 parseWithRead   :: (Read a, Textual t)   => e           -- ^ invalid input error@@ -574,11 +720,13 @@ parseWithRead invalidError = maybe (Left invalidError) Right . readMaybe . toS {-# INLINEABLE parseWithRead #-} --- | Parse a value using the 'Read' instance, with 'String' error messages+-- | Parse a value using the 'Read' instance, with 'Textual' error messages -- -- The following English error message is returned: -- -- * \"invalid {name}\" when the parse fails+--+-- @since 0.3.0.0 parseWithRead'   :: (Read a, Textual t, Textual e)   => String      -- ^ name to include in error messages@@ -588,6 +736,8 @@ {-# INLINEABLE parseWithRead' #-}  -- | Parse a value to a 'Maybe' type using the 'Read' instance+--+-- @since 0.3.0.0 maybeParseWithRead   :: (Read a, Textual t)   => t           -- ^ textual input to parse@@ -597,6 +747,8 @@ -- | Implement 'ReadS' using 'parseEnum' -- -- This implementation expects all of the input to be consumed.+--+-- @since 0.1.0.0 readsEnum   :: (Bounded a, Enum a, Render a)   => Bool  -- ^ case-insensitive when 'True'@@ -611,6 +763,8 @@ -- | Implement 'ReadS' using a 'Parse' instance -- -- This implementation expects all of the input to be consumed.+--+-- @since 0.3.0.0 readsWithParse   :: Parse a   => ReadS a@@ -619,7 +773,26 @@     Nothing -> [] {-# INLINEABLE readsWithParse #-} +------------------------------------------------------------------------------ -- $ParseValid+--+-- The follow functions provide a number of ways to use a 'Parse' instance to+-- validate constants at compile-time.+--+-- If you can use Template Haskell typed expressions in your project, use+-- 'valid', 'mkValid', or 'validOf'.  Use 'valid' to define constants for+-- types that have a 'THS.Lift' instance.  For types that do not have a+-- 'THS.Lift' instance, use 'mkValid' to define a validation function for that+-- type using a 'Proxy', or use 'validOf' to pass the 'Proxy' when defining+-- constants.+--+-- Typed expressions were not supported in @haskell-src-exts <1.22.0@, which+-- causes problems with old versions of @hlint@.  If the issue affects you,+-- you may use 'mkUntypedValid', 'mkUntypedValidQQ', or 'untypedValidOf'+-- instead of the above functions.  Use 'mkUntypedValid' to define a+-- validation function for a type using a 'Proxy', or use 'untypedValidOf' to+-- pass the 'Proxy' when defining constants.  Alternatively, use+-- 'mkUntypedValidQQ' to define a validation quasi-quoter.  -- | Validate a constant at compile-time using a 'Parse' instance --@@ -628,20 +801,61 @@ -- a 'THS.Lift' instance.  When this is inconvenient, use one of the -- alternative functions in this library. ----- This function uses a typed expression.  Typed expressions were not--- supported in @haskell-src-exts <1.22.0@, which caused problems with--- @hlint@.  If the issue effects you, use @hlint -i "Parse error"@ to ignore--- parse errors or use one of the alternative functions in this library.+-- This function uses a Template Haskell typed expression.  Typed expressions+-- were not supported in @haskell-src-exts <1.22.0@, which causes problems+-- with old versions of @hlint@.  If the issue affects you, use+-- @hlint -i "Parse error"@ to ignore parse errors or use one of the+-- alternative functions in this library. ----- See the @valid@, @invalid@, and @lift@ example programs in the @examples@--- directory.+-- Note that the typed Template Haskell API changed in GHC 9.  The type+-- displayed in this documentation is determined by the version of GHC used to+-- build the documentation.+--+-- The type of this function in GHC 9 or later is as follows:+--+-- @+-- valid+--   :: (MonadFail m, THS.Quote m, Parse a, THS.Lift a)+--   => String+--   -> THS.Code m a+-- @+--+-- The type of this function in previous versions of GHC is as follows:+--+-- @+-- valid+--   :: (Parse a, THS.Lift a)+--   => String+--   -> TH.Q (TH.TExp a)+-- @+--+-- This function is used the same way in all GHC versions.  See the @valid@,+-- @invalid@, and @lift@ example programs in the @examples@ directory.  The+-- following is example usage from the @valid@ example:+--+-- @+-- sample :: Username+-- sample = $$(TTC.valid "tcard")+-- @+--+-- @since 0.1.0.0+#if __GLASGOW_HASKELL__ >= 900 valid+  :: (MonadFail m, THS.Quote m, Parse a, THS.Lift a)+  => String+  -> THS.Code m a+valid s = case parse s of+    Right x -> [|| x ||]+    Left err -> THS.Code . fail $ "Invalid constant: " ++ err+#else+valid   :: (Parse a, THS.Lift a)   => String   -> TH.Q (TH.TExp a) valid s = case parse s of     Right x -> [|| x ||]     Left err -> fail $ "Invalid constant: " ++ err+#endif  -- | Validate a constant at compile-time using a 'Parse' instance --@@ -653,13 +867,57 @@ -- run-time.  Since the result is not compiled in, no 'THS.Lift' instance is -- required. ----- This function uses a typed expression.  Typed expressions were not--- supported in @haskell-src-exts <1.22.0@, which caused problems with--- @hlint@.  If the issue effects you, use @hlint -i "Parse error"@ to ignore--- parse errors or use 'untypedValidOf' instead.+-- This function uses a Template Haskell typed expression.  Typed expressions+-- were not supported in @haskell-src-exts <1.22.0@, which causes problems+-- with old versions of @hlint@.  If the issue affects you, use+-- @hlint -i "Parse error"@ to ignore parse errors or use 'untypedValidOf'+-- instead. ----- See the @validof@ example program in the @examples@ directory.+-- Note that the typed Template Haskell API changed in GHC 9.  The type+-- displayed in this documentation is determined by the version of GHC used to+-- build the documentation.+--+-- The type of this function in GHC 9 or later is as follows:+--+-- @+-- validOf+--   :: (MonadFail m, THS.Quote m, Parse a)+--   => Proxy a+--   -> String+--   -> THS.Code m a+-- @+--+-- The type of this function in previous versions of GHC is as follows:+--+-- @+-- validOf+--   :: Parse a+--   => Proxy a+--   -> String+--   -> TH.Q (TH.TExp a)+-- @+--+-- This function is used the same way in all GHC versions.  See the @validof@+-- example program in the @examples@ directory.  The following is example+-- usage from the @validof@ example:+--+-- @+-- sample :: Username+-- sample = $$(TTC.validOf (Proxy :: Proxy Username) "tcard")+-- @+--+-- @since 0.1.0.0+#if __GLASGOW_HASKELL__ >= 900 validOf+  :: (MonadFail m, THS.Quote m, Parse a)+  => Proxy a+  -> String+  -> THS.Code m a+validOf proxy s = case (`asProxyTypeOf` proxy) <$> parse s of+    Right{} -> [|| parseUnsafeS s ||]+    Left err -> THS.Code . fail $ "Invalid constant: " ++ err+#else+validOf   :: Parse a   => Proxy a   -> String@@ -667,18 +925,57 @@ validOf proxy s = case (`asProxyTypeOf` proxy) <$> parse s of     Right{} -> [|| parseUnsafeS s ||]     Left err -> fail $ "Invalid constant: " ++ err+#endif  -- | Make a @valid@ function using 'validOf' for the given type ----- Create a @valid@ function in the module for a type in order to avoid having--- to write a 'Proxy' when defining constants.+-- Create a @valid@ function for a type in order to avoid having to write a+-- 'Proxy' when defining constants. ----- This function uses a typed expression.  Typed expressions were not--- supported in @haskell-src-exts <1.22.0@, which caused problems with--- @hlint@.  If the issue effects you, use @hlint -i "Parse error"@ to ignore--- parse errors or use 'mkUntypedValidOf' instead.+-- This function uses a Template Haskell typed expression.  Typed expressions+-- were not supported in @haskell-src-exts <1.22.0@, which causes problems+-- with old versions of @hlint@.  If the issue affects you, use+-- @hlint -i "Parse error"@ to ignore parse errors or use 'mkUntypedValid'+-- instead. ----- See the @mkvalid@ example program in the @examples@ directory.+-- Note that the typed Template Haskell API changed in GHC 9.  The type+-- displayed in this documentation is determined by the version of GHC used to+-- build the documentation.+--+-- The type of the created @valid@ function in GHC 9 or later is as follows:+--+-- @+-- \$funName+--   :: forall m. (MonadFail m, THS.Quote m)+--   => String+--   -> THS.Code m $resultType+-- @+--+-- The type of the created @valid@ function in previous versions of GHC is as+-- follows:+--+-- @+-- \$funName+--   :: String+--   -> TH.Q (TH.TExp $resultType)+-- @+--+-- This function is used the same way in all GHC versions.  See the @mkvalid@+-- example program in the @examples@ directory.  The following is example+-- usage from the @mkvalid@ example:+--+-- @+-- \$(TTC.mkValid "valid" ''Username)+-- @+--+-- The created @valid@ function can then be used as follows:+--+-- @+-- sample :: Username+-- sample = $$(Username.valid "tcard")+-- @+--+-- @since 0.1.0.0 mkValid   :: String   -> TH.Name@@ -686,7 +983,15 @@ mkValid funName typeName = do     let funName' = TH.mkName funName         resultType = pure $ TH.ConT typeName+#if __GLASGOW_HASKELL__ >= 900+    funType <-+      [t|+        forall m . (MonadFail m, THS.Quote m) =>+          String -> THS.Code m $resultType+        |]+#else     funType <- [t| String -> TH.Q (TH.TExp $resultType) |]+#endif     body <- [| validOf (Proxy :: Proxy $resultType) |]     return       [ TH.SigD funName' funType@@ -703,7 +1008,15 @@ -- run-time.  Since the result is not compiled in, no 'THS.Lift' instance is -- required. ----- See the @uvalidof@ example program in the @examples@ directory.+-- See the @uvalidof@ example program in the @examples@ directory.  The+-- following is example usage from the @uvalidof@ example:+--+-- @+-- sample :: Username+-- sample = $(TTC.untypedValidOf (Proxy :: Proxy Username) "tcard")+-- @+--+-- @since 0.2.0.0 untypedValidOf   :: Parse a   => Proxy a@@ -715,10 +1028,24 @@  -- | Make a @valid@ function using 'untypedValidOf' for the given type ----- Create a @valid@ function in the module for a type in order to avoid having--- to write a 'Proxy' when defining constants.+-- Create a @valid@ function for a type in order to avoid having to write a+-- 'Proxy' when defining constants. ----- See the @mkuvalid@ example program in the @examples@ directory.+-- See the @mkuvalid@ example program in the @examples@ directory.  The+-- following is example usage from the @mkuvalid@ example:+--+-- @+-- \$(TTC.mkUntypedValid "valid" ''Username)+-- @+--+-- The created @valid@ function can then be used as follows:+--+-- @+-- sample :: Username+-- sample = $(Username.valid "tcard")+-- @+--+-- @since 0.2.0.0 mkUntypedValid   :: String   -> TH.Name@@ -735,7 +1062,21 @@  -- | Make a @valid@ quasi-quoter using 'untypedValidOf' for the given type ----- See the @uvalidqq@ example program in the @examples@ directory.+-- See the @uvalidqq@ example program in the @examples@ directory.  The+-- following is example usage from the @uvalidqq@ example:+--+-- @+-- \$(TTC.mkUntypedValidQQ "valid" ''Username)+-- @+--+-- The created @valid@ function can then be used as follows:+--+-- @+-- sample :: Username+-- sample = [Username.valid|tcard|]+-- @+--+-- @since 0.2.0.0 mkUntypedValidQQ   :: String   -> TH.Name
src/Data/TTC/Instances.hs view
@@ -2,7 +2,7 @@ -- | -- Module      : Data.TTC.Instances -- Description : instances for basic data types--- Copyright   : Copyright (c) 2019-2020 Travis Cardwell+-- Copyright   : Copyright (c) 2019-2021 Travis Cardwell -- License     : MIT -- -- This module defines TTC 'TTC.Render' and 'TTC.Parse' instances for some@@ -44,7 +44,7 @@ instance TTC.Parse Char where   parse = TTC.asS $ \case     [c] -> Right c-    _ -> Left $ TTC.fromS "invalid Char"+    _cs -> Left $ TTC.fromS "invalid Char"  instance TTC.Render Char where   render c = TTC.fromS [c]
test/Data/TTC/Test.hs view
@@ -123,6 +123,12 @@ answerBSL :: BSL.ByteString answerBSL = "42" +answerTLB :: TLB.Builder+answerTLB = "42"++answerSBS :: SBS.ShortByteString+answerSBS = "42"+ answerZ :: Int answerZ = 42 @@ -394,6 +400,16 @@ testRenderBSL :: TestTree testRenderBSL = testCase "renderBSL" $ answerBSL @=? TTC.renderBSL answer +testRenderTLB :: TestTree+testRenderTLB = testCase "renderTLB" $ answerTLB @=? TTC.renderTLB answer++testRenderBSB :: TestTree+testRenderBSB = testCase "renderBSB" $+    answerBSL @=? BSB.toLazyByteString (TTC.renderBSB answer)++testRenderSBS :: TestTree+testRenderSBS = testCase "renderSBS" $ answerSBS @=? TTC.renderSBS answer+ testRenderWithShow :: TestTree testRenderWithShow = testGroup "renderWithShow"     [ testCase "S" $ answerS @=? TTC.renderWithShow answerZ@@ -657,6 +673,9 @@         , testRenderTL         , testRenderBS         , testRenderBSL+        , testRenderTLB+        , testRenderBSB+        , testRenderSBS         , testRenderWithShow         ]     , testGroup "Parse"
ttc.cabal view
@@ -1,5 +1,5 @@ name:           ttc-version:        0.3.0.0+version:        0.4.0.0 category:       Data, Text synopsis:       Textual Type Classes description:@@ -11,18 +11,19 @@ bug-reports:    https://github.com/ExtremaIS/ttc-haskell/issues author:         Travis Cardwell <travis.cardwell@extrema.is> maintainer:     Travis Cardwell <travis.cardwell@extrema.is>-copyright:      Copyright (c) 2019-2020 Travis Cardwell+copyright:      Copyright (c) 2019-2021 Travis Cardwell license:        MIT license-file:   LICENSE -cabal-version:  >=1.10+cabal-version:  1.24 build-type:     Simple tested-with:   GHC ==8.2.2    || ==8.4.4    || ==8.6.5    || ==8.8.4-   || ==8.10.2+   || ==8.10.4+   || ==9.0.1  extra-source-files:   CHANGELOG.md@@ -32,6 +33,10 @@   type: git   location: https://github.com/ExtremaIS/ttc-haskell.git +flag write-hie+  description: write .hie files+  default: False+ library   hs-source-dirs: src   exposed-modules:@@ -40,10 +45,15 @@   build-depends:       base >=4.7 && <5     , bytestring >=0.10.8 && <0.12-    , template-haskell >=2.12 && <2.17+    , template-haskell >=2.12 && <2.18     , text >=1.2.3 && <1.3   default-language: Haskell2010-  ghc-options: -Wall+  default-extensions:+      OverloadedStrings+  if flag(write-hie)+    ghc-options: -Wall -fwrite-ide-info -hiedir=.hie+  else+    ghc-options: -Wall  test-suite ttc-test   type: exitcode-stdio-1.0