packages feed

ttc 1.4.0.0 → 1.5.0.0

raw patch · 11 files changed

+3723/−3687 lines, 11 filesdep ~basedep ~bytestringdep ~tasty

Dependency ranges changed: base, bytestring, tasty, tasty-hunit, template-haskell, text, text-short

Files

CHANGELOG.md view
@@ -1,10 +1,10 @@-# `ttc-haskell` Changelog+# `ttc` Changelog  This project follows the [Haskell package versioning policy][PVP], with versions in `A.B.C.D` format.  `A` may be incremented arbitrarily for non-technical reasons, but [semantic versioning][SemVer] is otherwise followed, where `A.B` is the major version, `C` is the minor version, and `D`-is the patch version.  Initial development uses versions `0.0.0.D`, for which+is the patch version.  Initial development uses versions `0.0.C.D`, for which every version is considered breaking.  [PVP]: <https://pvp.haskell.org/>@@ -23,6 +23,27 @@ * Changes are listed in arbitrary order and present tense.  [KaC]: <https://keepachangelog.com/en/1.0.0/>++## 1.5.0.0 (2025-01-02)++### Breaking++* Change type argument order for easier use with `TypeApplications`+* Add `RenderDefault` `Bool` instance+* Add `ParseDefault` `Bool` instance+* Add missing `RenderDefault` and `ParseDefault` instances for `TLB.Builder`,+  `ST.ShortText`, `BSB.Builder`, and `SBS.ShortByteString`+* Remove support for GHC 8.6, constraining lower bounds+* Remove support for GHC 8.4, constraining lower bounds+* Remove support for GHC 8.2, constraining lower bounds+* Change minimal Cabal from 1.24 to 3.0++### Non-Breaking++* Add `Data.TTC.Wrapper` module+* Add Template Haskell functions for loading default instances+* Bump `base` dependency version upper bound+* Bump `template-haskell` dependency version upper bound  ## 1.4.0.0 (2023-12-03) 
LICENSE view
@@ -1,6 +1,6 @@ The MIT License -Copyright (c) 2019-2023 Travis Cardwell+Copyright (c) 2019-2025 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
@@ -6,32 +6,20 @@ [![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) -* [Overview](#overview)-    * [`Textual`](#textual)-    * [`Render`](#render)-    * [`Parse`](#parse)-    * [Constant Validation](#constant-validation)-* [Related Work](#related-work)-    * [Rendering and Parsing](#rendering-and-parsing)-    * [Validating Constants](#validating-constants)-    * [String Type Conversion](#string-type-conversion)-    * [Arbitrary Type Conversion](#arbitrary-type-conversion)-* [Project](#project)-    * [Links](#links)-    * [Tags](#tags)-    * [Contribution](#contribution)-    * [License](#license)- ## Overview  TTC, an initialism of _Textual Type Classes_, is a library that provides `Render` and `Parse` type classes for conversion between data types and textual data types (strings).  Use the `Show` and `Read` type classes for debugging/development, and use the `Render` and `Parse` type classes for your-own purposes.  The library also provides a `Textual` type class for conversion-between textual data types as well as functions for validating constants at+own purposes.  The library also provides various ways to validate constants at compile-time. +This package (`ttc`) uses a `Textual` type class for conversion between+textual data types.  This package uses simple types and compiles quickly, but+the supported textual data types are fixed.  It is not possible for users to+add support for additional textual data types.+ Since a type may have at most one instance of a given type class, special care must be taken when defining type class instances in a shared library.  In particular, orphan instances should generally *not* be used in shared@@ -53,7 +41,7 @@     2. [Render and Parse][]     3. [Validated Constants][]     4. [Best Practices][]-* The [examples][] directory in the GitHub repository contains usage examples.+* The [`ttc-examples`][] directory in the repository contains usage examples.  [API documentation]: <https://hackage.haskell.org/package/ttc#modules> [series of articles]: <https://www.extrema.is/articles/ttc-textual-type-classes>@@ -61,7 +49,7 @@ [Render and Parse]: <https://www.extrema.is/articles/ttc-textual-type-classes/render-and-parse> [Validated Constants]: <https://www.extrema.is/articles/ttc-textual-type-classes/validated-constants> [Best Practices]: <https://www.extrema.is/articles/ttc-textual-type-classes/best-practices>-[examples]: <https://github.com/ExtremaIS/ttc-haskell/tree/main/examples>+[`ttc-examples`]: <https://github.com/ExtremaIS/ttc-haskell/tree/main/ttc-examples>  ### `Textual` @@ -186,160 +174,8 @@  For more details, see the [Validated Constants][] article. -## Related Work--### Rendering and Parsing--The [relude][] library has polymorphic versions of `show` and `readEither` in-`Relude.String.Conversion`, as well as various type classes for converting-between string types.  This does not encourage using `Show` and `Read`-instances with syntactically valid Haskell syntax, and it encourages the using-of the `String` data type.--The [rio][] library has a `Display` type class with a similar goal as-`TTC.Render`.  Since the library encourages a uniform usage of textual data-types, `Display` only provides functions for rendering to `Text` and a builder-format.  It does not have a type class similar to `TTC.Parse`.--The [text-display][] library defines a `Display` type class intended to render-user-facing text.  It uses a `Builder` type internally and renders to a `Text`-value.--Harry Garrood has an interesting series of blog posts about type classes and-`Show`:--* [Down with Show! Part 1: Rules of thumb for when to use a type class][]-* [Down with Show! Part 2: What's wrong with the Show type class][]-* [Down with Show! Part 3: A replacement for Show][]--[relude]: <https://hackage.haskell.org/package/relude>-[rio]: <https://hackage.haskell.org/package/rio>-[text-display]: <https://hackage.haskell.org/package/text-display>-[Down with Show! Part 1: Rules of thumb for when to use a type class]: <https://harry.garrood.me/blog/down-with-show-part-1/>-[Down with Show! Part 2: What's wrong with the Show type class]: <https://harry.garrood.me/blog/down-with-show-part-2/>-[Down with Show! Part 3: A replacement for Show]: <https://harry.garrood.me/blog/down-with-show-part-3/>--### Validating Constants--The [qq-literals][] library creates a `QuasiQuoter` from a parse function of-type `String -> Either String a`.  The functionality is similar to TTC's-`mkUntypedValidQQ` function.  The `mkUntypedValidQQ` function allows the user-to choose the name of the `QuasiQuoter` because a name like `valid` is-preferred when used via a qualified import while a name like `username` may be-preferred when not using qualified imports.  Note that `mkUntypedValidQQ` also-splices in an explicit type signature.--The [validated-literals][] library has a `Validate` type class that is similar-to `TTC.Parse` but supports conversion between arbitrary types, not just from-textual data types.  Template Haskell functions are provided to perform-validation at compile-time.  Result types must either have `Lift` instances or-equivalent implementations.--Chris Done posted [a gist][] about implementing statically checked overloaded-strings.--[qq-literals]: <https://hackage.haskell.org/package/qq-literals>-[validated-literals]: <https://hackage.haskell.org/package/validated-literals>-[a gist]: <https://gist.github.com/chrisdone/809296b769ee36d352ae4f8dbe89a364>--### String Type Conversion--There are a number of libraries that simplify conversion between string types.--The following libraries provide type classes with two type variables.  The-primary benefit of this approach is that one can add support for any string-type.  The drawback of this approach is that implementations of `Render` and-`Parse` using such a type class would have to be done via a fixed type,-resulting in unnecessary conversion when using other types.--* [string-conv][]-* [string-conversions][]--The following library provide type classes with a single type variable, but-conversion is done via a fixed type.--* [hxt-regex-xmlschema][] has a `StringLike` type class and does conversion-  via the `String` type-* [ListLike][] has a `StringLike` type class and does conversion via the-  `String` type-* [monoid-subclasses][] provides a `TextualMonoid` type class that provides an-  abstract API over textual types, using `String` as the underlying type-* [stringlike][] converts via the `Text` type-* [tagsoup][] has a `StringLike` type class that provides an abstract API over-  textual types and a `castString` function that converts via the `String`-  type-* [text-conversions][] converts via the `Text` type-* [textual][] (deprecated) converts via the `String` type--[string-conv]: <https://hackage.haskell.org/package/string-conv>-[string-conversions]: <https://hackage.haskell.org/package/string-conversions>-[hxt-regex-xmlschema]: <https://hackage.haskell.org/package/hxt-regex-xmlschema>-[ListLike]: <https://hackage.haskell.org/package/ListLike>-[monoid-subclasses]: <https://hackage.haskell.org/package/monoid-subclasses>-[stringlike]: <https://hackage.haskell.org/package/stringlike>-[tagsoup]: <https://hackage.haskell.org/package/tagsoup>-[text-conversions]: <https://hackage.haskell.org/package/text-conversions>-[textual]: <https://hackage.haskell.org/package/textual>--### Arbitrary Type Conversion--There are also a number of libraries that provide type classes for conversion-between arbitrary types, including string types.--* [basement][] provides type classes for conversion that may fail as well as-  conversion that cannot fail-* [convertible][]-* [witch][] provides type classes for conversion that may fail as well as-  conversion that cannot fail--[basement]: <https://hackage.haskell.org/package/basement>-[convertible]: <https://hackage.haskell.org/package/convertible>-[witch]: <https://hackage.haskell.org/package/witch>- ## Project -### Links--* Hackage: <https://hackage.haskell.org/package/ttc>-* Stackage: <https://stackage.org/package/ttc>-* Flora: <https://flora.pm/packages/@hackage/ttc>-* GitHub: <https://github.com/ExtremaIS/ttc-haskell>-* GitHub Actions CI: <https://github.com/ExtremaIS/ttc-haskell/actions>--### Branches--The `main` branch is reserved for releases.  It may be considered stable, and-`HEAD` is always the latest release.--The `develop` branch is the primary development branch.  It contains changes-that have not yet been released, and it is not necessarily stable.--[Hackage revisions][] are made for metadata changes, such as relaxation of-constraints when new versions of dependencies are released.  The `ttc.cabal`-metadata in the `main` branch may therefore not match that of Hackage.  The-`ttc.cabal` metadata in the `develop` branch may match, *unless* work is being-done on a new release that contains other changes.--[Hackage revisions]: <https://github.com/haskell-infra/hackage-trustees/blob/master/revisions-information.md#hackage-metadata-revisions--what-they-are-how-they-work>--### Tags--All releases are tagged in the `main` branch.  Release tags are signed using-the [`security@extrema.is` GPG key][].--[`security@extrema.is` GPG key]: <https://keyserver.ubuntu.com/pks/lookup?search=0x1D484E4B4705FADF&fingerprint=on&op=index>--### Contribution--Issues and feature requests are tracked on GitHub:-<https://github.com/ExtremaIS/ttc-haskell/issues>--Issues may also be submitted via email to <bugs@extrema.is>.--### License--This project is released under the [MIT License][] as specified in the-[`LICENSE`][] file.+See the [project README][] for general project information. -[MIT License]: <https://opensource.org/licenses/MIT>-[`LICENSE`]: <LICENSE>+[project README]: <https://github.com/ExtremaIS/ttc-haskell#ttc-textual-type-classes>
src/Data/TTC.hs view
@@ -1,1994 +1,2301 @@ ------------------------------------------------------------------------------ -- | -- Module      : Data.TTC--- Description : textual type classes--- Copyright   : Copyright (c) 2019-2023 Travis Cardwell--- License     : MIT------ TTC, an initialism of /Textual Type Classes/, is a library that provides--- type classes for conversion between data types and textual data types--- (strings).------ This library is meant to be imported qualified, as follows:------ @--- import qualified Data.TTC as TTC--- @---------------------------------------------------------------------------------{-# LANGUAGE CPP #-}-{-# LANGUAGE DefaultSignatures #-}-{-# LANGUAGE FlexibleInstances #-}-{-# LANGUAGE LambdaCase #-}-{-# LANGUAGE TemplateHaskell #-}-{-# OPTIONS_GHC -fno-warn-orphans #-}--#if __GLASGOW_HASKELL__ >= 900-{-# LANGUAGE ExplicitForAll #-}-#endif--module Data.TTC-  ( -- * Textual-    Textual-  , convert-    -- ** \"To\" Conversions-    -- $TextualTo-  , toS-  , toT-  , toTL-  , toTLB-  , toST-  , toBS-  , toBSL-  , toBSB-  , toSBS-    -- ** \"From\" Conversions-    -- $TextualFrom-  , fromS-  , fromT-  , fromTL-  , fromTLB-  , fromST-  , fromBS-  , fromBSL-  , fromBSB-  , fromSBS-    -- ** \"As\" Conversions-    -- $TextualAs-  , asS-  , asT-  , asTL-  , asTLB-  , asST-  , asBS-  , asBSL-  , asBSB-  , asSBS-    -- * Render-  , Render(..)-  , RenderDefault(..)-    -- ** Rendering Specific Types-    -- $RenderSpecific-  , renderS-  , renderT-  , renderTL-  , renderTLB-  , renderST-  , renderBS-  , renderBSL-  , renderBSB-  , renderSBS-    -- ** Render Utilities-  , renderWithShow-    -- * Parse-  , Parse(..)-  , ParseDefault(..)-    -- ** Parsing From Specific Types-    -- $ParseSpecific-  , parseS-  , parseT-  , parseTL-  , parseTLB-  , parseST-  , parseBS-  , parseBSL-  , parseBSB-  , parseSBS-    -- ** 'Maybe' Parsing-    -- $ParseMaybe-  , parseMaybe-  , parseMaybeS-  , parseMaybeT-  , parseMaybeTL-  , parseMaybeTLB-  , parseMaybeST-  , parseMaybeBS-  , parseMaybeBSL-  , parseMaybeBSB-  , parseMaybeSBS-    -- ** 'MonadFail' Parsing-    -- $ParseOrFail-  , parseOrFail-  , parseOrFailS-  , parseOrFailT-  , parseOrFailTL-  , parseOrFailTLB-  , parseOrFailST-  , parseOrFailBS-  , parseOrFailBSL-  , parseOrFailBSB-  , parseOrFailSBS-    -- ** Unsafe Parsing-    -- $ParseUnsafe-  , parseUnsafe-  , parseUnsafeS-  , parseUnsafeT-  , parseUnsafeTL-  , parseUnsafeTLB-  , parseUnsafeST-  , parseUnsafeBS-  , parseUnsafeBSL-  , parseUnsafeBSB-  , parseUnsafeSBS-    -- ** Parse With A Single Error Message-    -- $ParseWithASingleErrorMessage-  , withError-  , withErrorS-  , withErrorT-  , withErrorTL-  , withErrorTLB-  , withErrorST-  , withErrorBS-  , withErrorBSL-  , withErrorBSB-  , withErrorSBS-    -- ** Parse With An Error Prefix-    -- $ParseWithAnErrorPrefix-  , prefixError-  , prefixErrorS-  , prefixErrorT-  , prefixErrorTL-  , prefixErrorTLB-  , prefixErrorST-  , prefixErrorBS-  , prefixErrorBSL-  , prefixErrorBSB-  , prefixErrorSBS-    -- ** Parse Enums-  , parseEnum-  , parseEnum'-    -- ** Read Instances-  , parseWithRead-  , parseWithRead'-  , maybeParseWithRead-  , readsEnum-  , readsWithParse-    -- ** Constant Validation-    -- $ParseValid-  , valid-  , validOf-  , mkValid-  , untypedValidOf-  , mkUntypedValid-  , mkUntypedValidQQ-  ) where---- https://hackage.haskell.org/package/base-#if __GLASGOW_HASKELL__ <= 806-import Control.Monad.Fail (MonadFail)-#endif-import Data.Int (Int16, Int32, Int64, Int8)-import Data.Proxy (Proxy(Proxy), asProxyTypeOf)-import Data.String (IsString(fromString))-import Data.Word (Word16, Word32, Word64, Word8)-import GHC.Stack (HasCallStack)-import Text.Read (readMaybe)---- https://hackage.haskell.org/package/bytestring-import qualified Data.ByteString as BS-import qualified Data.ByteString.Builder as BSB-import qualified Data.ByteString.Lazy as BSL-import qualified Data.ByteString.Short as SBS---- https://hackage.haskell.org/package/template-haskell-import qualified Language.Haskell.TH as TH-import qualified Language.Haskell.TH.Quote as Q-import qualified Language.Haskell.TH.Syntax as THS---- https://hackage.haskell.org/package/text-import qualified Data.Text as T-import qualified Data.Text.Encoding as TE-import qualified Data.Text.Encoding.Error as TEE-import qualified Data.Text.Lazy as TL-import qualified Data.Text.Lazy.Builder as TLB-import qualified Data.Text.Lazy.Encoding as TLE---- https://hackage.haskell.org/package/text-short-import qualified Data.Text.Short as ST----------------------------------------------------------------------------------- $Textual---- | The 'Textual' type class is used to convert between the following textual--- data types:------ * 'String' (@S@)--- * Strict 'T.Text' (@T@)--- * Lazy 'TL.Text' (@TL@)--- * @Text@ 'TLB.Builder' (@TLB@)--- * 'ST.ShortText' (@ST@)--- * Strict 'BS.ByteString' (@BS@)--- * Lazy 'BSL.ByteString' (@BSL@)--- * @ByteString@ 'BSB.Builder' (@BSB@) (Note: @Data.Binary.Builder@---   re-exports this type, so TTC can be used with @binary@ as well.)--- * 'SBS.ShortByteString' (@SBS@)------ @ByteString@ values are assumed to be UTF-8 encoded text.  Invalid bytes--- are replaced with the Unicode replacement character @U+FFFD@.  In cases--- where different behavior is required, process @ByteString@ values /before/--- using this class.------ This type class has two key features:------ * Type conversion is /not/ done through a fixed type (such as 'String' or---   'T.Text').--- * It has a single type variable, making it easy to write functions that---   accept arguments and/or return values that may be any of the supported---   textual data types.------ Note that support for additional data types cannot be implemented by--- writing instances.  Adding support for additional data types would require--- changing the class definition itself.------ For more details, see the following article:--- <https://www.extrema.is/articles/ttc-textual-type-classes/textual-type-class>------ @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 @Text@ 'TLB.Builder'-  ---  -- @since 1.1.0.0-  toTLB :: t -> TLB.Builder--  -- | Convert to 'ST.ShortText'-  ---  -- @since 1.4.0.0-  toST :: t -> ST.ShortText--  -- | 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 to a @ByteString@ 'BSB.Builder'-  ---  -- @since 1.1.0.0-  toBSB :: t -> BSB.Builder--  -- | Convert to a 'SBS.ShortByteString'-  ---  -- @since 1.1.0.0-  toSBS :: t -> SBS.ShortByteString--  -- | Convert between any supported textual data types-  ---  -- @since 0.1.0.0-  convert :: Textual t' => t' -> t--instance Textual String where-  toS = id-  toT = T.pack-  toTL = TL.pack-  toTLB = TLB.fromString-  toST = ST.fromString-  toBS = TE.encodeUtf8 . T.pack-  toBSL = TLE.encodeUtf8 . TL.pack-  toBSB = BSB.byteString . TE.encodeUtf8 . T.pack-  toSBS = SBS.toShort . TE.encodeUtf8 . T.pack-  convert = toS-  {-# INLINE toS #-}-  {-# INLINE toT #-}-  {-# INLINE toTL #-}-  {-# INLINE toTLB #-}-  {-# INLINE toST #-}-  {-# INLINE toBS #-}-  {-# INLINE toBSL #-}-  {-# INLINE toBSB #-}-  {-# INLINE toSBS #-}-  {-# INLINE convert #-}--instance Textual T.Text where-  toS = T.unpack-  toT = id-  toTL = TL.fromStrict-  toTLB = TLB.fromText-  toST = ST.fromText-  toBS = TE.encodeUtf8-  toBSL = TLE.encodeUtf8 . TL.fromStrict-  toBSB = BSB.byteString . TE.encodeUtf8-  toSBS = SBS.toShort . TE.encodeUtf8-  convert = toT-  {-# INLINE toS #-}-  {-# INLINE toT #-}-  {-# INLINE toTL #-}-  {-# INLINE toTLB #-}-  {-# INLINE toST #-}-  {-# INLINE toBS #-}-  {-# INLINE toBSL #-}-  {-# INLINE toBSB #-}-  {-# INLINE toSBS #-}-  {-# INLINE convert #-}--instance Textual TL.Text where-  toS = TL.unpack-  toT = TL.toStrict-  toTL = id-  toTLB = TLB.fromLazyText-  toST = ST.fromText . TL.toStrict-  toBS = BSL.toStrict . TLE.encodeUtf8-  toBSL = TLE.encodeUtf8-  toBSB = BSB.lazyByteString . TLE.encodeUtf8-  toSBS = SBS.toShort . BSL.toStrict . TLE.encodeUtf8-  convert = toTL-  {-# INLINE toS #-}-  {-# INLINE toT #-}-  {-# INLINE toTL #-}-  {-# INLINE toTLB #-}-  {-# INLINE toST #-}-  {-# INLINE toBS #-}-  {-# INLINE toBSL #-}-  {-# INLINE toBSB #-}-  {-# INLINE toSBS #-}-  {-# INLINE convert #-}--instance Textual TLB.Builder where-  toS = TL.unpack . TLB.toLazyText-  toT = TL.toStrict . TLB.toLazyText-  toTL = TLB.toLazyText-  toTLB = id-  toST = ST.fromText . TL.toStrict . TLB.toLazyText-  toBS = BSL.toStrict . TLE.encodeUtf8 . TLB.toLazyText-  toBSL = TLE.encodeUtf8 . TLB.toLazyText-  toBSB = BSB.lazyByteString . TLE.encodeUtf8 . TLB.toLazyText-  toSBS = SBS.toShort . BSL.toStrict . TLE.encodeUtf8 . TLB.toLazyText-  convert = toTLB-  {-# INLINE toS #-}-  {-# INLINE toT #-}-  {-# INLINE toTL #-}-  {-# INLINE toTLB #-}-  {-# INLINE toST #-}-  {-# INLINE toBS #-}-  {-# INLINE toBSL #-}-  {-# INLINE toBSB #-}-  {-# INLINE toSBS #-}-  {-# INLINE convert #-}--instance Textual ST.ShortText where-  toS = ST.toString-  toT = ST.toText-  toTL = TL.fromStrict . ST.toText-  toTLB = TLB.fromText . ST.toText-  toST = id-  toBS = ST.toByteString-  toBSL = BSL.fromStrict . ST.toByteString-  toBSB = BSB.byteString . ST.toByteString-  toSBS = ST.toShortByteString-  convert = toST-  {-# INLINE toS #-}-  {-# INLINE toT #-}-  {-# INLINE toTL #-}-  {-# INLINE toTLB #-}-  {-# INLINE toST #-}-  {-# INLINE toBS #-}-  {-# INLINE toBSL #-}-  {-# INLINE toBSB #-}-  {-# INLINE toSBS #-}-  {-# INLINE convert #-}--instance Textual BS.ByteString where-  toS = T.unpack . TE.decodeUtf8With TEE.lenientDecode-  toT = TE.decodeUtf8With TEE.lenientDecode-  toTL = TLE.decodeUtf8With TEE.lenientDecode . BSL.fromStrict-  toTLB = TLB.fromText . TE.decodeUtf8With TEE.lenientDecode-  toST = ST.fromText . TE.decodeUtf8With TEE.lenientDecode-  toBS = id-  toBSL = BSL.fromStrict-  toBSB = BSB.byteString-  toSBS = SBS.toShort-  convert = toBS-  {-# INLINE toS #-}-  {-# INLINE toT #-}-  {-# INLINE toTL #-}-  {-# INLINE toTLB #-}-  {-# INLINE toST #-}-  {-# INLINE toBS #-}-  {-# INLINE toBSL #-}-  {-# INLINE toBSB #-}-  {-# INLINE toSBS #-}-  {-# INLINE convert #-}--instance Textual BSL.ByteString where-  toS = TL.unpack . TLE.decodeUtf8With TEE.lenientDecode-  toT = TL.toStrict . TLE.decodeUtf8With TEE.lenientDecode-  toTL = TLE.decodeUtf8With TEE.lenientDecode-  toTLB = TLB.fromLazyText . TLE.decodeUtf8With TEE.lenientDecode-  toST = ST.fromText . TL.toStrict . TLE.decodeUtf8With TEE.lenientDecode-  toBS = BSL.toStrict-  toBSL = id-  toBSB = BSB.lazyByteString-  toSBS = SBS.toShort . BSL.toStrict-  convert = toBSL-  {-# INLINE toS #-}-  {-# INLINE toT #-}-  {-# INLINE toTL #-}-  {-# INLINE toTLB #-}-  {-# INLINE toST #-}-  {-# INLINE toBS #-}-  {-# INLINE toBSL #-}-  {-# INLINE toBSB #-}-  {-# INLINE toSBS #-}-  {-# INLINE convert #-}--instance Textual BSB.Builder where-  toS =-    TL.unpack . TLE.decodeUtf8With TEE.lenientDecode . BSB.toLazyByteString-  toT =-    TL.toStrict . TLE.decodeUtf8With TEE.lenientDecode . BSB.toLazyByteString-  toTL = TLE.decodeUtf8With TEE.lenientDecode . BSB.toLazyByteString-  toTLB-    = TLB.fromLazyText-    . TLE.decodeUtf8With TEE.lenientDecode-    . BSB.toLazyByteString-  toST-    = ST.fromText-    . TL.toStrict-    . TLE.decodeUtf8With TEE.lenientDecode-    . BSB.toLazyByteString-  toBS = BSL.toStrict . BSB.toLazyByteString-  toBSL = BSB.toLazyByteString-  toBSB = id-  toSBS = SBS.toShort . BSL.toStrict . BSB.toLazyByteString-  convert = toBSB-  {-# INLINE toS #-}-  {-# INLINE toT #-}-  {-# INLINE toTL #-}-  {-# INLINE toTLB #-}-  {-# INLINE toST #-}-  {-# INLINE toBS #-}-  {-# INLINE toBSL #-}-  {-# INLINE toBSB #-}-  {-# INLINE toSBS #-}-  {-# INLINE convert #-}--instance Textual SBS.ShortByteString where-  toS = T.unpack . TE.decodeUtf8With TEE.lenientDecode . SBS.fromShort-  toT = TE.decodeUtf8With TEE.lenientDecode . SBS.fromShort-  toTL = TLE.decodeUtf8With TEE.lenientDecode . BSL.fromStrict . SBS.fromShort-  toTLB = TLB.fromText . TE.decodeUtf8With TEE.lenientDecode . SBS.fromShort-  toST = ST.fromText . TE.decodeUtf8With TEE.lenientDecode . SBS.fromShort-  toBS = SBS.fromShort-  toBSL = BSL.fromStrict . SBS.fromShort-  toBSB = BSB.byteString . SBS.fromShort-  toSBS = id-  convert = toSBS-  {-# INLINE toS #-}-  {-# INLINE toT #-}-  {-# INLINE toTL #-}-  {-# INLINE toTLB #-}-  {-# INLINE toST #-}-  {-# INLINE toBS #-}-  {-# INLINE toBSL #-}-  {-# INLINE toBSB #-}-  {-# INLINE toSBS #-}-  {-# INLINE convert #-}----------------------------------------------------------------------------------- $TextualTo------ These functions are equivalent to 'convert', but they specify the type--- being converted to.  Use them to avoid having to write type annotations in--- cases where the type is ambiguous.---- $TextualFrom------ These functions are equivalent to 'convert', but they specify the type--- being converted from.  Use them to avoid having to write type annotations--- 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 @Text@ 'TLB.Builder'------ @since 1.1.0.0-fromTLB :: Textual t => TLB.Builder -> t-fromTLB = convert-{-# INLINE fromTLB #-}---- | Convert from a 'ST.ShortText'------ @since 1.4.0.0-fromST :: Textual t => ST.ShortText -> t-fromST = convert-{-# INLINE fromST #-}---- | 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 #-}---- | Convert from a @ByteString@ 'TLB.Builder'------ @since 1.1.0.0-fromBSB :: Textual t => BSB.Builder -> t-fromBSB = convert-{-# INLINE fromBSB #-}---- | Convert from a 'SBS.ShortByteString'------ @since 1.1.0.0-fromSBS :: Textual t => SBS.ShortByteString -> t-fromSBS = convert-{-# INLINE fromSBS #-}----------------------------------------------------------------------------------- $TextualAs------ These functions are used to convert a 'Textual' argument of a function to a--- specific type.  Use them to reduce boilerplate in small function--- 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 @Text@ 'TLB.Builder'------ @since 1.1.0.0-asTLB :: Textual t => (TLB.Builder -> a) -> t -> a-asTLB f = f . convert-{-# INLINE asTLB #-}---- | Convert an argument to a 'ST.ShortText'------ @since 1.4.0.0-asST :: Textual t => (ST.ShortText -> a) -> t -> a-asST f = f . convert-{-# INLINE asST #-}---- | 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 #-}---- | Convert an argument to a @ByteString@ 'TLB.Builder'------ @since 1.1.0.0-asBSB :: Textual t => (BSB.Builder -> a ) -> t -> a-asBSB f = f . convert-{-# INLINE asBSB #-}---- | Convert an argument to a 'SBS.ShortByteString'------ @since 1.1.0.0-asSBS :: Textual t => (SBS.ShortByteString -> a) -> t -> a-asSBS f = f . convert-{-# INLINE asSBS #-}----------------------------------------------------------------------------------- $Render---- | The 'Render' type class renders a data type as a textual data type.------ There are no default instances for the 'Render' type class, so that all--- instances can be customized per project when desired.  Instances for some--- basic data types are defined for the 'RenderDefault' type class, however,--- and you can load the 'Render' instance as follows:------ @--- instance TTC.Render Int--- @------ Since a type may have at most one instance of a given type class, special--- care must be taken when defining type class instances in a shared library.--- In particular, orphan instances should generally not be used in shared--- libraries since they prevent users of the libraries from writing their own--- instances.------ See the @uname@ and @prompt@ example programs in the @examples@ directory.------ For more details, see the following article:--- <https://www.extrema.is/articles/ttc-textual-type-classes/render-and-parse>------ @since 0.1.0.0-class Render a where-  render :: Textual t => a -> t--  default render :: (RenderDefault a, Textual t) => a -> t-  render = renderDefault------------------------------------------------------------------------------------ | The 'RenderDefault' type class provides some default 'Render' instances.------ * The 'Char' instance renders a single-character string.--- * Numeric type instances all render using the 'Show' instance.--- * Textual type instances all convert to the target 'Textual' data type.------ @since 1.1.0.0-class RenderDefault a where-  renderDefault :: Textual t => a -> t--instance RenderDefault Char where-  renderDefault c = fromS [c]--instance RenderDefault Double where-  renderDefault = renderWithShow--instance RenderDefault Float where-  renderDefault = renderWithShow--instance RenderDefault Int where-  renderDefault = renderWithShow--instance RenderDefault Int8 where-  renderDefault = renderWithShow--instance RenderDefault Int16 where-  renderDefault = renderWithShow--instance RenderDefault Int32 where-  renderDefault = renderWithShow--instance RenderDefault Int64 where-  renderDefault = renderWithShow--instance RenderDefault Integer where-  renderDefault = renderWithShow--instance RenderDefault Word where-  renderDefault = renderWithShow--instance RenderDefault Word8 where-  renderDefault = renderWithShow--instance RenderDefault Word16 where-  renderDefault = renderWithShow--instance RenderDefault Word32 where-  renderDefault = renderWithShow--instance RenderDefault Word64 where-  renderDefault = renderWithShow--instance RenderDefault String where-  renderDefault = fromS--instance RenderDefault BSL.ByteString where-  renderDefault = fromBSL--instance RenderDefault BS.ByteString where-  renderDefault = fromBS--instance RenderDefault TL.Text where-  renderDefault = fromTL--instance RenderDefault T.Text where-  renderDefault = fromT----------------------------------------------------------------------------------- $RenderSpecific------ These functions are equivalent to 'render', but they specify the type being--- rendered to.  Use them to avoid having to write type annotations in cases--- 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 @Text@ 'TLB.Builder'------ @since 0.4.0.0-renderTLB :: Render a => a -> TLB.Builder-renderTLB = render-{-# INLINE renderTLB #-}---- | Render to a 'ST.ShortText'------ @since 1.4.0.0-renderST :: Render a => a -> ST.ShortText-renderST = render-{-# INLINE renderST #-}---- | 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 @ByteString@ 'BSB.Builder'------ @since 0.4.0.0-renderBSB :: Render a => a -> BSB.Builder-renderBSB = render-{-# INLINE renderBSB #-}---- | Render to a 'SBS.ShortByteString'------ @since 0.4.0.0-renderSBS :: Render a => a -> SBS.ShortByteString-renderSBS = render-{-# 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 #-}----------------------------------------------------------------------------------- $Parse---- | The 'Parse' type class parses a data type from a textual data type.------ There are no default instances for the 'Parse' type class, so that all--- instances can be customized per project when desired.  Instances for some--- basic data types are defined for the 'ParseDefault' type class, however,--- and you can load the 'Parse' instance as follows:------ @--- instance TTC.Parse Int--- @------ Since a type may have at most one instance of a given type class, special--- care must be taken when defining type class instances in a shared library.--- In particular, orphan instances should generally not be used in shared--- libraries since they prevent users of the libraries from writing their own--- instances.------ See the @uname@ and @prompt@ example programs in the @examples@ directory.------ For more details, see the following article:--- <https://www.extrema.is/articles/ttc-textual-type-classes/render-and-parse>------ @since 0.3.0.0-class Parse a where-  parse :: (Textual t, Textual e) => t -> Either e a--  default parse :: (Textual t, Textual e, ParseDefault a) => t -> Either e a-  parse = parseDefault---- 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' #-}------------------------------------------------------------------------------------ | The 'ParseDefault' type class provides some default 'Parse' instances.------ * The 'Char' instance parses single-character strings.--- * Numeric type instances all parse using the 'Read' instance.--- * Textual type instances all convert from the source 'Textual' data type.------ @since 1.1.0.0-class ParseDefault a where-  parseDefault :: (Textual t, Textual e) => t -> Either e a--instance ParseDefault Char where-  parseDefault = asS $ \case-    [c] -> Right c-    _cs -> Left $ fromS "invalid Char"--instance ParseDefault Double where-  parseDefault = parseWithRead' "Double"--instance ParseDefault Float where-  parseDefault = parseWithRead' "Float"--instance ParseDefault Int where-  parseDefault = parseWithRead' "Int"--instance ParseDefault Int8 where-  parseDefault = parseWithRead' "Int8"--instance ParseDefault Int16 where-  parseDefault = parseWithRead' "Int16"--instance ParseDefault Int32 where-  parseDefault = parseWithRead' "Int32"--instance ParseDefault Int64 where-  parseDefault = parseWithRead' "Int64"--instance ParseDefault Integer where-  parseDefault = parseWithRead' "Integer"--instance ParseDefault Word where-  parseDefault = parseWithRead' "Word"--instance ParseDefault Word8 where-  parseDefault = parseWithRead' "Word8"--instance ParseDefault Word16 where-  parseDefault = parseWithRead' "Word16"--instance ParseDefault Word32 where-  parseDefault = parseWithRead' "Word32"--instance ParseDefault Word64 where-  parseDefault = parseWithRead' "Word64"--instance ParseDefault String where-  parseDefault = Right . toS--instance ParseDefault BSL.ByteString where-  parseDefault = Right . toBSL--instance ParseDefault BS.ByteString where-  parseDefault = Right . toBS--instance ParseDefault TL.Text where-  parseDefault = Right . toTL--instance ParseDefault T.Text where-  parseDefault = Right . toT----------------------------------------------------------------------------------- $ParseSpecific------ These functions are equivalent to 'parse', but they specify the type being--- parsed from.  Use them to avoid having to write type annotations in cases--- 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 @Text@ 'TLB.Builder'------ @since 1.1.0.0-parseTLB :: (Parse a, Textual e) => TLB.Builder -> Either e a-parseTLB = parse-{-# INLINE parseTLB #-}---- | Parse from a 'ST.ShortText'------ @since 1.4.0.0-parseST :: (Parse a, Textual e) => ST.ShortText -> Either e a-parseST = parse-{-# INLINE parseST #-}---- | 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 #-}---- | Parse from a @ByteString@ 'BSB.Builder'------ @since 1.1.0.0-parseBSB :: (Parse a, Textual e) => BSB.Builder -> Either e a-parseBSB = parse-{-# INLINE parseBSB #-}---- | Parse from a 'SBS.ShortByteString'------ @since 1.1.0.0-parseSBS :: (Parse a, Textual e) => SBS.ShortByteString -> Either e a-parseSBS = parse-{-# INLINE parseSBS #-}----------------------------------------------------------------------------------- $ParseMaybe------ The 'parseMaybe' function parses to a 'Maybe' type instead of an 'Either'--- type.  The rest of the functions are equivalent to 'parseMaybe', but they--- specify the type being parsed from.  Use them to avoid having to write type--- 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 @Text@ 'TLB.Builder' to a 'Maybe' type------ @since 1.1.0.0-parseMaybeTLB :: Parse a => TLB.Builder -> Maybe a-parseMaybeTLB = parseMaybe-{-# INLINE parseMaybeTLB #-}---- | Parse from a 'ST.ShortText' to a 'Maybe' type------ @since 1.4.0.0-parseMaybeST :: Parse a => ST.ShortText -> Maybe a-parseMaybeST = parseMaybe-{-# INLINE parseMaybeST #-}---- | 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 #-}---- | Parse from a @ByteString@ 'BSB.Builder' to a 'Maybe' type------ @since 1.1.0.0-parseMaybeBSB :: Parse a => BSB.Builder -> Maybe a-parseMaybeBSB = parseMaybe-{-# INLINE parseMaybeBSB #-}---- | Parse from a 'SBS.ShortByteString' to a 'Maybe' type------ @since 1.1.0.0-parseMaybeSBS :: Parse a => SBS.ShortByteString -> Maybe a-parseMaybeSBS = parseMaybe-{-# INLINE parseMaybeSBS #-}----------------------------------------------------------------------------------- $ParseOrFail------ The 'parseOrFail' function fails using 'MonadFail' on error instead of--- using an 'Either' type.  The rest of the functions are equivalent to--- 'parseOrFail', but they specify the type being parsed from.  Use them to--- avoid having to write type annotations in cases where the type is--- ambiguous.---- | Parse or fail using 'MonadFail'------ @since 1.3.0.0-parseOrFail :: (MonadFail m, Parse a, Textual t) => t -> m a-parseOrFail = either fail pure . parse-{-# INLINE parseOrFail #-}---- | Parse from a 'String' or fail using 'MonadFail'------ @since 1.3.0.0-parseOrFailS :: (MonadFail m, Parse a) => String -> m a-parseOrFailS = parseOrFail-{-# INLINE parseOrFailS #-}---- | Parse from strict 'T.Text' or fail using 'MonadFail'------ @since 1.3.0.0-parseOrFailT :: (MonadFail m, Parse a) => T.Text -> m a-parseOrFailT = parseOrFail-{-# INLINE parseOrFailT #-}---- | Parse from lazy 'TL.Text' or fail using 'MonadFail'------ @since 1.3.0.0-parseOrFailTL :: (MonadFail m, Parse a) => TL.Text -> m a-parseOrFailTL = parseOrFail-{-# INLINE parseOrFailTL #-}---- | Parse from a @Text@ 'TLB.Builder' or fail using 'MonadFail'------ @since 1.3.0.0-parseOrFailTLB :: (MonadFail m, Parse a) => TLB.Builder -> m a-parseOrFailTLB = parseOrFail-{-# INLINE parseOrFailTLB #-}---- | Parse from a 'ST.ShortText' or fail using 'MonadFail'------ @since 1.4.0.0-parseOrFailST :: (MonadFail m, Parse a) => ST.ShortText -> m a-parseOrFailST = parseOrFail-{-# INLINE parseOrFailST #-}---- | Parse from a strict 'BS.ByteString' or fail using 'MonadFail'------ @since 1.3.0.0-parseOrFailBS :: (MonadFail m, Parse a) => BS.ByteString -> m a-parseOrFailBS = parseOrFail-{-# INLINE parseOrFailBS #-}---- | Parse from a lazy 'BSL.ByteString' or fail using 'MonadFail'------ @since 1.3.0.0-parseOrFailBSL :: (MonadFail m, Parse a) => BSL.ByteString -> m a-parseOrFailBSL = parseOrFail-{-# INLINE parseOrFailBSL #-}---- | Parse from a @ByteString@ 'BSB.Builder' or fail using 'MonadFail'------ @since 1.3.0.0-parseOrFailBSB :: (MonadFail m, Parse a) => BSB.Builder -> m a-parseOrFailBSB = parseOrFail-{-# INLINE parseOrFailBSB #-}---- | Parse from a 'SBS.ShortByteString' or fail using 'MonadFail'------ @since 1.3.0.0-parseOrFailSBS :: (MonadFail m, Parse a) => SBS.ShortByteString -> m a-parseOrFailSBS = parseOrFail-{-# INLINE parseOrFailSBS #-}----------------------------------------------------------------------------------- $ParseUnsafe------ The 'parseUnsafe' function raises an exception on error instead of using an--- 'Either' type.  It should only be used when an error is not possible.  The--- rest of the functions are equivalent to 'parseUnsafe', but they specify the--- type being parsed from.  Use them to avoid having to write type annotations--- in cases where the type is ambiguous.---- | Unsafely parse------ @since 0.1.0.0-parseUnsafe :: (HasCallStack, Parse a, Textual t) => t -> a-parseUnsafe = either (error . ("parseUnsafe: " ++)) id . parse-{-# INLINE parseUnsafe #-}---- | Unsafely parse from a 'String'------ @since 0.1.0.0-parseUnsafeS :: (HasCallStack, Parse a) => String -> a-parseUnsafeS = parseUnsafe-{-# INLINE parseUnsafeS #-}---- | Unsafely parse from strict 'T.Text'------ @since 0.1.0.0-parseUnsafeT :: (HasCallStack, Parse a) => T.Text -> a-parseUnsafeT = parseUnsafe-{-# INLINE parseUnsafeT #-}---- | Unsafely parse from lazy 'TL.Text'------ @since 0.1.0.0-parseUnsafeTL :: (HasCallStack, Parse a) => TL.Text -> a-parseUnsafeTL = parseUnsafe-{-# INLINE parseUnsafeTL #-}---- | Unsafely parse from a @Text@ 'TLB.Builder'------ @since 1.1.0.0-parseUnsafeTLB :: (HasCallStack, Parse a) => TLB.Builder -> a-parseUnsafeTLB = parseUnsafe-{-# INLINE parseUnsafeTLB #-}---- | Unsafely parse from a 'ST.ShortText'------ @since 1.4.0.0-parseUnsafeST :: (HasCallStack, Parse a) => ST.ShortText -> a-parseUnsafeST = parseUnsafe-{-# INLINE parseUnsafeST #-}---- | Unsafely parse from a strict 'BS.ByteString'------ @since 0.1.0.0-parseUnsafeBS :: (HasCallStack, Parse a) => BS.ByteString -> a-parseUnsafeBS = parseUnsafe-{-# INLINE parseUnsafeBS #-}---- | Unsafely parse from a lazy 'BSL.ByteString'------ @since 0.1.0.0-parseUnsafeBSL :: (HasCallStack, Parse a) => BSL.ByteString -> a-parseUnsafeBSL = parseUnsafe-{-# INLINE parseUnsafeBSL #-}---- | Unsafely parse from a @ByteString@ 'BSB.Builder'------ @since 1.1.0.0-parseUnsafeBSB :: (HasCallStack, Parse a) => BSB.Builder -> a-parseUnsafeBSB = parseUnsafe-{-# INLINE parseUnsafeBSB #-}---- | Unsafely parse from a 'SBS.ShortByteString'------ @since 1.1.0.0-parseUnsafeSBS :: (HasCallStack, Parse a) => SBS.ShortByteString -> a-parseUnsafeSBS = parseUnsafe-{-# INLINE parseUnsafeSBS #-}----------------------------------------------------------------------------------- $ParseWithASingleErrorMessage------ The 'withError' function takes an error message and a 'Maybe' value.  It--- returns a 'Parse' result: the error when the 'Maybe' value is 'Nothing', or--- the value inside the 'Just'.  This provides a convenient way to return the--- same error message for any parse error.  The rest of the functions are--- equivalent to 'withError', but they specify the type of the error message.--- Use them to avoid having to write type annotations in cases where the type--- is ambiguous.---- | Create a 'Parse' result from a 'Textual' error message and a 'Maybe'--- value------ @since 1.2.0.0-withError-  :: (Textual e', Textual e)-  => e'-  -> Maybe a-  -> Either e a-withError err = maybe (Left $ convert err) Right-{-# INLINE withError #-}---- | Create a 'Parse' result from a 'String' error message and a 'Maybe' value------ @since 1.2.0.0-withErrorS-  :: Textual e-  => String-  -> Maybe a-  -> Either e a-withErrorS = withError-{-# INLINE withErrorS #-}---- | Create a 'Parse' result from a 'T.Text' error message and a 'Maybe' value------ @since 1.2.0.0-withErrorT-  :: Textual e-  => T.Text-  -> Maybe a-  -> Either e a-withErrorT = withError-{-# INLINE withErrorT #-}---- | Create a 'Parse' result from a 'TL.Text' error message and a 'Maybe'--- value------ @since 1.2.0.0-withErrorTL-  :: Textual e-  => TL.Text-  -> Maybe a-  -> Either e a-withErrorTL = withError-{-# INLINE withErrorTL #-}---- | Create a 'Parse' result from a 'TLB.Builder' error message and a 'Maybe'--- value------ @since 1.2.0.0-withErrorTLB-  :: Textual e-  => TLB.Builder-  -> Maybe a-  -> Either e a-withErrorTLB = withError-{-# INLINE withErrorTLB #-}---- | Create a 'Parse' result from a 'ST.ShortText' error message and a 'Maybe'--- value------ @since 1.4.0.0-withErrorST-  :: Textual e-  => ST.ShortText-  -> Maybe a-  -> Either e a-withErrorST = withError-{-# INLINE withErrorST #-}---- | Create a 'Parse' result from a 'BS.ByteString' error message and a--- 'Maybe' value------ @since 1.2.0.0-withErrorBS-  :: Textual e-  => BS.ByteString-  -> Maybe a-  -> Either e a-withErrorBS = withError-{-# INLINE withErrorBS #-}---- | Create a 'Parse' result from a 'BSL.ByteString' error message and a--- 'Maybe' value------ @since 1.2.0.0-withErrorBSL-  :: Textual e-  => BSL.ByteString-  -> Maybe a-  -> Either e a-withErrorBSL = withError-{-# INLINE withErrorBSL #-}---- | Create a 'Parse' result from a 'BSB.Builder' error message and a--- 'Maybe' value------ @since 1.2.0.0-withErrorBSB-  :: Textual e-  => BSB.Builder-  -> Maybe a-  -> Either e a-withErrorBSB = withError-{-# INLINE withErrorBSB #-}---- | Create a 'Parse' result from a 'SBS.ShortByteString' error message and a--- 'Maybe' value------ @since 1.2.0.0-withErrorSBS-  :: Textual e-  => SBS.ShortByteString-  -> Maybe a-  -> Either e a-withErrorSBS = withError-{-# INLINE withErrorSBS #-}----------------------------------------------------------------------------------- $ParseWithAnErrorPrefix------ The 'prefixError' function adds a common prefix to error messages of a--- 'Parse' result.  The rest of the functions are equivalent to 'prefixError',--- but they specify the type of the error message.  Use them to avoid having--- to write type annotations in cases where the type is ambiguous.---- | Add a prefix to 'Textual' error messages of a 'Parse' result------ @since 1.2.0.0-prefixError-  :: (Monoid e', Textual e', Textual e)-  => e'-  -> Either e' a-  -> Either e a-prefixError prefix = either (Left . convert . mappend prefix) Right-{-# INLINE prefixError #-}---- | Add a prefix to 'String' error messages of a 'Parse' result------ @since 1.2.0.0-prefixErrorS-  :: Textual e-  => String-  -> Either String a-  -> Either e a-prefixErrorS = prefixError-{-# INLINE prefixErrorS #-}---- | Add a prefix to 'T.Text' error messages of a 'Parse' result------ @since 1.2.0.0-prefixErrorT-  :: Textual e-  => T.Text-  -> Either T.Text a-  -> Either e a-prefixErrorT = prefixError-{-# INLINE prefixErrorT #-}---- | Add a prefix to 'TL.Text' error messages of a 'Parse' result------ @since 1.2.0.0-prefixErrorTL-  :: Textual e-  => TL.Text-  -> Either TL.Text a-  -> Either e a-prefixErrorTL = prefixError-{-# INLINE prefixErrorTL #-}---- | Add a prefix to 'TLB.Builder' error messages of a 'Parse' result------ @since 1.2.0.0-prefixErrorTLB-  :: Textual e-  => TLB.Builder-  -> Either TLB.Builder a-  -> Either e a-prefixErrorTLB = prefixError-{-# INLINE prefixErrorTLB #-}---- | Add a prefix to 'ST.ShortText' error messages of a 'Parse' result------ @since 1.4.0.0-prefixErrorST-  :: Textual e-  => ST.ShortText-  -> Either ST.ShortText a-  -> Either e a-prefixErrorST = prefixError-{-# INLINE prefixErrorST #-}---- | Add a prefix to 'BS.ByteString' error messages of a 'Parse' result------ @since 1.2.0.0-prefixErrorBS-  :: Textual e-  => BS.ByteString-  -> Either BS.ByteString a-  -> Either e a-prefixErrorBS = prefixError-{-# INLINE prefixErrorBS #-}---- | Add a prefix to 'BSL.ByteString' error messages of a 'Parse' result------ @since 1.2.0.0-prefixErrorBSL-  :: Textual e-  => BSL.ByteString-  -> Either BSL.ByteString a-  -> Either e a-prefixErrorBSL = prefixError-{-# INLINE prefixErrorBSL #-}---- | Add a prefix to 'BSB.Builder' error messages of a 'Parse' result------ @since 1.2.0.0-prefixErrorBSB-  :: Textual e-  => BSB.Builder-  -> Either BSB.Builder a-  -> Either e a-prefixErrorBSB = prefixError-{-# INLINE prefixErrorBSB #-}---- | Add a prefix to 'SBS.ShortByteString' error messages of a 'Parse' result------ @since 1.2.0.0-prefixErrorSBS-  :: Textual e-  => SBS.ShortByteString-  -> Either SBS.ShortByteString a-  -> Either e a-prefixErrorSBS = prefixError-{-# INLINE prefixErrorSBS #-}----------------------------------------------------------------------------------- $ParseEnums---- | Parse a value in an enumeration------ This function is intended to be used with types that have few choices, as--- 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'-  -> Bool        -- ^ accept unique prefixes when 'True'-  -> e           -- ^ invalid input error-  -> e           -- ^ ambiguous input error-  -> t           -- ^ textual input to parse-  -> Either e a  -- ^ error or parsed value-parseEnum allowCI allowPrefix invalidError ambiguousError t =-    let t' = norm $ toT t-    in  case [v | v <- [minBound ..], t' `match` norm (render v)] of-          [v] -> Right v-          []  -> Left invalidError-          _vs -> Left ambiguousError-  where-    norm :: T.Text -> T.Text-    norm = if allowCI then T.toLower else id--    match :: T.Text -> T.Text -> Bool-    match = if allowPrefix then T.isPrefixOf else (==)---- | 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, 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-      (fromS $ "invalid " ++ name)-      (fromS $ "ambiguous " ++ name)-{-# INLINEABLE parseEnum' #-}----------------------------------------------------------------------------------- $ReadInstanced---- | Parse a value using the 'Read' instance------ @since 0.1.0.0-parseWithRead-  :: (Read a, Textual t)-  => e           -- ^ invalid input error-  -> t           -- ^ textual input to parse-  -> Either e a  -- ^ error or parsed value-parseWithRead invalidError = maybe (Left invalidError) Right . readMaybe . toS-{-# INLINEABLE parseWithRead #-}---- | 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-  -> t           -- ^ textual input to parse-  -> Either e a  -- ^ error or parsed value-parseWithRead' name = parseWithRead (fromS $ "invalid " ++ name)-{-# 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-  -> Maybe a  -- ^ parsed value or 'Nothing' if invalid-maybeParseWithRead = readMaybe . toS---- | 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'-  -> Bool  -- ^ accept unique prefixes when 'True'-  -> ReadS a-readsEnum allowCI allowPrefix s =-    case parseEnum allowCI allowPrefix () () s of-      Right v -> [(v, "")]-      Left{}  -> []-{-# INLINEABLE readsEnum #-}---- | 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-readsWithParse s = case parseMaybe s of-    Just v  -> [(v, "")]-    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.------ For more details, see the following article:--- <https://www.extrema.is/articles/ttc-textual-type-classes/validated-constants>---- | Validate a constant at compile-time using a 'Parse' instance------ This function parses the 'String' at compile-time and fails compilation on--- error.  When valid, the result is compiled in, so the result type must have--- a 'THS.Lift' instance.  When this is inconvenient, 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.------ 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---- | This instance enables use of 'valid' without having to type @valid@.  The--- [OverloadedStrings](https://ghc.gitlab.haskell.org/ghc/doc/users_guide/exts/overloaded_strings.html)--- extension must be enabled in the module where this functionality is used.--- Note that this reduces the number of characters in the code, but it can--- also make the code more difficult to understand by somebody who is not--- already familiar with it.  Typing @valid@ gives people a way to investigate--- and understand what is going on.------ 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 instance in GHC 9 or later is as follows:------ @--- (MonadFail m, THS.Quote m, Parse a, THS.Lift a) => IsString (THS.Code m a)--- @------ The type of this instance in previous versions of GHC is as follows:------ @--- (Parse a, THS.Lift a) => IsString (TH.Q (TH.TExp a))--- @------ This functionality can be used as follows in all supported versions of GHC.--- The following is example usage from the @valid@ example:------ @--- sample2 :: Username--- sample2 = $$("alice")--- @------ The parenthesis are not required from GHC 9.  The following is example--- usage from the @valid@ example:------ @--- sample2 :: Username--- sample2 = $$"alice"--- @------ @since 1.3.0.0-#if __GLASGOW_HASKELL__ >= 900-instance (MonadFail m, THS.Quote m, Parse a, THS.Lift a)-    => IsString (THS.Code m a) where-  fromString = valid-#else-instance (Parse a, THS.Lift a) => IsString (TH.Q (TH.TExp a)) where-  fromString = valid-#endif---- | Validate a constant at compile-time using a 'Parse' instance------ This function requires a 'Proxy' of the result type.  Use 'mkValid' to--- avoid having to pass a 'Proxy' during constant definition.------ This function parses the 'String' at compile-time and fails compilation on--- error.  When valid, the 'String' is compiled in, to be parsed again at--- run-time.  Since the result is not compiled in, no 'THS.Lift' instance is--- required.------ 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.------ 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-  -> TH.Q (TH.TExp a)-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 for a type in order to avoid having to write a--- 'Proxy' when defining constants.------ 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.------ 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-  -> TH.DecsQ-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-      , TH.FunD funName' [TH.Clause [] (TH.NormalB body) []]-      ]---- | Validate a constant at compile-time using a 'Parse' instance------ This function requires a 'Proxy' of the result type.  Use 'mkUntypedValid'--- to avoid having to pass a 'Proxy' during constant definition.------ This function parses the 'String' at compile-time and fails compilation on--- error.  When valid, the 'String' is compiled in, to be parsed again at--- run-time.  Since the result is not compiled in, no 'THS.Lift' instance is--- required.------ 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-  -> String-  -> TH.ExpQ-untypedValidOf proxy s = case (`asProxyTypeOf` proxy) <$> parse s of-    Right{} -> [| parseUnsafeS s |]-    Left err -> fail $ "Invalid constant: " ++ err---- | Make a @valid@ function using 'untypedValidOf' for the given type------ 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.  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-  -> TH.DecsQ-mkUntypedValid funName typeName = do-    let funName' = TH.mkName funName-        resultType = pure $ TH.ConT typeName-    funType <- [t| String -> TH.ExpQ |]-    body <- [| untypedValidOf (Proxy :: Proxy $resultType) |]-    return-      [ TH.SigD funName' funType-      , TH.FunD funName' [TH.Clause [] (TH.NormalB body) []]-      ]---- | Make a @valid@ quasi-quoter using 'untypedValidOf' for the given type------ 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-  -> TH.DecsQ-mkUntypedValidQQ funName typeName = do-    let funName' = TH.mkName funName-        resultType = pure $ TH.ConT typeName-    expE <- [| untypedValidOf (Proxy :: Proxy $resultType) |]-    expP <- [| error "pattern not supported" |]-    expT <- [| error "type not supported" |]-    expD <- [| error "declaration not supported" |]-    let body = TH.NormalB $ TH.RecConE 'Q.QuasiQuoter-          [ ('Q.quoteExp, expE)-          , ('Q.quotePat, expP)-          , ('Q.quoteType, expT)-          , ('Q.quoteDec, expD)-          ]-    return-      [ TH.SigD funName' $ TH.ConT ''Q.QuasiQuoter-      , TH.FunD funName' [TH.Clause [] body []]-      ]+-- Description : Textual Type Classes+-- Copyright   : Copyright (c) 2019-2025 Travis Cardwell+-- License     : MIT+--+-- TTC, an initialism of /Textual Type Classes/, is a library that provides+-- type classes for conversion between data types and textual data types+-- (strings).+--+-- The 'Render' type class renders a data type as a textual data type, similar+-- to 'Show'.  Use 'Render' in your business logic, and only use 'Show' for+-- debugging, as use of 'Show' instances in business logic is a common source+-- of bugs.+--+-- The 'Parse' type class parses a data type from a textual data type, similar+-- to 'Read'.  Unlike 'Read', 'Parse' allows you to specify meaningful error+-- messages.+--+-- 'Render' and 'Parse' work with multiple textual data types.  They are not+-- limited to 'String' (like 'Show' and 'Read'), and implementations can use+-- the textual data type that is most appropriate for each data type.+--+-- Conversion between textual data types is managed by the 'Textual' type+-- class.  This library provides instances to support the following textual+-- data types:+--+-- * 'String' (@S@)+-- * Strict 'T.Text' (@T@)+-- * Lazy 'TL.Text' (@TL@)+-- * @Text@ 'TLB.Builder' (@TLB@)+-- * 'ST.ShortText' (@ST@)+-- * Strict 'BS.ByteString' (@BS@)+-- * Lazy 'BSL.ByteString' (@BSL@)+-- * @ByteString@ 'BSB.Builder' (@BSB@)+-- * 'SBS.ShortByteString' (@SBS@)+--+-- This library is meant to be imported qualified, as follows:+--+-- @+-- import qualified Data.TTC as TTC+-- @+--+-- Note that this library has a similar API to the+-- [ETTC](https://github.com/ExtremaIS/ttc-haskell/tree/main/ettc) library,+-- which uses a @Utf8Convertible@ type class instead of 'Textual'.  The TTC+-- API types are simpler, but it is not possible to add support for additional+-- textual data types without changing the library itself.  The ETTC API types+-- are more complex, leading to longer compilation times, but one can add+-- support for additional textual data types by defining new @Utf8Convertible@+-- instances.  Both libraries are maintained, allowing you to use the one that+-- best matches the needs of your project.+------------------------------------------------------------------------------++{-# LANGUAGE CPP #-}+{-# LANGUAGE DefaultSignatures #-}+{-# LANGUAGE ExplicitForAll #-}+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE LambdaCase #-}+{-# LANGUAGE TemplateHaskell #-}+{-# OPTIONS_GHC -fno-warn-orphans #-}++module Data.TTC+  ( -- * Textual+    Textual+  , convert+    -- ** \"To\" Conversions+    -- $TextualTo+  , toS+  , toT+  , toTL+  , toTLB+  , toST+  , toBS+  , toBSL+  , toBSB+  , toSBS+    -- ** \"From\" Conversions+    -- $TextualFrom+  , fromS+  , fromT+  , fromTL+  , fromTLB+  , fromST+  , fromBS+  , fromBSL+  , fromBSB+  , fromSBS+    -- ** \"As\" Conversions+    -- $TextualAs+  , asS+  , asT+  , asTL+  , asTLB+  , asST+  , asBS+  , asBSL+  , asBSB+  , asSBS+    -- * Render+  , Render(..)+  , RenderDefault(..)+    -- ** Render Utility Functions+    -- $RenderUtilityFunctions+  , renderWithShow+    -- ** Rendering Specific Types+    -- $RenderSpecific+  , renderS+  , renderT+  , renderTL+  , renderTLB+  , renderST+  , renderBS+  , renderBSL+  , renderBSB+  , renderSBS+    -- * Parse+  , Parse(..)+  , ParseDefault(..)+    -- ** Parse Utility Functions+    -- $ParseUtilityFunctions+    -- *** Parse With A Single Error Message+    -- $ParseWithASingleErrorMessage+  , withError+  , withErrorS+  , withErrorT+  , withErrorTL+  , withErrorTLB+  , withErrorST+  , withErrorBS+  , withErrorBSL+  , withErrorBSB+  , withErrorSBS+    -- *** Parse With An Error Prefix+    -- $ParseWithAnErrorPrefix+  , prefixError+  , prefixErrorS+  , prefixErrorT+  , prefixErrorTL+  , prefixErrorTLB+  , prefixErrorST+  , prefixErrorBS+  , prefixErrorBSL+  , prefixErrorBSB+  , prefixErrorSBS+    -- *** 'Read' Parsing+  , parseWithRead+  , parseWithRead'+  , maybeParseWithRead+    -- *** 'Enum' Parsing+  , parseEnum+  , parseEnum'+    -- ** Parsing From Specific Types+    -- $ParseSpecific+  , parseS+  , parseT+  , parseTL+  , parseTLB+  , parseST+  , parseBS+  , parseBSL+  , parseBSB+  , parseSBS+    -- ** 'Maybe' Parsing+    -- $ParseMaybe+  , parseMaybe+  , parseMaybeS+  , parseMaybeT+  , parseMaybeTL+  , parseMaybeTLB+  , parseMaybeST+  , parseMaybeBS+  , parseMaybeBSL+  , parseMaybeBSB+  , parseMaybeSBS+    -- ** 'MonadFail' Parsing+    -- $ParseOrFail+  , parseOrFail+  , parseOrFailS+  , parseOrFailT+  , parseOrFailTL+  , parseOrFailTLB+  , parseOrFailST+  , parseOrFailBS+  , parseOrFailBSL+  , parseOrFailBSB+  , parseOrFailSBS+    -- ** Unsafe Parsing+    -- $ParseUnsafe+  , parseUnsafe+  , parseUnsafeS+  , parseUnsafeT+  , parseUnsafeTL+  , parseUnsafeTLB+  , parseUnsafeST+  , parseUnsafeBS+  , parseUnsafeBSL+  , parseUnsafeBSB+  , parseUnsafeSBS+    -- ** 'ReadS' Instances+  , readsWithParse+  , readsEnum+    -- * Template Haskell+    -- ** Constant Validation+    -- $ConstantValidation+  , valid+  , validOf+  , mkValid+  , untypedValidOf+  , mkUntypedValid+  , mkUntypedValidQQ+    -- * Default Instances+    -- $DefaultInstances+  , defaultRenderInstance+  , defaultRenderInstances+  , defaultParseInstance+  , defaultParseInstances+  , defaultRenderAndParseInstance+  , defaultRenderAndParseInstances+  ) where++-- https://hackage.haskell.org/package/base+import Data.Int (Int8, Int16, Int32, Int64)+import Data.Proxy (Proxy(Proxy), asProxyTypeOf)+import Data.String (IsString(fromString))+import Data.Word (Word8, Word16, Word32, Word64)+import GHC.Stack (HasCallStack)+import Text.Read (readMaybe)++-- https://hackage.haskell.org/package/bytestring+import qualified Data.ByteString as BS+import qualified Data.ByteString.Builder as BSB+import qualified Data.ByteString.Lazy as BSL+import qualified Data.ByteString.Short as SBS++-- https://hackage.haskell.org/package/template-haskell+import qualified Language.Haskell.TH as TH+import qualified Language.Haskell.TH.Quote as Q+import qualified Language.Haskell.TH.Syntax as THS++-- https://hackage.haskell.org/package/text+import qualified Data.Text as T+import qualified Data.Text.Encoding as TE+import qualified Data.Text.Encoding.Error as TEE+import qualified Data.Text.Lazy as TL+import qualified Data.Text.Lazy.Builder as TLB+import qualified Data.Text.Lazy.Encoding as TLE++-- https://hackage.haskell.org/package/text-short+import qualified Data.Text.Short as ST++------------------------------------------------------------------------------+-- $Textual++-- | Convert from one textual data type to another+--+-- The following textual data types are supported:+--+-- * 'String' (@S@)+-- * Strict 'T.Text' (@T@)+-- * Lazy 'TL.Text' (@TL@)+-- * @Text@ 'TLB.Builder' (@TLB@)+-- * 'ST.ShortText' (@ST@)+-- * Strict 'BS.ByteString' (@BS@)+-- * Lazy 'BSL.ByteString' (@BSL@)+-- * @ByteString@ 'BSB.Builder' (@BSB@)+-- * 'SBS.ShortByteString' (@SBS@)+--+-- Note that support for additional textual data types cannot be implemented+-- by writing instances.  Adding support for additional textual data types+-- requires changing the class definition itself.  If you need support for+-- additional textual data types, consider using the+-- [ETTC](https://github.com/ExtremaIS/ttc-haskell/tree/main/ettc) library+-- instead.+--+-- Encoded values are assumed to be valid UTF-8 encoded text.  Conversions+-- must be pure, and any invalid bytes must be replaced with the Unicode+-- replacement character @U+FFFD@.  In cases where different behavior is+-- required, process encoded values separately.+--+-- For more details, see the following article:+-- <https://www.extrema.is/articles/ttc-textual-type-classes/textual-type-class>+--+-- @since 0.1.0.0+class Textual t where+  -- | Convert from a textual data type to a 'String'+  --+  -- @since 0.1.0.0+  toS :: t -> String++  -- | Convert from a textual data type to strict 'T.Text'+  --+  -- @since 0.1.0.0+  toT :: t -> T.Text++  -- | Convert from a textual data type to lazy 'TL.Text'+  --+  -- @since 0.1.0.0+  toTL :: t -> TL.Text++  -- | Convert from a textual data type to a @Text@ 'TLB.Builder'+  --+  -- @since 1.1.0.0+  toTLB :: t -> TLB.Builder++  -- | Convert from a textual data type to 'ST.ShortText'+  --+  -- @since 1.4.0.0+  toST :: t -> ST.ShortText++  -- | Convert from a textual data type to a strict 'BS.ByteString'+  --+  -- @since 0.1.0.0+  toBS :: t -> BS.ByteString++  -- | Convert from a textual data type to a lazy 'BS.ByteString'+  --+  -- @since 0.1.0.0+  toBSL :: t -> BSL.ByteString++  -- | Convert from a textual data type to a @ByteString@ 'BSB.Builder'+  --+  -- @since 1.1.0.0+  toBSB :: t -> BSB.Builder++  -- | Convert from a textual data type to a 'SBS.ShortByteString'+  --+  -- @since 1.1.0.0+  toSBS :: t -> SBS.ShortByteString++  -- | Convert from one textual data type to another+  --+  -- @since 0.1.0.0+  convert' :: Textual t' => t' -> t++instance Textual String where+  toS = id+  toT = T.pack+  toTL = TL.pack+  toTLB = TLB.fromString+  toST = ST.fromString+  toBS = TE.encodeUtf8 . T.pack+  toBSL = TLE.encodeUtf8 . TL.pack+  toBSB = BSB.byteString . TE.encodeUtf8 . T.pack+  toSBS = SBS.toShort . TE.encodeUtf8 . T.pack+  convert' = toS+  {-# INLINE toS #-}+  {-# INLINE toT #-}+  {-# INLINE toTL #-}+  {-# INLINE toTLB #-}+  {-# INLINE toST #-}+  {-# INLINE toBS #-}+  {-# INLINE toBSL #-}+  {-# INLINE toBSB #-}+  {-# INLINE toSBS #-}+  {-# INLINE convert' #-}++instance Textual T.Text where+  toS = T.unpack+  toT = id+  toTL = TL.fromStrict+  toTLB = TLB.fromText+  toST = ST.fromText+  toBS = TE.encodeUtf8+  toBSL = TLE.encodeUtf8 . TL.fromStrict+  toBSB = BSB.byteString . TE.encodeUtf8+  toSBS = SBS.toShort . TE.encodeUtf8+  convert' = toT+  {-# INLINE toS #-}+  {-# INLINE toT #-}+  {-# INLINE toTL #-}+  {-# INLINE toTLB #-}+  {-# INLINE toST #-}+  {-# INLINE toBS #-}+  {-# INLINE toBSL #-}+  {-# INLINE toBSB #-}+  {-# INLINE toSBS #-}+  {-# INLINE convert' #-}++instance Textual TL.Text where+  toS = TL.unpack+  toT = TL.toStrict+  toTL = id+  toTLB = TLB.fromLazyText+  toST = ST.fromText . TL.toStrict+  toBS = BSL.toStrict . TLE.encodeUtf8+  toBSL = TLE.encodeUtf8+  toBSB = BSB.lazyByteString . TLE.encodeUtf8+  toSBS = SBS.toShort . BSL.toStrict . TLE.encodeUtf8+  convert' = toTL+  {-# INLINE toS #-}+  {-# INLINE toT #-}+  {-# INLINE toTL #-}+  {-# INLINE toTLB #-}+  {-# INLINE toST #-}+  {-# INLINE toBS #-}+  {-# INLINE toBSL #-}+  {-# INLINE toBSB #-}+  {-# INLINE toSBS #-}+  {-# INLINE convert' #-}++instance Textual TLB.Builder where+  toS = TL.unpack . TLB.toLazyText+  toT = TL.toStrict . TLB.toLazyText+  toTL = TLB.toLazyText+  toTLB = id+  toST = ST.fromText . TL.toStrict . TLB.toLazyText+  toBS = BSL.toStrict . TLE.encodeUtf8 . TLB.toLazyText+  toBSL = TLE.encodeUtf8 . TLB.toLazyText+  toBSB = BSB.lazyByteString . TLE.encodeUtf8 . TLB.toLazyText+  toSBS = SBS.toShort . BSL.toStrict . TLE.encodeUtf8 . TLB.toLazyText+  convert' = toTLB+  {-# INLINE toS #-}+  {-# INLINE toT #-}+  {-# INLINE toTL #-}+  {-# INLINE toTLB #-}+  {-# INLINE toST #-}+  {-# INLINE toBS #-}+  {-# INLINE toBSL #-}+  {-# INLINE toBSB #-}+  {-# INLINE toSBS #-}+  {-# INLINE convert' #-}++instance Textual ST.ShortText where+  toS = ST.toString+  toT = ST.toText+  toTL = TL.fromStrict . ST.toText+  toTLB = TLB.fromText . ST.toText+  toST = id+  toBS = ST.toByteString+  toBSL = BSL.fromStrict . ST.toByteString+  toBSB = BSB.byteString . ST.toByteString+  toSBS = ST.toShortByteString+  convert' = toST+  {-# INLINE toS #-}+  {-# INLINE toT #-}+  {-# INLINE toTL #-}+  {-# INLINE toTLB #-}+  {-# INLINE toST #-}+  {-# INLINE toBS #-}+  {-# INLINE toBSL #-}+  {-# INLINE toBSB #-}+  {-# INLINE toSBS #-}+  {-# INLINE convert' #-}++instance Textual BS.ByteString where+  toS = T.unpack . TE.decodeUtf8With TEE.lenientDecode+  toT = TE.decodeUtf8With TEE.lenientDecode+  toTL = TLE.decodeUtf8With TEE.lenientDecode . BSL.fromStrict+  toTLB = TLB.fromText . TE.decodeUtf8With TEE.lenientDecode+  toST = ST.fromText . TE.decodeUtf8With TEE.lenientDecode+  toBS = id+  toBSL = BSL.fromStrict+  toBSB = BSB.byteString+  toSBS = SBS.toShort+  convert' = toBS+  {-# INLINE toS #-}+  {-# INLINE toT #-}+  {-# INLINE toTL #-}+  {-# INLINE toTLB #-}+  {-# INLINE toST #-}+  {-# INLINE toBS #-}+  {-# INLINE toBSL #-}+  {-# INLINE toBSB #-}+  {-# INLINE toSBS #-}+  {-# INLINE convert' #-}++instance Textual BSL.ByteString where+  toS = TL.unpack . TLE.decodeUtf8With TEE.lenientDecode+  toT = TL.toStrict . TLE.decodeUtf8With TEE.lenientDecode+  toTL = TLE.decodeUtf8With TEE.lenientDecode+  toTLB = TLB.fromLazyText . TLE.decodeUtf8With TEE.lenientDecode+  toST = ST.fromText . TL.toStrict . TLE.decodeUtf8With TEE.lenientDecode+  toBS = BSL.toStrict+  toBSL = id+  toBSB = BSB.lazyByteString+  toSBS = SBS.toShort . BSL.toStrict+  convert' = toBSL+  {-# INLINE toS #-}+  {-# INLINE toT #-}+  {-# INLINE toTL #-}+  {-# INLINE toTLB #-}+  {-# INLINE toST #-}+  {-# INLINE toBS #-}+  {-# INLINE toBSL #-}+  {-# INLINE toBSB #-}+  {-# INLINE toSBS #-}+  {-# INLINE convert' #-}++instance Textual BSB.Builder where+  toS =+    TL.unpack . TLE.decodeUtf8With TEE.lenientDecode . BSB.toLazyByteString+  toT =+    TL.toStrict . TLE.decodeUtf8With TEE.lenientDecode . BSB.toLazyByteString+  toTL = TLE.decodeUtf8With TEE.lenientDecode . BSB.toLazyByteString+  toTLB+    = TLB.fromLazyText+    . TLE.decodeUtf8With TEE.lenientDecode+    . BSB.toLazyByteString+  toST+    = ST.fromText+    . TL.toStrict+    . TLE.decodeUtf8With TEE.lenientDecode+    . BSB.toLazyByteString+  toBS = BSL.toStrict . BSB.toLazyByteString+  toBSL = BSB.toLazyByteString+  toBSB = id+  toSBS = SBS.toShort . BSL.toStrict . BSB.toLazyByteString+  convert' = toBSB+  {-# INLINE toS #-}+  {-# INLINE toT #-}+  {-# INLINE toTL #-}+  {-# INLINE toTLB #-}+  {-# INLINE toST #-}+  {-# INLINE toBS #-}+  {-# INLINE toBSL #-}+  {-# INLINE toBSB #-}+  {-# INLINE toSBS #-}+  {-# INLINE convert' #-}++instance Textual SBS.ShortByteString where+  toS = T.unpack . TE.decodeUtf8With TEE.lenientDecode . SBS.fromShort+  toT = TE.decodeUtf8With TEE.lenientDecode . SBS.fromShort+  toTL = TLE.decodeUtf8With TEE.lenientDecode . BSL.fromStrict . SBS.fromShort+  toTLB = TLB.fromText . TE.decodeUtf8With TEE.lenientDecode . SBS.fromShort+  toST = ST.fromText . TE.decodeUtf8With TEE.lenientDecode . SBS.fromShort+  toBS = SBS.fromShort+  toBSL = BSL.fromStrict . SBS.fromShort+  toBSB = BSB.byteString . SBS.fromShort+  toSBS = id+  convert' = toSBS+  {-# INLINE toS #-}+  {-# INLINE toT #-}+  {-# INLINE toTL #-}+  {-# INLINE toTLB #-}+  {-# INLINE toST #-}+  {-# INLINE toBS #-}+  {-# INLINE toBSL #-}+  {-# INLINE toBSB #-}+  {-# INLINE toSBS #-}+  {-# INLINE convert' #-}++------------------------------------------------------------------------------++-- | Convert from one textual data type to another+--+-- The order of the type arguments was changed in version 1.5.0.0.+--+-- @since 0.1.0.0+convert :: forall t t'. (Textual t, Textual t') => t -> t'+convert = convert'+{-# INLINE convert #-}++------------------------------------------------------------------------------+-- $TextualTo+--+-- These functions are equivalent to 'convert', but they specify the type+-- being converted to.  Use them to avoid having to write type annotations in+-- cases where the type is ambiguous.  Using these functions may make code+-- easier to understand even in cases where the types are not ambiguous.++-- $TextualFrom+--+-- These functions are equivalent to 'convert', but they specify the type+-- being converted from.  Use them to avoid having to write type annotations+-- in cases where the type is ambiguous.  Using these functions may make code+-- easier to understand even in cases where the types are not ambiguous.++-- | Convert from a 'String' to a textual data type+--+-- @since 0.1.0.0+fromS :: Textual t => String -> t+fromS = convert'+{-# INLINE fromS #-}++-- | Convert from strict 'T.Text' to a textual data type+--+-- @since 0.1.0.0+fromT :: Textual t => T.Text -> t+fromT = convert'+{-# INLINE fromT #-}++-- | Convert from lazy 'TL.Text' to a textual data type+--+-- @since 0.1.0.0+fromTL :: Textual t => TL.Text -> t+fromTL = convert'+{-# INLINE fromTL #-}++-- | Convert from a @Text@ 'TLB.Builder' to a textual data type+--+-- @since 1.1.0.0+fromTLB :: Textual t => TLB.Builder -> t+fromTLB = convert'+{-# INLINE fromTLB #-}++-- | Convert from a 'ST.ShortText' to a textual data type+--+-- @since 1.4.0.0+fromST :: Textual t => ST.ShortText -> t+fromST = convert'+{-# INLINE fromST #-}++-- | Convert from a strict 'BS.ByteString' to a textual data type+--+-- @since 0.1.0.0+fromBS :: Textual t => BS.ByteString -> t+fromBS = convert'+{-# INLINE fromBS #-}++-- | Convert from a lazy 'BSL.ByteString' to a textual data type+--+-- @since 0.1.0.0+fromBSL :: Textual t => BSL.ByteString -> t+fromBSL = convert'+{-# INLINE fromBSL #-}++-- | Convert from a @ByteString@ 'TLB.Builder' to a textual data type+--+-- @since 1.1.0.0+fromBSB :: Textual t => BSB.Builder -> t+fromBSB = convert'+{-# INLINE fromBSB #-}++-- | Convert from a 'SBS.ShortByteString' to a textual data type+--+-- @since 1.1.0.0+fromSBS :: Textual t => SBS.ShortByteString -> t+fromSBS = convert'+{-# INLINE fromSBS #-}++------------------------------------------------------------------------------+-- $TextualAs+--+-- These functions are used to convert a textual data type argument to a+-- specific type.  Use them to reduce boilerplate in small function+-- definitions.++-- | Convert a textual data type argument to a 'String'+--+-- @since 0.1.0.0+asS :: forall t a. Textual t => (String -> a) -> t -> a+asS f = f . convert'+{-# INLINE asS #-}++-- | Convert a textual data type argument to strict 'T.Text'+--+-- @since 0.1.0.0+asT :: forall t a. Textual t => (T.Text -> a) -> t -> a+asT f = f . convert'+{-# INLINE asT #-}++-- | Convert a textual data type argument to lazy 'TL.Text'+--+-- @since 0.1.0.0+asTL :: forall t a. Textual t => (TL.Text -> a) -> t -> a+asTL f = f . convert'+{-# INLINE asTL #-}++-- | Convert a textual data type argument to a @Text@ 'TLB.Builder'+--+-- @since 1.1.0.0+asTLB :: forall t a. Textual t => (TLB.Builder -> a) -> t -> a+asTLB f = f . convert'+{-# INLINE asTLB #-}++-- | Convert a textual data type argument to a 'ST.ShortText'+--+-- @since 1.4.0.0+asST :: forall t a. Textual t => (ST.ShortText -> a) -> t -> a+asST f = f . convert'+{-# INLINE asST #-}++-- | Convert a textual data type argument to a strict 'BS.ByteString'+--+-- @since 0.1.0.0+asBS :: forall t a. Textual t => (BS.ByteString -> a) -> t -> a+asBS f = f . convert'+{-# INLINE asBS #-}++-- | Convert a textual data type argument to a lazy 'BSL.ByteString'+--+-- @since 0.1.0.0+asBSL :: forall t a. Textual t => (BSL.ByteString -> a) -> t -> a+asBSL f = f . convert'+{-# INLINE asBSL #-}++-- | Convert a textual data type argument to a @ByteString@ 'TLB.Builder'+--+-- @since 1.1.0.0+asBSB :: forall t a. Textual t => (BSB.Builder -> a ) -> t -> a+asBSB f = f . convert'+{-# INLINE asBSB #-}++-- | Convert a textual data type argument to a 'SBS.ShortByteString'+--+-- @since 1.1.0.0+asSBS :: forall t a. Textual t => (SBS.ShortByteString -> a) -> t -> a+asSBS f = f . convert'+{-# INLINE asSBS #-}++------------------------------------------------------------------------------+-- $Render++-- | Render a data type as a textual data type+--+-- Use 'Render' in your business logic, and only use 'Show' for debugging, as+-- use of 'Show' instances in business logic is a common source of bugs.+--+-- When defining an instance, render to the textual data type that is most+-- natural for the data type, and then use 'convert' to handle the conversion+-- to any textual data type.  This is particularly wrappers around a textual+-- data type.  Example:+--+-- @+-- newtype Username = Username { usernameText :: Text }+--+-- instance TTC.Render Username where+--   render = TTC.convert . usernameText+-- @+--+-- To use @render@ in a context where the types are ambiguous, use the+-- [@TypeApplications@](https://ghc.gitlab.haskell.org/ghc/doc/users_guide/exts/type_applications.html)+-- GHC extension to specify one or both types.  Example:+--+-- @+-- -- Render to Text+-- render @_ @Text foo+-- @+--+-- Alternatively, use one of the functions that render to a specific textual+-- data type (such as 'renderS').  Using these functions may make code easier+-- to understand even in cases where the types are not ambiguous.+--+-- See the @uname@ and @prompt@ example programs in the @ttc-examples@+-- directory of the source repository.+--+-- For more details, see the following article:+-- <https://www.extrema.is/articles/ttc-textual-type-classes/render-and-parse>+--+-- Since a type may have at most one instance of a given type class, special+-- care must be taken when defining type class instances in a shared library.+-- In particular, orphan instances should generally not be used in shared+-- libraries since they prevent users of the libraries from writing their own+-- instances.  Use @newtype@ wrappers instead.+--+-- There are no default instances for the 'Render' type class, so that all+-- instances can be customized per project when desired.  Instances for some+-- basic data types are defined for the 'RenderDefault' type class, however,+-- and the Template Haskell functions documented below can be used to load+-- these definitions with minimal boilerplate.+--+-- @since 0.1.0.0+class Render a where+  -- | Render a data type as a textual data type+  --+  -- @since 0.1.0.0+  render :: Textual t => a -> t++  default render :: (RenderDefault a, Textual t) => a -> t+  render = renderDefault++------------------------------------------------------------------------------++-- | Default 'Render' instances for some common types+--+-- * The 'Bool' instance renders using the 'Show' instance.  This instance was+--   added in version 1.5.0.0.+-- * The 'Char' instance renders a single-character string.+-- * Numeric type instances all render using the 'Show' instance.+-- * Textual data type instances all convert to the target textual data type.+--+-- @since 1.1.0.0+class RenderDefault a where+  -- | Render a data type as a textual data type+  --+  -- @since 1.1.0.0+  renderDefault :: Textual t => a -> t++instance RenderDefault Bool where+  renderDefault = renderWithShow++instance RenderDefault Char where+  renderDefault c = fromS [c]++instance RenderDefault Double where+  renderDefault = renderWithShow++instance RenderDefault Float where+  renderDefault = renderWithShow++instance RenderDefault Integer where+  renderDefault = renderWithShow++instance RenderDefault Int where+  renderDefault = renderWithShow++instance RenderDefault Int8 where+  renderDefault = renderWithShow++instance RenderDefault Int16 where+  renderDefault = renderWithShow++instance RenderDefault Int32 where+  renderDefault = renderWithShow++instance RenderDefault Int64 where+  renderDefault = renderWithShow++instance RenderDefault Word where+  renderDefault = renderWithShow++instance RenderDefault Word8 where+  renderDefault = renderWithShow++instance RenderDefault Word16 where+  renderDefault = renderWithShow++instance RenderDefault Word32 where+  renderDefault = renderWithShow++instance RenderDefault Word64 where+  renderDefault = renderWithShow++instance RenderDefault String where+  renderDefault = fromS++instance RenderDefault T.Text where+  renderDefault = fromT++instance RenderDefault TL.Text where+  renderDefault = fromTL++instance RenderDefault TLB.Builder where+  renderDefault = fromTLB++instance RenderDefault ST.ShortText where+  renderDefault = fromST++instance RenderDefault BS.ByteString where+  renderDefault = fromBS++instance RenderDefault BSL.ByteString where+  renderDefault = fromBSL++instance RenderDefault BSB.Builder where+  renderDefault = fromBSB++instance RenderDefault SBS.ShortByteString where+  renderDefault = fromSBS++------------------------------------------------------------------------------+-- $RenderUtilityFunctions+--+-- These functions are used to implement 'Render' instances.++-- | Render a value to a textual data type using a 'Show' instance+--+-- To use this function in a context where the types are ambiguous, use the+-- [@TypeApplications@](https://ghc.gitlab.haskell.org/ghc/doc/users_guide/exts/type_applications.html)+-- GHC extension to specify one or both types.  Example:+--+-- @+-- -- Render to Text+-- renderWithShow @Text foo+-- @+--+-- See the @enum@ example program in the @ttc-examples@ directory of the+-- source repository.+--+-- @since 0.1.0.0+renderWithShow :: forall t a. (Show a, Textual t) => a -> t+renderWithShow = convert' . show+{-# INLINE renderWithShow #-}++------------------------------------------------------------------------------+-- $RenderSpecific+--+-- These functions are equivalent to 'render', but they specify the textual+-- data type being rendered to.  Use them to avoid having to write type+-- annotations in cases where the type is ambiguous.  Using these functions+-- may make code easier to understand even in cases where the types are not+-- 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 @Text@ 'TLB.Builder'+--+-- @since 0.4.0.0+renderTLB :: Render a => a -> TLB.Builder+renderTLB = render+{-# INLINE renderTLB #-}++-- | Render to a 'ST.ShortText'+--+-- @since 1.4.0.0+renderST :: Render a => a -> ST.ShortText+renderST = render+{-# INLINE renderST #-}++-- | 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 @ByteString@ 'BSB.Builder'+--+-- @since 0.4.0.0+renderBSB :: Render a => a -> BSB.Builder+renderBSB = render+{-# INLINE renderBSB #-}++-- | Render to a 'SBS.ShortByteString'+--+-- @since 0.4.0.0+renderSBS :: Render a => a -> SBS.ShortByteString+renderSBS = render+{-# INLINE renderSBS #-}++------------------------------------------------------------------------------+-- $Parse++-- | Parse a data type from a textual data type+--+-- Unlike 'Read', 'Parse' allows you to specify meaningful error messages.+--+-- When defining an instance, first convert the textual data type to the+-- textual data type that is most natural for the data type.  The @as@+-- functions (such as 'asS') provide a convenient way to do this.  Note that+-- error is also a textual data type.  The 'withError' and 'prefixError'+-- functions can be used to reduce boilerplate.  Example:+--+-- @+-- newtype Username = Username { usernameText :: Text }+--+-- instance TTC.Parse Username where+--   parse = TTC.asT $ \t -> TTC.prefixErrorS "invalid username: " $ do+--     unless (T.all isAsciiLower t) $ Left "not only lowercase ASCII letters"+--     let len = T.length t+--     when (len < 3) $ Left "fewer than 3 characters"+--     when (len > 12) $ Left "more than 12 characters"+--     pure $ Username t+-- @+--+-- To use @parse@ in a context where the types are ambiguous, use the+-- [@TypeApplications@](https://ghc.gitlab.haskell.org/ghc/doc/users_guide/exts/type_applications.html)+-- GHC extension to specify one or more types.  Example:+--+-- @+-- -- Parse from Text+-- parse @_ @Text foo+--+-- -- Parse using String errors+-- parse @_ @_ @String foo+--+-- -- Parse from Text using String errors+-- parse @_ @Text @String foo+-- @+--+-- Alternatively, use one of the functions that parse from a specific textual+-- data type (such as 'renderS').  Using these functions may make code easier+-- to understand even in cases where the types are not ambiguous.+--+-- See the @uname@ and @prompt@ example programs in the @ttc-examples@+-- directory of the source repository.+--+-- For more details, see the following article:+-- <https://www.extrema.is/articles/ttc-textual-type-classes/render-and-parse>+--+-- Since a type may have at most one instance of a given type class, special+-- care must be taken when defining type class instances in a shared library.+-- In particular, orphan instances should generally not be used in shared+-- libraries since they prevent users of the libraries from writing their own+-- instances.  Use @newtype@ wrappers instead.+--+-- There are no default instances for the 'Parse' type class, so that all+-- instances can be customized per project when desired.  Instances for some+-- basic data types are defined for the 'ParseDefault' type class, however,+-- and the Template Haskell functions documented below can be used to load+-- these definitions with minimal boilerplate.+--+-- @since 0.3.0.0+class Parse a where+  -- | Parse a data type from a textual data type+  --+  -- @since 0.3.0.0+  parse :: (Textual t, Textual e) => t -> Either e a++  default parse :: (Textual t, Textual e, ParseDefault a) => t -> Either e a+  parse = parseDefault++-- 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' :: forall t a. (Parse a, Textual t) => t -> Either String a+parse' = parse+{-# INLINE parse' #-}++------------------------------------------------------------------------------++-- | The 'ParseDefault' type class provides some default 'Parse' instances.+--+-- * The 'Bool' instance parses using the 'Read' instance.  This instance was+--   added in version 1.5.0.0.+-- * The 'Char' instance parses single-character strings.+-- * Numeric type instances all parse using the 'Read' instance.+-- * Textual data type instances all convert from the source textual data+--   type.+--+-- @since 1.1.0.0+class ParseDefault a where+  -- | Parse a data type from a textual data type+  --+  -- @since 1.1.0.0+  parseDefault :: (Textual t, Textual e) => t -> Either e a++instance ParseDefault Bool where+  parseDefault = parseWithRead' "Bool"++instance ParseDefault Char where+  parseDefault = asS $ \case+    [c] -> Right c+    _cs -> Left $ fromS "invalid Char"++instance ParseDefault Double where+  parseDefault = parseWithRead' "Double"++instance ParseDefault Float where+  parseDefault = parseWithRead' "Float"++instance ParseDefault Integer where+  parseDefault = parseWithRead' "Integer"++instance ParseDefault Int where+  parseDefault = parseWithRead' "Int"++instance ParseDefault Int8 where+  parseDefault = parseWithRead' "Int8"++instance ParseDefault Int16 where+  parseDefault = parseWithRead' "Int16"++instance ParseDefault Int32 where+  parseDefault = parseWithRead' "Int32"++instance ParseDefault Int64 where+  parseDefault = parseWithRead' "Int64"++instance ParseDefault Word where+  parseDefault = parseWithRead' "Word"++instance ParseDefault Word8 where+  parseDefault = parseWithRead' "Word8"++instance ParseDefault Word16 where+  parseDefault = parseWithRead' "Word16"++instance ParseDefault Word32 where+  parseDefault = parseWithRead' "Word32"++instance ParseDefault Word64 where+  parseDefault = parseWithRead' "Word64"++instance ParseDefault String where+  parseDefault = Right . toS++instance ParseDefault T.Text where+  parseDefault = Right . toT++instance ParseDefault TL.Text where+  parseDefault = Right . toTL++instance ParseDefault TLB.Builder where+  parseDefault = Right . toTLB++instance ParseDefault ST.ShortText where+  parseDefault = Right . toST++instance ParseDefault BS.ByteString where+  parseDefault = Right . toBS++instance ParseDefault BSL.ByteString where+  parseDefault = Right . toBSL++instance ParseDefault BSB.Builder where+  parseDefault = Right . toBSB++instance ParseDefault SBS.ShortByteString where+  parseDefault = Right . toSBS++------------------------------------------------------------------------------+-- $ParseUtilityFunctions+--+-- These functions are used to implement 'Parse' instances.++------------------------------------------------------------------------------+-- $ParseWithASingleErrorMessage+--+-- The 'withError' function takes an error message and a 'Maybe' value.  It+-- returns a 'Parse' result: the error when the 'Maybe' value is 'Nothing', or+-- the value inside the 'Just'.  This provides a convenient way to return the+-- same error message for any parse error.  The rest of the functions are+-- equivalent to 'withError', but they specify the type of the error message.+-- Use them to avoid having to write type annotations in cases where the type+-- is ambiguous.++-- | Create a 'Parse' result from a 'Textual' error message and a 'Maybe'+-- value+--+-- @since 1.2.0.0+withError+  :: forall e' e a. (Textual e', Textual e)+  => e'+  -> Maybe a+  -> Either e a+withError err = maybe (Left $ convert' err) Right+{-# INLINE withError #-}++-- | Create a 'Parse' result from a 'String' error message and a 'Maybe' value+--+-- @since 1.2.0.0+withErrorS+  :: forall e a. Textual e+  => String+  -> Maybe a+  -> Either e a+withErrorS = withError+{-# INLINE withErrorS #-}++-- | Create a 'Parse' result from a 'T.Text' error message and a 'Maybe' value+--+-- @since 1.2.0.0+withErrorT+  :: forall e a. Textual e+  => T.Text+  -> Maybe a+  -> Either e a+withErrorT = withError+{-# INLINE withErrorT #-}++-- | Create a 'Parse' result from a 'TL.Text' error message and a 'Maybe'+-- value+--+-- @since 1.2.0.0+withErrorTL+  :: forall e a. Textual e+  => TL.Text+  -> Maybe a+  -> Either e a+withErrorTL = withError+{-# INLINE withErrorTL #-}++-- | Create a 'Parse' result from a 'TLB.Builder' error message and a 'Maybe'+-- value+--+-- @since 1.2.0.0+withErrorTLB+  :: forall e a. Textual e+  => TLB.Builder+  -> Maybe a+  -> Either e a+withErrorTLB = withError+{-# INLINE withErrorTLB #-}++-- | Create a 'Parse' result from a 'ST.ShortText' error message and a 'Maybe'+-- value+--+-- @since 1.4.0.0+withErrorST+  :: forall e a. Textual e+  => ST.ShortText+  -> Maybe a+  -> Either e a+withErrorST = withError+{-# INLINE withErrorST #-}++-- | Create a 'Parse' result from a 'BS.ByteString' error message and a+-- 'Maybe' value+--+-- @since 1.2.0.0+withErrorBS+  :: forall e a. Textual e+  => BS.ByteString+  -> Maybe a+  -> Either e a+withErrorBS = withError+{-# INLINE withErrorBS #-}++-- | Create a 'Parse' result from a 'BSL.ByteString' error message and a+-- 'Maybe' value+--+-- @since 1.2.0.0+withErrorBSL+  :: forall e a. Textual e+  => BSL.ByteString+  -> Maybe a+  -> Either e a+withErrorBSL = withError+{-# INLINE withErrorBSL #-}++-- | Create a 'Parse' result from a 'BSB.Builder' error message and a+-- 'Maybe' value+--+-- @since 1.2.0.0+withErrorBSB+  :: forall e a. Textual e+  => BSB.Builder+  -> Maybe a+  -> Either e a+withErrorBSB = withError+{-# INLINE withErrorBSB #-}++-- | Create a 'Parse' result from a 'SBS.ShortByteString' error message and a+-- 'Maybe' value+--+-- @since 1.2.0.0+withErrorSBS+  :: forall e a. Textual e+  => SBS.ShortByteString+  -> Maybe a+  -> Either e a+withErrorSBS = withError+{-# INLINE withErrorSBS #-}++------------------------------------------------------------------------------+-- $ParseWithAnErrorPrefix+--+-- The 'prefixError' function adds a common prefix to error messages of a+-- 'Parse' result.  The rest of the functions are equivalent to 'prefixError',+-- but they specify the type of the error message.  Use them to avoid having+-- to write type annotations in cases where the type is ambiguous.++-- | Add a prefix to 'Textual' error messages of a 'Parse' result+--+-- @since 1.2.0.0+prefixError+  :: forall e' e a. (Monoid e', Textual e', Textual e)+  => e'+  -> Either e' a+  -> Either e a+prefixError prefix = either (Left . convert' . mappend prefix) Right+{-# INLINE prefixError #-}++-- | Add a prefix to 'String' error messages of a 'Parse' result+--+-- @since 1.2.0.0+prefixErrorS+  :: forall e a. Textual e+  => String+  -> Either String a+  -> Either e a+prefixErrorS = prefixError+{-# INLINE prefixErrorS #-}++-- | Add a prefix to 'T.Text' error messages of a 'Parse' result+--+-- @since 1.2.0.0+prefixErrorT+  :: forall e a. Textual e+  => T.Text+  -> Either T.Text a+  -> Either e a+prefixErrorT = prefixError+{-# INLINE prefixErrorT #-}++-- | Add a prefix to 'TL.Text' error messages of a 'Parse' result+--+-- @since 1.2.0.0+prefixErrorTL+  :: forall e a. Textual e+  => TL.Text+  -> Either TL.Text a+  -> Either e a+prefixErrorTL = prefixError+{-# INLINE prefixErrorTL #-}++-- | Add a prefix to 'TLB.Builder' error messages of a 'Parse' result+--+-- @since 1.2.0.0+prefixErrorTLB+  :: forall e a. Textual e+  => TLB.Builder+  -> Either TLB.Builder a+  -> Either e a+prefixErrorTLB = prefixError+{-# INLINE prefixErrorTLB #-}++-- | Add a prefix to 'ST.ShortText' error messages of a 'Parse' result+--+-- @since 1.4.0.0+prefixErrorST+  :: forall e a. Textual e+  => ST.ShortText+  -> Either ST.ShortText a+  -> Either e a+prefixErrorST = prefixError+{-# INLINE prefixErrorST #-}++-- | Add a prefix to 'BS.ByteString' error messages of a 'Parse' result+--+-- @since 1.2.0.0+prefixErrorBS+  :: forall e a. Textual e+  => BS.ByteString+  -> Either BS.ByteString a+  -> Either e a+prefixErrorBS = prefixError+{-# INLINE prefixErrorBS #-}++-- | Add a prefix to 'BSL.ByteString' error messages of a 'Parse' result+--+-- @since 1.2.0.0+prefixErrorBSL+  :: forall e a. Textual e+  => BSL.ByteString+  -> Either BSL.ByteString a+  -> Either e a+prefixErrorBSL = prefixError+{-# INLINE prefixErrorBSL #-}++-- | Add a prefix to 'BSB.Builder' error messages of a 'Parse' result+--+-- @since 1.2.0.0+prefixErrorBSB+  :: forall e a. Textual e+  => BSB.Builder+  -> Either BSB.Builder a+  -> Either e a+prefixErrorBSB = prefixError+{-# INLINE prefixErrorBSB #-}++-- | Add a prefix to 'SBS.ShortByteString' error messages of a 'Parse' result+--+-- @since 1.2.0.0+prefixErrorSBS+  :: forall e a. Textual e+  => SBS.ShortByteString+  -> Either SBS.ShortByteString a+  -> Either e a+prefixErrorSBS = prefixError+{-# INLINE prefixErrorSBS #-}++------------------------------------------------------------------------------+-- $ReadParsing++-- | Parse a value using a 'Read' instance+--+-- @since 0.1.0.0+parseWithRead+  :: forall t e a. (Read a, Textual t)+  => e           -- ^ invalid input error+  -> t           -- ^ textual input to parse+  -> Either e a  -- ^ error or parsed value+parseWithRead invalidError = maybe (Left invalidError) Right . readMaybe . toS+{-# INLINEABLE parseWithRead #-}++-- | Parse a value using a 'Read' instance with default error messages+--+-- The following English error message is returned:+--+-- * \"invalid {name}\" when the parse fails+--+-- @since 0.3.0.0+parseWithRead'+  :: forall t e a. (Read a, Textual t, Textual e)+  => String      -- ^ name to include in error messages+  -> t           -- ^ textual input to parse+  -> Either e a  -- ^ error or parsed value+parseWithRead' name = parseWithRead (fromS $ "invalid " ++ name)+{-# INLINEABLE parseWithRead' #-}++-- | Parse a value to a 'Maybe' result using a 'Read' instance+--+-- @since 0.3.0.0+maybeParseWithRead+  :: forall t a. (Read a, Textual t)+  => t        -- ^ textual input to parse+  -> Maybe a  -- ^ parsed value or 'Nothing' if invalid+maybeParseWithRead = readMaybe . toS++------------------------------------------------------------------------------+-- $EnumParsing++-- | Parse a value in an enumeration+--+-- The 'Render' instance determines the textual values to parse from.+--+-- This function is intended to be used with types that have few choices, as+-- the implementation uses a linear algorithm.+--+-- See the @enum@ example program in the @ttc-examples@ directory of the+-- source repository.+--+-- @since 0.1.0.0+parseEnum+  :: forall t e a. (Bounded a, Enum a, Render a, Textual t)+  => Bool        -- ^ case-insensitive when 'True'+  -> Bool        -- ^ accept unique prefixes when 'True'+  -> e           -- ^ invalid input error+  -> e           -- ^ ambiguous input error+  -> t           -- ^ textual input to parse+  -> Either e a  -- ^ error or parsed value+parseEnum allowCI allowPrefix invalidError ambiguousError t =+    let t' = norm $ toT t+    in  case [v | v <- [minBound ..], t' `match` norm (render v)] of+          [v] -> Right v+          []  -> Left invalidError+          _vs -> Left ambiguousError+  where+    norm :: T.Text -> T.Text+    norm = if allowCI then T.toLower else id++    match :: T.Text -> T.Text -> Bool+    match = if allowPrefix then T.isPrefixOf else (==)++-- | Parse a value in an enumeration using default error messages+--+-- The 'Render' instance determines the textual values to parse from.+--+-- The following English error messages are returned:+--+-- * \"invalid {name}\" when there are no matches+-- * \"ambiguous {name}\" when there is more than one match+--+-- This function is intended to be used with types that have few choices, as+-- the implementation uses a linear algorithm.+--+-- @since 0.4.0.0+parseEnum'+  :: forall t e a. (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+      (fromS $ "invalid " ++ name)+      (fromS $ "ambiguous " ++ name)+{-# INLINEABLE parseEnum' #-}++------------------------------------------------------------------------------+-- $ParseSpecific+--+-- These functions are equivalent to 'parse', but they specify the textual+-- data type being parsed from.  Use them to avoid having to write type+-- annotations in cases where the type is ambiguous.  Using these functions+-- may make code easier to understand even in cases where the types are not+-- ambiguous.++-- | Parse from a 'String'+--+-- @since 0.3.0.0+parseS :: forall e a. (Parse a, Textual e) => String -> Either e a+parseS = parse+{-# INLINE parseS #-}++-- | Parse from strict 'T.Text'+--+-- @since 0.3.0.0+parseT :: forall e a. (Parse a, Textual e) => T.Text -> Either e a+parseT = parse+{-# INLINE parseT #-}++-- | Parse from lazy 'TL.Text'+--+-- @since 0.3.0.0+parseTL :: forall e a. (Parse a, Textual e) => TL.Text -> Either e a+parseTL = parse+{-# INLINE parseTL #-}++-- | Parse from a @Text@ 'TLB.Builder'+--+-- @since 1.1.0.0+parseTLB :: forall e a. (Parse a, Textual e) => TLB.Builder -> Either e a+parseTLB = parse+{-# INLINE parseTLB #-}++-- | Parse from a 'ST.ShortText'+--+-- @since 1.4.0.0+parseST :: forall e a. (Parse a, Textual e) => ST.ShortText -> Either e a+parseST = parse+{-# INLINE parseST #-}++-- | Parse from a strict 'BS.ByteString'+--+-- @since 0.3.0.0+parseBS :: forall e a. (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 :: forall e a. (Parse a, Textual e) => BSL.ByteString -> Either e a+parseBSL = parse+{-# INLINE parseBSL #-}++-- | Parse from a @ByteString@ 'BSB.Builder'+--+-- @since 1.1.0.0+parseBSB :: forall e a. (Parse a, Textual e) => BSB.Builder -> Either e a+parseBSB = parse+{-# INLINE parseBSB #-}++-- | Parse from a 'SBS.ShortByteString'+--+-- @since 1.1.0.0+parseSBS+  :: forall e a. (Parse a, Textual e)+  => SBS.ShortByteString+  -> Either e a+parseSBS = parse+{-# INLINE parseSBS #-}++------------------------------------------------------------------------------+-- $ParseMaybe+--+-- The 'parseMaybe' function parses to a 'Maybe' result instead of an 'Either'+-- result.+--+-- The rest of the functions are equivalent to 'parseMaybe', but they specify+-- the type being parsed from.  Use them to avoid having to write type+-- annotations in cases where the type is ambiguous.  Using these functions+-- may make code easier to understand even in cases where the types are not+-- ambiguous.++-- | Parse to a 'Maybe' result+--+-- @since 0.3.0.0+parseMaybe :: forall t a. (Parse a, Textual t) => t -> Maybe a+parseMaybe = either (const Nothing) Just . parse'+{-# INLINE parseMaybe #-}++-- | Parse from a 'String' to a 'Maybe' result+--+-- @since 0.3.0.0+parseMaybeS :: Parse a => String -> Maybe a+parseMaybeS = parseMaybe+{-# INLINE parseMaybeS #-}++-- | Parse from strict 'T.Text' to a 'Maybe' result+--+-- @since 0.3.0.0+parseMaybeT :: Parse a => T.Text -> Maybe a+parseMaybeT = parseMaybe+{-# INLINE parseMaybeT #-}++-- | Parse from lazy 'TL.Text' to a 'Maybe' result+--+-- @since 0.3.0.0+parseMaybeTL :: Parse a => TL.Text -> Maybe a+parseMaybeTL = parseMaybe+{-# INLINE parseMaybeTL #-}++-- | Parse from a @Text@ 'TLB.Builder' to a 'Maybe' result+--+-- @since 1.1.0.0+parseMaybeTLB :: Parse a => TLB.Builder -> Maybe a+parseMaybeTLB = parseMaybe+{-# INLINE parseMaybeTLB #-}++-- | Parse from a 'ST.ShortText' to a 'Maybe' result+--+-- @since 1.4.0.0+parseMaybeST :: Parse a => ST.ShortText -> Maybe a+parseMaybeST = parseMaybe+{-# INLINE parseMaybeST #-}++-- | Parse from a strict 'BS.ByteString' to a 'Maybe' result+--+-- @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' result+--+-- @since 0.3.0.0+parseMaybeBSL :: Parse a => BSL.ByteString -> Maybe a+parseMaybeBSL = parseMaybe+{-# INLINE parseMaybeBSL #-}++-- | Parse from a @ByteString@ 'BSB.Builder' to a 'Maybe' result+--+-- @since 1.1.0.0+parseMaybeBSB :: Parse a => BSB.Builder -> Maybe a+parseMaybeBSB = parseMaybe+{-# INLINE parseMaybeBSB #-}++-- | Parse from a 'SBS.ShortByteString' to a 'Maybe' result+--+-- @since 1.1.0.0+parseMaybeSBS :: Parse a => SBS.ShortByteString -> Maybe a+parseMaybeSBS = parseMaybe+{-# INLINE parseMaybeSBS #-}++------------------------------------------------------------------------------+-- $ParseOrFail+--+-- The 'parseOrFail' function fails using 'MonadFail' on error instead of+-- using an 'Either' result.+--+-- The rest of the functions are equivalent to 'parseOrFail', but they specify+-- the type being parsed from.  Use them to avoid having to write type+-- annotations in cases where the type is ambiguous.  Using these functions+-- may make code easier to understand even in cases where the types are not+-- ambiguous.++-- | Parse or fail using 'MonadFail'+--+-- @since 1.3.0.0+parseOrFail :: forall t a m. (MonadFail m, Parse a, Textual t) => t -> m a+parseOrFail = either fail pure . parse+{-# INLINE parseOrFail #-}++-- | Parse from a 'String' or fail using 'MonadFail'+--+-- @since 1.3.0.0+parseOrFailS :: forall a m. (MonadFail m, Parse a) => String -> m a+parseOrFailS = parseOrFail+{-# INLINE parseOrFailS #-}++-- | Parse from strict 'T.Text' or fail using 'MonadFail'+--+-- @since 1.3.0.0+parseOrFailT :: forall a m. (MonadFail m, Parse a) => T.Text -> m a+parseOrFailT = parseOrFail+{-# INLINE parseOrFailT #-}++-- | Parse from lazy 'TL.Text' or fail using 'MonadFail'+--+-- @since 1.3.0.0+parseOrFailTL :: forall a m. (MonadFail m, Parse a) => TL.Text -> m a+parseOrFailTL = parseOrFail+{-# INLINE parseOrFailTL #-}++-- | Parse from a @Text@ 'TLB.Builder' or fail using 'MonadFail'+--+-- @since 1.3.0.0+parseOrFailTLB :: forall a m. (MonadFail m, Parse a) => TLB.Builder -> m a+parseOrFailTLB = parseOrFail+{-# INLINE parseOrFailTLB #-}++-- | Parse from a 'ST.ShortText' or fail using 'MonadFail'+--+-- @since 1.4.0.0+parseOrFailST :: forall a m. (MonadFail m, Parse a) => ST.ShortText -> m a+parseOrFailST = parseOrFail+{-# INLINE parseOrFailST #-}++-- | Parse from a strict 'BS.ByteString' or fail using 'MonadFail'+--+-- @since 1.3.0.0+parseOrFailBS :: forall a m. (MonadFail m, Parse a) => BS.ByteString -> m a+parseOrFailBS = parseOrFail+{-# INLINE parseOrFailBS #-}++-- | Parse from a lazy 'BSL.ByteString' or fail using 'MonadFail'+--+-- @since 1.3.0.0+parseOrFailBSL :: forall a m. (MonadFail m, Parse a) => BSL.ByteString -> m a+parseOrFailBSL = parseOrFail+{-# INLINE parseOrFailBSL #-}++-- | Parse from a @ByteString@ 'BSB.Builder' or fail using 'MonadFail'+--+-- @since 1.3.0.0+parseOrFailBSB :: forall a m. (MonadFail m, Parse a) => BSB.Builder -> m a+parseOrFailBSB = parseOrFail+{-# INLINE parseOrFailBSB #-}++-- | Parse from a 'SBS.ShortByteString' or fail using 'MonadFail'+--+-- @since 1.3.0.0+parseOrFailSBS+  :: forall a m. (MonadFail m, Parse a)+  => SBS.ShortByteString+  -> m a+parseOrFailSBS = parseOrFail+{-# INLINE parseOrFailSBS #-}++------------------------------------------------------------------------------+-- $ParseUnsafe+--+-- The 'parseUnsafe' function raises an exception on error instead of using an+-- 'Either' result.  It should only be used when an error is not possible.+--+-- The rest of the functions are equivalent to 'parseUnsafe', but they specify+-- the type being parsed from.  Use them to avoid having to write type+-- annotations in cases where the type is ambiguous.  Using these functions+-- may make code easier to understand even in cases where the types are not+-- ambiguous.++-- | Parse or raise an exception+--+-- @since 0.1.0.0+parseUnsafe :: forall t a. (HasCallStack, Parse a, Textual t) => t -> a+parseUnsafe = either (error . ("parseUnsafe: " ++)) id . parse+{-# INLINE parseUnsafe #-}++-- | Parse from a 'String' or raise an exception+--+-- @since 0.1.0.0+parseUnsafeS :: (HasCallStack, Parse a) => String -> a+parseUnsafeS = parseUnsafe+{-# INLINE parseUnsafeS #-}++-- | Parse from strict 'T.Text' or raise an exception+--+-- @since 0.1.0.0+parseUnsafeT :: (HasCallStack, Parse a) => T.Text -> a+parseUnsafeT = parseUnsafe+{-# INLINE parseUnsafeT #-}++-- | Parse from lazy 'TL.Text' or raise an exception+--+-- @since 0.1.0.0+parseUnsafeTL :: (HasCallStack, Parse a) => TL.Text -> a+parseUnsafeTL = parseUnsafe+{-# INLINE parseUnsafeTL #-}++-- | Parse from a @Text@ 'TLB.Builder' or raise an exception+--+-- @since 1.1.0.0+parseUnsafeTLB :: (HasCallStack, Parse a) => TLB.Builder -> a+parseUnsafeTLB = parseUnsafe+{-# INLINE parseUnsafeTLB #-}++-- | Parse from a 'ST.ShortText' or raise an exception+--+-- @since 1.4.0.0+parseUnsafeST :: (HasCallStack, Parse a) => ST.ShortText -> a+parseUnsafeST = parseUnsafe+{-# INLINE parseUnsafeST #-}++-- | Parse from a strict 'BS.ByteString' or raise an exception+--+-- @since 0.1.0.0+parseUnsafeBS :: (HasCallStack, Parse a) => BS.ByteString -> a+parseUnsafeBS = parseUnsafe+{-# INLINE parseUnsafeBS #-}++-- | Parse from a lazy 'BSL.ByteString' or raise an exception+--+-- @since 0.1.0.0+parseUnsafeBSL :: (HasCallStack, Parse a) => BSL.ByteString -> a+parseUnsafeBSL = parseUnsafe+{-# INLINE parseUnsafeBSL #-}++-- | Parse from a @ByteString@ 'BSB.Builder' or raise an exception+--+-- @since 1.1.0.0+parseUnsafeBSB :: (HasCallStack, Parse a) => BSB.Builder -> a+parseUnsafeBSB = parseUnsafe+{-# INLINE parseUnsafeBSB #-}++-- | Parse from a 'SBS.ShortByteString' or raise an exception+--+-- @since 1.1.0.0+parseUnsafeSBS :: (HasCallStack, Parse a) => SBS.ShortByteString -> a+parseUnsafeSBS = parseUnsafe+{-# INLINE parseUnsafeSBS #-}++------------------------------------------------------------------------------+-- $ReadSInstances++-- | 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+readsWithParse s = case parseMaybe s of+    Just v  -> [(v, "")]+    Nothing -> []+{-# INLINEABLE readsWithParse #-}++-- | 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'+  -> Bool  -- ^ accept unique prefixes when 'True'+  -> ReadS a+readsEnum allowCI allowPrefix s =+    case parseEnum allowCI allowPrefix () () s of+      Right v -> [(v, "")]+      Left{}  -> []+{-# INLINEABLE readsEnum #-}++------------------------------------------------------------------------------+-- $ConstantValidation+--+-- 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.+--+-- For more details, see the following article:+-- <https://www.extrema.is/articles/ttc-textual-type-classes/validated-constants>++-- | Validate a constant at compile-time using a 'Parse' instance+--+-- This function parses the 'String' at compile-time and fails compilation on+-- error.  When valid, the result is compiled in, so the result type must have+-- a 'THS.Lift' instance.  When this is inconvenient, 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.+--+-- 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@+-- and @invalid@ example programs in the @ttc-examples@ directory of the+-- source repository.  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++-- | This instance enables use of 'valid' without having to type @valid@.  The+-- [OverloadedStrings](https://ghc.gitlab.haskell.org/ghc/doc/users_guide/exts/overloaded_strings.html)+-- extension must be enabled in the module where this functionality is used.+-- Note that this reduces the number of characters in the code, but it can+-- also make the code more difficult to understand by somebody who is not+-- already familiar with it.  Typing @valid@ gives people a way to investigate+-- and understand what is going on.+--+-- 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 instance in GHC 9 or later is as follows:+--+-- @+-- (MonadFail m, THS.Quote m, Parse a, THS.Lift a) => IsString (THS.Code m a)+-- @+--+-- The type of this instance in previous versions of GHC is as follows:+--+-- @+-- (Parse a, THS.Lift a) => IsString (TH.Q (TH.TExp a))+-- @+--+-- This functionality can be used as follows in all supported versions of GHC.+-- The following is example usage from the @valid@ example:+--+-- @+-- sample2 :: Username+-- sample2 = $$("alice")+-- @+--+-- The parenthesis are not required from GHC 9.  The following is example+-- usage from the @valid@ example:+--+-- @+-- sample2 :: Username+-- sample2 = $$"alice"+-- @+--+-- @since 1.3.0.0+#if __GLASGOW_HASKELL__ >= 900+instance (MonadFail m, THS.Quote m, Parse a, THS.Lift a)+    => IsString (THS.Code m a) where+  fromString = valid+#else+instance (Parse a, THS.Lift a) => IsString (TH.Q (TH.TExp a)) where+  fromString = valid+#endif++-- | Validate a constant at compile-time using a 'Parse' instance+--+-- This function requires a 'Proxy' of the result type.  Use 'mkValid' to+-- avoid having to pass a 'Proxy' during constant definition.+--+-- This function parses the 'String' at compile-time and fails compilation on+-- error.  When valid, the 'String' is compiled in, to be parsed again at+-- run-time.  Since the result is not compiled in, no 'THS.Lift' instance is+-- required.+--+-- 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.+--+-- 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 @ttc-examples@ directory of the source repository.+-- 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+  -> TH.Q (TH.TExp a)+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 for a type in order to avoid having to write a+-- 'Proxy' when defining constants.+--+-- 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.+--+-- 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 @ttc-examples@ directory of the source repository.+-- 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+  -> TH.DecsQ+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+      , TH.FunD funName' [TH.Clause [] (TH.NormalB body) []]+      ]++-- | Validate a constant at compile-time using a 'Parse' instance+--+-- This function requires a 'Proxy' of the result type.  Use 'mkUntypedValid'+-- to avoid having to pass a 'Proxy' during constant definition.+--+-- This function parses the 'String' at compile-time and fails compilation on+-- error.  When valid, the 'String' is compiled in, to be parsed again at+-- run-time.  Since the result is not compiled in, no 'THS.Lift' instance is+-- required.+--+-- See the @uvalidof@ example program in the @ttc-examples@ directory of the+-- source repository.  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+  -> String+  -> TH.ExpQ+untypedValidOf proxy s = case (`asProxyTypeOf` proxy) <$> parse s of+    Right{} -> [| parseUnsafeS s |]+    Left err -> fail $ "Invalid constant: " ++ err++-- | Make a @valid@ function using 'untypedValidOf' for the given type+--+-- 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 @ttc-examples@ directory of the+-- source repository.  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+  -> TH.DecsQ+mkUntypedValid funName typeName = do+    let funName' = TH.mkName funName+        resultType = pure $ TH.ConT typeName+    funType <- [t| String -> TH.ExpQ |]+    body <- [| untypedValidOf (Proxy :: Proxy $resultType) |]+    return+      [ TH.SigD funName' funType+      , TH.FunD funName' [TH.Clause [] (TH.NormalB body) []]+      ]++-- | Make a @valid@ quasi-quoter using 'untypedValidOf' for the given type+--+-- See the @mkuvalidqq@ example program in the @ttc-examples@ directory of the+-- source repository.  The following is example usage from the @mkuvalidqq@+-- 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+  -> TH.DecsQ+mkUntypedValidQQ funName typeName = do+    let funName' = TH.mkName funName+        resultType = pure $ TH.ConT typeName+    expE <- [| untypedValidOf (Proxy :: Proxy $resultType) |]+    expP <- [| error "pattern not supported" |]+    expT <- [| error "type not supported" |]+    expD <- [| error "declaration not supported" |]+    let body = TH.NormalB $ TH.RecConE 'Q.QuasiQuoter+          [ ('Q.quoteExp, expE)+          , ('Q.quotePat, expP)+          , ('Q.quoteType, expT)+          , ('Q.quoteDec, expD)+          ]+    return+      [ TH.SigD funName' $ TH.ConT ''Q.QuasiQuoter+      , TH.FunD funName' [TH.Clause [] body []]+      ]++------------------------------------------------------------------------------+-- $DefaultInstances+--+-- These Template Haskell functions provide an easy way to load default+-- 'Render' and 'Parse' instances for common types.  See the documentation for+-- 'Render' and 'Parse' for details about default instances.  Remember that+-- loading such default instances should be avoided in libraries.++-- | Load the default 'Render' instance for a type+--+-- Example:+--+-- @+-- TTC.defaultRenderInstance ''Int+-- @+--+-- @since 1.5.0.0+defaultRenderInstance :: TH.Name -> TH.DecsQ+defaultRenderInstance typeName =+    let a = pure $ TH.ConT typeName+    in  [d| instance Render $a |]++-- | Load the default 'Render' instances for any number of types+--+-- Example:+--+-- @+-- TTC.defaultRenderInstances [''Int, ''Int8, ''Int16, ''Int32, ''Int64]+-- @+--+-- @since 1.5.0.0+defaultRenderInstances :: [TH.Name] -> TH.DecsQ+defaultRenderInstances = fmap concat . mapM defaultRenderInstance++-- | Load the default 'Parse' instance for a type+--+-- Example:+--+-- @+-- TTC.defaultParseInstance ''Int+-- @+--+-- @since 1.5.0.0+defaultParseInstance :: TH.Name -> TH.DecsQ+defaultParseInstance typeName =+    let a = pure $ TH.ConT typeName+    in  [d| instance Parse $a |]++-- | Load the default 'Parse' instances for any number of types+--+-- Example:+--+-- @+-- TTC.defaultParseInstances [''Int, ''Int8, ''Int16, ''Int32, ''Int64]+-- @+--+-- @since 1.5.0.0+defaultParseInstances :: [TH.Name] -> TH.DecsQ+defaultParseInstances = fmap concat . mapM defaultParseInstance++-- | Load the default 'Render' and 'Parse' instance for a type+--+-- Example:+--+-- @+-- TTC.defaultRenderAndParseInstance ''Int+-- @+--+-- @since 1.5.0.0+defaultRenderAndParseInstance :: TH.Name -> TH.DecsQ+defaultRenderAndParseInstance typeName = do+    -- NOTE This function is implemented this way for compatibility with old+    -- versions of GHC/base.+    renderDecs <- defaultRenderInstance typeName+    parseDecs <- defaultParseInstance typeName+    pure $ renderDecs ++ parseDecs++-- | Load the default 'Render' and 'Parse' instances for any number of types+--+-- Example:+--+-- @+-- TTC.defaultRenderAndParseInstances+--   [''Int, ''Int8, ''Int16, ''Int32, ''Int64]+-- @+--+-- @since 1.5.0.0+defaultRenderAndParseInstances :: [TH.Name] -> TH.DecsQ+defaultRenderAndParseInstances =+    fmap concat . mapM defaultRenderAndParseInstance
+ src/Data/TTC/Wrapper.hs view
@@ -0,0 +1,163 @@+------------------------------------------------------------------------------+-- |+-- Module      : Data.TTC.Wrapper+-- Description : TTC wrapper types+-- Copyright   : Copyright (c) 2019-2025 Travis Cardwell+-- License     : MIT+--+-- This module defines a @newtype@ wrapper for each 'TTC.Textual' data type.+-- Each wrapper has a 'TTC.Render' instance that converts the wrapped type and+-- a 'TTC.Parse' instance that wraps the argument (never failing).  Data types+-- that are coercible to a 'TTC.Textual' data type can use these wrappers to+-- derive instances using @DerivingVia@.+--+-- See the @wrapper@ example program in the @ttc-examples@ directory of the+-- source repository.+------------------------------------------------------------------------------++module Data.TTC.Wrapper+  ( -- * Wrapper Types+    WrapperS(..)+  , WrapperT(..)+  , WrapperTL(..)+  , WrapperTLB(..)+  , WrapperST(..)+  , WrapperBS(..)+  , WrapperBSL(..)+  , WrapperBSB(..)+  , WrapperSBS(..)+  ) where++-- https://hackage.haskell.org/package/bytestring+import qualified Data.ByteString as BS+import qualified Data.ByteString.Builder as BSB+import qualified Data.ByteString.Lazy as BSL+import qualified Data.ByteString.Short as SBS++-- https://hackage.haskell.org/package/text+import qualified Data.Text as T+import qualified Data.Text.Lazy as TL+import qualified Data.Text.Lazy.Builder as TLB++-- https://hackage.haskell.org/package/text-short+import qualified Data.Text.Short as ST++-- (ttc)+import qualified Data.TTC as TTC++------------------------------------------------------------------------------++-- | 'String' wrapper type+--+-- @since 1.5.0.0+newtype WrapperS = WrapperS { unWrapperS :: String }++instance TTC.Parse WrapperS where+  parse = TTC.asS $ pure . WrapperS++instance TTC.Render WrapperS where+  render = TTC.fromS . unWrapperS++------------------------------------------------------------------------------++-- | Strict 'T.Text' wrapper type+--+-- @since 1.5.0.0+newtype WrapperT = WrapperT { unWrapperT :: T.Text }++instance TTC.Parse WrapperT where+  parse = TTC.asT $ pure . WrapperT++instance TTC.Render WrapperT where+  render = TTC.fromT . unWrapperT++------------------------------------------------------------------------------++-- | Lazy 'TL.Text' wrapper type+--+-- @since 1.5.0.0+newtype WrapperTL = WrapperTL { unWrapperTL :: TL.Text }++instance TTC.Parse WrapperTL where+  parse = TTC.asTL $ pure . WrapperTL++instance TTC.Render WrapperTL where+  render = TTC.fromTL . unWrapperTL++------------------------------------------------------------------------------++-- | Text 'TLB.Builder' wrapper type+--+-- @since 1.5.0.0+newtype WrapperTLB = WrapperTLB { unWrapperTLB :: TLB.Builder }++instance TTC.Parse WrapperTLB where+  parse = TTC.asTLB $ pure . WrapperTLB++instance TTC.Render WrapperTLB where+  render = TTC.fromTLB . unWrapperTLB++------------------------------------------------------------------------------++-- | 'ST.ShortText' wrapper type+--+-- @since 1.5.0.0+newtype WrapperST = WrapperST { unWrapperST :: ST.ShortText }++instance TTC.Parse WrapperST where+  parse = TTC.asST $ pure . WrapperST++instance TTC.Render WrapperST where+  render = TTC.fromST . unWrapperST++------------------------------------------------------------------------------++-- | Strict 'BS.ByteString' wrapper type+--+-- @since 1.5.0.0+newtype WrapperBS = WrapperBS { unWrapperBS :: BS.ByteString }++instance TTC.Parse WrapperBS where+  parse = TTC.asBS $ pure . WrapperBS++instance TTC.Render WrapperBS where+  render = TTC.fromBS . unWrapperBS++------------------------------------------------------------------------------++-- | Lazy 'BSL.ByteString' wrapper type+--+-- @since 1.5.0.0+newtype WrapperBSL = WrapperBSL { unWrapperBSL :: BSL.ByteString }++instance TTC.Parse WrapperBSL where+  parse = TTC.asBSL $ pure . WrapperBSL++instance TTC.Render WrapperBSL where+  render = TTC.fromBSL . unWrapperBSL++------------------------------------------------------------------------------++-- | ByteString 'BSB.Builder' wrapper type+--+-- @since 1.5.0.0+newtype WrapperBSB = WrapperBSB { unWrapperBSB :: BSB.Builder }++instance TTC.Parse WrapperBSB where+  parse = TTC.asBSB $ pure . WrapperBSB++instance TTC.Render WrapperBSB where+  render = TTC.fromBSB . unWrapperBSB++------------------------------------------------------------------------------++-- | 'SBS.ShortByteString' wrapper type+--+-- @since 1.5.0.0+newtype WrapperSBS = WrapperSBS { unWrapperSBS :: SBS.ShortByteString }++instance TTC.Parse WrapperSBS where+  parse = TTC.asSBS $ pure . WrapperSBS++instance TTC.Render WrapperSBS where+  render = TTC.fromSBS . unWrapperSBS
test/Data/TTC/Test.hs view
@@ -1,1461 +1,994 @@ {-# LANGUAGE CPP #-} {-# LANGUAGE FlexibleInstances #-}-{-# LANGUAGE OverloadedStrings #-}-{-# LANGUAGE QuasiQuotes #-}-{-# LANGUAGE TemplateHaskell #-}--{-# OPTIONS_GHC -fno-warn-orphans #-}--module Data.TTC.Test (tests) where---- https://hackage.haskell.org/package/base-import Control.Exception (ErrorCall, Exception, evaluate, handle)-import Control.Monad (when)-import Data.Int (Int16, Int32, Int64, Int8)-import Data.Proxy (Proxy(Proxy), asProxyTypeOf)-import Data.Word (Word16, Word32, Word64, Word8)-import GHC.Stack (HasCallStack)-import Text.Read (readMaybe)---- https://hackage.haskell.org/package/bytestring-import qualified Data.ByteString as BS-import qualified Data.ByteString.Builder as BSB-import qualified Data.ByteString.Lazy as BSL-import qualified Data.ByteString.Short as SBS---- https://hackage.haskell.org/package/tasty-import Test.Tasty (TestTree, testGroup)---- https://hackage.haskell.org/package/tasty-hunit-import Test.Tasty.HUnit ((@=?), Assertion, assertFailure, testCase)---- https://hackage.haskell.org/package/text-import qualified Data.Text as T-import qualified Data.Text.Lazy as TL-import qualified Data.Text.Lazy.Builder as TLB---- https://hackage.haskell.org/package/text-short-import qualified Data.Text.Short as ST---- (ttc)-import qualified Data.TTC as TTC---- (ttc:test)-import qualified TestString-import TestString (TestString(TestString))----------------------------------------------------------------------------------- $Instances--instance TTC.Render Char-instance TTC.Parse Char--instance TTC.Render Double-instance TTC.Parse Double--instance TTC.Render Float-instance TTC.Parse Float--instance TTC.Render Int-instance TTC.Parse Int--instance TTC.Render Int8-instance TTC.Parse Int8--instance TTC.Render Int16-instance TTC.Parse Int16--instance TTC.Render Int32-instance TTC.Parse Int32--instance TTC.Render Int64-instance TTC.Parse Int64--instance TTC.Render Integer-instance TTC.Parse Integer--instance TTC.Render Word-instance TTC.Parse Word--instance TTC.Render Word8-instance TTC.Parse Word8--instance TTC.Render Word16-instance TTC.Parse Word16--instance TTC.Render Word32-instance TTC.Parse Word32--instance TTC.Render Word64-instance TTC.Parse Word64--instance TTC.Render String-instance TTC.Parse String--instance TTC.Render BSL.ByteString-instance TTC.Parse BSL.ByteString--instance TTC.Render BS.ByteString-instance TTC.Parse BS.ByteString--instance TTC.Render TL.Text-instance TTC.Parse TL.Text--instance TTC.Render T.Text-instance TTC.Parse T.Text----------------------------------------------------------------------------------instance Eq BSB.Builder where-  x == y = BSB.toLazyByteString x == BSB.toLazyByteString y--#if !MIN_VERSION_bytestring(0,11,1)-instance Show BSB.Builder where-  show = show . BSB.toLazyByteString-#endif----------------------------------------------------------------------------------- $HelperFunctions--assertRaises-  :: (HasCallStack, Exception e, Show a)-  => Proxy e-  -> a-  -> Assertion-assertRaises proxy x =-    handle-      (const (return ()) . (`asProxyTypeOf` proxy))-      (assertFailure . ("expected exception; got: " ++) . show =<< evaluate x)----------------------------------------------------------------------------------- $TestData--xS :: String-xS = "test テスト"--xT :: T.Text-xT = "test テスト"--xTL :: TL.Text-xTL = "test テスト"--xTLB :: TLB.Builder-xTLB = "test テスト"--xST :: ST.ShortText-xST = "test テスト"--xBS :: BS.ByteString-xBS = "test \xe3\x83\x86\xe3\x82\xb9\xe3\x83\x88"--xBSL :: BSL.ByteString-xBSL = "test \xe3\x83\x86\xe3\x82\xb9\xe3\x83\x88"--xBSB :: BSB.Builder-xBSB = "test テスト"--xSBS :: SBS.ShortByteString-xSBS = "test \xe3\x83\x86\xe3\x82\xb9\xe3\x83\x88"--xiS :: String-xiS = "test \xfffd"--xiT :: T.Text-xiT = "test \xfffd"--xiTL :: TL.Text-xiTL = "test \xfffd"--xiTLB :: TLB.Builder-xiTLB = "test \xfffd"--xiST :: ST.ShortText-xiST = "test \xfffd"--xiBS :: BS.ByteString-xiBS = "test \xe3"--xiBSL :: BSL.ByteString-xiBSL = "test \xe3"--xiBSB :: BSB.Builder-xiBSB = "test \xfffd"--xiSBS :: SBS.ShortByteString-xiSBS = "test \xfffd"----------------------------------------------------------------------------------newtype PosInt = PosInt Int-  deriving Eq--instance Show PosInt where-  show (PosInt i) = "(PosInt " ++ show i ++ ")"--instance TTC.Parse PosInt where-  parse = TTC.asS $ \ s -> case readMaybe s of-    Just i-      | i >= 0 -> Right $ PosInt i-      | otherwise -> Left $ TTC.fromS "not positive"-    Nothing -> Left $ TTC.fromS "not an integer"--instance TTC.Render PosInt where-  render (PosInt i) = TTC.convert $ show i--answer :: PosInt-answer = PosInt 42--answerS :: String-answerS = "42"--answerT :: T.Text-answerT = "42"--answerTL :: TL.Text-answerTL = "42"--answerTLB :: TLB.Builder-answerTLB = "42"--answerST :: ST.ShortText-answerST = "42"--answerBS :: BS.ByteString-answerBS = "42"--answerBSL :: BSL.ByteString-answerBSL = "42"--answerBSB :: BSB.Builder-answerBSB = "42"--answerSBS :: SBS.ShortByteString-answerSBS = "42"--answerZ :: Int-answerZ = 42--data IntError = IntInvalid-  deriving (Eq, Show)----------------------------------------------------------------------------------data Color-  = Red-  | Green-  | Blue-  | White-  | Black-  deriving (Bounded, Enum, Eq, Show)--instance Read Color where-  readsPrec _ = TTC.readsEnum True True--instance TTC.Render Color where-  render Red   = TTC.fromT "red"-  render Green = TTC.fromT "green"-  render Blue  = TTC.fromT "blue"-  render White = TTC.fromT "white"-  render Black = TTC.fromT "black"--data ColorError-  = ColorInvalid-  | ColorAmbiguous-  deriving (Eq, Show)--redS :: String-redS = "red"--redT :: T.Text-redT = "red"--redTL :: TL.Text-redTL = "red"--redTLB :: TLB.Builder-redTLB = "red"--redST :: ST.ShortText-redST = "red"--redBS :: BS.ByteString-redBS = "red"--redBSL :: BSL.ByteString-redBSL = "red"--redBSB :: BSB.Builder-redBSB = "red"--redSBS :: SBS.ShortByteString-redSBS = "red"----------------------------------------------------------------------------------newtype PartialParser = PartialParser String-  deriving (Eq, Show)--instance TTC.Parse PartialParser where-  parse = TTC.asS $ \s -> do-    when (null s) $ Left (TTC.fromT undefined)-    pure $ PartialParser s----------------------------------------------------------------------------------- $Textual--testToS :: TestTree-testToS = testGroup "toS"-    [ testCase "S" $ xS @=? TTC.toS xS-    , testCase "T" $ xS @=? TTC.toS xT-    , testCase "TL" $ xS @=? TTC.toS xTL-    , testCase "TLB" $ xS @=? TTC.toS xTLB-    , testCase "ST" $ xS @=? TTC.toS xST-    , testCase "BS" $ xS @=? TTC.toS xBS-    , testCase "BS/invalid" $ xiS @=? TTC.toS xiBS-    , testCase "BSL" $ xS @=? TTC.toS xBSL-    , testCase "BSL/invalid" $ xiS @=? TTC.toS xiBSL-    , testCase "BSB" $ xS @=? TTC.toS xBSB-    , testCase "BSB/invalid" $ xiS @=? TTC.toS xiBSB-    , testCase "SBS" $ xS @=? TTC.toS xSBS-    , testCase "SBS/invalid" $ xiS @=? TTC.toS xiSBS-    ]--testToT :: TestTree-testToT = testGroup "toT"-    [ testCase "S" $ xT @=? TTC.toT xS-    , testCase "T" $ xT @=? TTC.toT xT-    , testCase "TL" $ xT @=? TTC.toT xTL-    , testCase "TLB" $ xT @=? TTC.toT xTLB-    , testCase "ST" $ xT @=? TTC.toT xST-    , testCase "BS" $ xT @=? TTC.toT xBS-    , testCase "BS/invalid" $ xiT @=? TTC.toT xiBS-    , testCase "BSL" $ xT @=? TTC.toT xBSL-    , testCase "BSL/invalid" $ xiT @=? TTC.toT xiBSL-    , testCase "BSB" $  xT @=? TTC.toT xBSB-    , testCase "BSB/invalid" $ xiT @=? TTC.toT xiBSB-    , testCase "SBS" $  xT @=? TTC.toT xSBS-    , testCase "SBS/invalid" $ xiT @=? TTC.toT xiSBS-    ]--testToTL :: TestTree-testToTL = testGroup "toTL"-    [ testCase "S" $ xTL @=? TTC.toTL xS-    , testCase "T" $ xTL @=? TTC.toTL xT-    , testCase "TL" $ xTL @=? TTC.toTL xTL-    , testCase "TLB" $ xTL @=? TTC.toTL xTLB-    , testCase "ST" $ xTL @=? TTC.toTL xST-    , testCase "BS" $ xTL @=? TTC.toTL xBS-    , testCase "BS/invalid" $ xiTL @=? TTC.toTL xiBS-    , testCase "BSL" $ xTL @=? TTC.toTL xBSL-    , testCase "BSL/invalid" $ xiTL @=? TTC.toTL xiBSL-    , testCase "BSB" $ xTL @=? TTC.toTL xBSB-    , testCase "BSB/invalid" $ xiTL @=? TTC.toTL xiBSB-    , testCase "SBS" $ xTL @=? TTC.toTL xSBS-    , testCase "SBS/invalid" $ xiTL @=? TTC.toTL xiSBS-    ]--testToTLB :: TestTree-testToTLB = testGroup "toTLB"-    [ testCase "S" $ xTLB @=? TTC.toTLB xS-    , testCase "T" $ xTLB @=? TTC.toTLB xT-    , testCase "TL" $ xTLB @=? TTC.toTLB xTL-    , testCase "TLB" $ xTLB @=? TTC.toTLB xTLB-    , testCase "ST" $ xTLB @=? TTC.toTLB xST-    , testCase "BS" $ xTLB @=? TTC.toTLB xBS-    , testCase "BS/invalid" $ xiTLB @=? TTC.toTLB xiBS-    , testCase "BSL" $ xTLB @=? TTC.toTLB xBSL-    , testCase "BSL/invalid" $ xiTLB @=? TTC.toTLB xiBSL-    , testCase "BSB" $ xTLB @=? TTC.toTLB xBSB-    , testCase "BSB/invalid" $ xiTLB @=? TTC.toTLB xiBSB-    , testCase "SBS" $ xTLB @=? TTC.toTLB xSBS-    , testCase "SBS/invalid" $ xiTLB @=? TTC.toTLB xiSBS-    ]--testToST :: TestTree-testToST = testGroup "toST"-    [ testCase "S" $ xST @=? TTC.toST xS-    , testCase "T" $ xST @=? TTC.toST xT-    , testCase "TL" $ xST @=? TTC.toST xTL-    , testCase "TLB" $ xST @=? TTC.toST xTLB-    , testCase "ST" $ xST @=? TTC.toST xST-    , testCase "BS" $ xST @=? TTC.toST xBS-    , testCase "BS/invalid" $ xiST @=? TTC.toST xiBS-    , testCase "BSL" $ xST @=? TTC.toST xBSL-    , testCase "BSL/invalid" $ xiST @=? TTC.toST xiBSL-    , testCase "BSB" $ xST @=? TTC.toST xBSB-    , testCase "BSB/invalid" $ xiST @=? TTC.toST xiBSB-    , testCase "SBS" $ xST @=? TTC.toST xSBS-    , testCase "SBS/invalid" $ xiST @=? TTC.toST xiSBS-    ]--testToBS :: TestTree-testToBS = testGroup "toBS"-    [ testCase "S" $ xBS @=? TTC.toBS xS-    , testCase "T" $ xBS @=? TTC.toBS xT-    , testCase "TL" $ xBS @=? TTC.toBS xTL-    , testCase "TLB" $ xBS @=? TTC.toBS xTLB-    , testCase "ST" $ xBS @=? TTC.toBS xST-    , testCase "BS" $ xBS @=? TTC.toBS xBS-    , testCase "BSL" $ xBS @=? TTC.toBS xBSL-    , testCase "BSB" $ xBS @=? TTC.toBS xBSB-    , testCase "SBS" $ xBS @=? TTC.toBS xSBS-    ]--testToBSL :: TestTree-testToBSL = testGroup "toBSL"-    [ testCase "S" $ xBSL @=? TTC.toBSL xS-    , testCase "T" $ xBSL @=? TTC.toBSL xT-    , testCase "TL" $ xBSL @=? TTC.toBSL xTL-    , testCase "TLB" $ xBSL @=? TTC.toBSL xTLB-    , testCase "ST" $ xBSL @=? TTC.toBSL xST-    , testCase "BS" $ xBSL @=? TTC.toBSL xBS-    , testCase "BSL" $ xBSL @=? TTC.toBSL xBSL-    , testCase "BSB" $ xBSL @=? TTC.toBSL xBSB-    , testCase "SBS" $ xBSL @=? TTC.toBSL xSBS-    ]--testToBSB :: TestTree-testToBSB = testGroup "toBSB"-    [ testCase "S" $ xBSB @=? TTC.toBSB xS-    , testCase "T" $ xBSB @=? TTC.toBSB xT-    , testCase "TL" $ xBSB @=? TTC.toBSB xTL-    , testCase "TLB" $ xBSB @=? TTC.toBSB xTLB-    , testCase "ST" $ xBSB @=? TTC.toBSB xST-    , testCase "BS" $ xBSB @=? TTC.toBSB xBS-    , testCase "BSL" $ xBSB @=? TTC.toBSB xBSL-    , testCase "BSB" $ xBSB @=? TTC.toBSB xBSB-    , testCase "SBS" $ xBSB @=? TTC.toBSB xSBS-    ]--testToSBS :: TestTree-testToSBS = testGroup "toSBS"-    [ testCase "S" $ xSBS @=? TTC.toSBS xS-    , testCase "T" $ xSBS @=? TTC.toSBS xT-    , testCase "TL" $ xSBS @=? TTC.toSBS xTL-    , testCase "TLB" $ xSBS @=? TTC.toSBS xTLB-    , testCase "ST" $ xSBS @=? TTC.toSBS xST-    , testCase "BS" $ xSBS @=? TTC.toSBS xBS-    , testCase "BSL" $ xSBS @=? TTC.toSBS xBSL-    , testCase "BSB" $ xSBS @=? TTC.toSBS xBSB-    , testCase "SBS" $ xSBS @=? TTC.toSBS xSBS-    ]--testConvert :: TestTree-testConvert = testGroup "convert"-    [ testCase "S->S" $ xS @=? TTC.convert xS-    , testCase "S->T" $ xT @=? TTC.convert xS-    , testCase "S->TL" $ xTL @=? TTC.convert xS-    , testCase "S->TLB" $ xTLB @=? TTC.convert xS-    , testCase "S->ST" $ xST @=? TTC.convert xS-    , testCase "S->BS" $ xBS @=? TTC.convert xS-    , testCase "S->BSL" $ xBSL @=? TTC.convert xS-    , testCase "S->BSB" $ xBSB @=? TTC.convert xS-    , testCase "S->SBS" $ xSBS @=? TTC.convert xS-    , testCase "T->S" $ xS @=? TTC.convert xT-    , testCase "T->T" $ xT @=? TTC.convert xT-    , testCase "T->TL" $ xTL @=? TTC.convert xT-    , testCase "T->TLB" $ xTLB @=? TTC.convert xT-    , testCase "T->ST" $ xST @=? TTC.convert xT-    , testCase "T->BS" $ xBS @=? TTC.convert xT-    , testCase "T->BSL" $ xBSL @=? TTC.convert xT-    , testCase "T->BSB" $ xBSB @=? TTC.convert xT-    , testCase "T->SBS" $ xSBS @=? TTC.convert xT-    , testCase "TL->S" $ xS @=? TTC.convert xTL-    , testCase "TL->T" $ xT @=? TTC.convert xTL-    , testCase "TL->TL" $ xTL @=? TTC.convert xTL-    , testCase "TL->TLB" $ xTLB @=? TTC.convert xTL-    , testCase "TL->ST" $ xST @=? TTC.convert xTL-    , testCase "TL->BS" $ xBS @=? TTC.convert xTL-    , testCase "TL->BSL" $ xBSL @=? TTC.convert xTL-    , testCase "TL->BSB" $ xBSB @=? TTC.convert xTL-    , testCase "TL->SBS" $ xSBS @=? TTC.convert xTL-    , testCase "TLB->S" $ xS @=? TTC.convert xTLB-    , testCase "TLB->T" $ xT @=? TTC.convert xTLB-    , testCase "TLB->TL" $ xTL @=? TTC.convert xTLB-    , testCase "TLB->TLB" $ xTLB @=? TTC.convert xTLB-    , testCase "TLB->ST" $ xST @=? TTC.convert xTLB-    , testCase "TLB->BS" $ xBS @=? TTC.convert xTLB-    , testCase "TLB->BSL" $ xBSL @=? TTC.convert xTLB-    , testCase "TLB->BSB" $ xBSB @=? TTC.convert xTLB-    , testCase "TLB->SBS" $ xSBS @=? TTC.convert xTLB-    , testCase "BS->S" $ xS @=? TTC.convert xBS-    , testCase "BS->T" $ xT @=? TTC.convert xBS-    , testCase "BS->TL" $ xTL @=? TTC.convert xBS-    , testCase "BS->TLB" $ xTLB @=? TTC.convert xBS-    , testCase "BS->ST" $ xST @=? TTC.convert xBS-    , testCase "BS->BS" $ xBS @=? TTC.convert xBS-    , testCase "BS->BSL" $ xBSL @=? TTC.convert xBS-    , testCase "BS->BSB" $ xBSB @=? TTC.convert xBS-    , testCase "BS->SBS" $ xSBS @=? TTC.convert xBS-    , testCase "BSL->S" $ xS @=? TTC.convert xBSL-    , testCase "BSL->T" $ xT @=? TTC.convert xBSL-    , testCase "BSL->TL" $ xTL @=? TTC.convert xBSL-    , testCase "BSL->TLB" $ xTLB @=? TTC.convert xBSL-    , testCase "BSL->ST" $ xST @=? TTC.convert xBSL-    , testCase "BSL->BS" $ xBS @=? TTC.convert xBSL-    , testCase "BSL->BSL" $ xBSL @=? TTC.convert xBSL-    , testCase "BSL->BSB" $ xBSB @=? TTC.convert xBSL-    , testCase "BSL->SBS" $ xSBS @=? TTC.convert xBSL-    , testCase "BSB->S" $ xS @=? TTC.convert xBSB-    , testCase "BSB->T" $ xT @=? TTC.convert xBSB-    , testCase "BSB->TL" $ xTL @=? TTC.convert xBSB-    , testCase "BSB->TLB" $ xTLB @=? TTC.convert xBSB-    , testCase "BSB->ST" $ xST @=? TTC.convert xBSB-    , testCase "BSB->BS" $ xBS @=? TTC.convert xBSB-    , testCase "BSB->BSL" $ xBSL @=? TTC.convert xBSB-    , testCase "BSB->BSB" $ xBSB @=? TTC.convert xBSB-    , testCase "BSB->SBS" $ xSBS @=? TTC.convert xBSB-    , testCase "SBS->S" $ xS @=? TTC.convert xSBS-    , testCase "SBS->T" $ xT @=? TTC.convert xSBS-    , testCase "SBS->TL" $ xTL @=? TTC.convert xSBS-    , testCase "SBS->TLB" $ xTLB @=? TTC.convert xSBS-    , testCase "SBS->ST" $ xST @=? TTC.convert xSBS-    , testCase "SBS->BS" $ xBS @=? TTC.convert xSBS-    , testCase "SBS->BSL" $ xBSL @=? TTC.convert xSBS-    , testCase "SBS->BSB" $ xBSB @=? TTC.convert xSBS-    , testCase "SBS->SBS" $ xSBS @=? TTC.convert xSBS-    ]--testFromS :: TestTree-testFromS = testGroup "fromS"-    [ testCase "S" $ xS @=? TTC.fromS xS-    , testCase "T" $ xT @=? TTC.fromS xS-    , testCase "TL" $ xTL @=? TTC.fromS xS-    , testCase "TLB" $ xTLB @=? TTC.fromS xS-    , testCase "ST" $ xST @=? TTC.fromS xS-    , testCase "BS" $ xBS @=? TTC.fromS xS-    , testCase "BSL" $ xBSL @=? TTC.fromS xS-    , testCase "BSB" $ xBSB @=? TTC.fromS xS-    , testCase "SBS" $ xSBS @=? TTC.fromS xS-    ]--testFromT :: TestTree-testFromT = testGroup "fromT"-    [ testCase "S" $ xS @=? TTC.fromT xT-    , testCase "T" $ xT @=? TTC.fromT xT-    , testCase "TL" $ xTL @=? TTC.fromT xT-    , testCase "TLB" $ xTLB @=? TTC.fromT xT-    , testCase "ST" $ xST @=? TTC.fromT xT-    , testCase "BS" $ xBS @=? TTC.fromT xT-    , testCase "BSL" $ xBSL @=? TTC.fromT xT-    , testCase "BSB" $ xBSB @=? TTC.fromT xT-    , testCase "SBS" $ xSBS @=? TTC.fromT xT-    ]--testFromTL :: TestTree-testFromTL = testGroup "fromTL"-    [ testCase "S" $ xS @=? TTC.fromTL xTL-    , testCase "T" $ xT @=? TTC.fromTL xTL-    , testCase "TL" $ xTL @=? TTC.fromTL xTL-    , testCase "TLB" $ xTLB @=? TTC.fromTL xTL-    , testCase "ST" $ xST @=? TTC.fromTL xTL-    , testCase "BS" $ xBS @=? TTC.fromTL xTL-    , testCase "BSL" $ xBSL @=? TTC.fromTL xTL-    , testCase "BSB" $ xBSB @=? TTC.fromTL xTL-    , testCase "SBS" $ xSBS @=? TTC.fromTL xTL-    ]--testFromTLB :: TestTree-testFromTLB = testGroup "fromTLB"-    [ testCase "S" $ xS @=? TTC.fromTLB xTLB-    , testCase "T" $ xT @=? TTC.fromTLB xTLB-    , testCase "TL" $ xTL @=? TTC.fromTLB xTLB-    , testCase "TLB" $ xTLB @=? TTC.fromTLB xTLB-    , testCase "ST" $ xST @=? TTC.fromTLB xTLB-    , testCase "BS" $ xBS @=? TTC.fromTLB xTLB-    , testCase "BSL" $ xBSL @=? TTC.fromTLB xTLB-    , testCase "BSB" $ xBSB @=? TTC.fromTLB xTLB-    , testCase "SBS" $ xSBS @=? TTC.fromTLB xTLB-    ]--testFromBS :: TestTree-testFromBS = testGroup "fromBS"-    [ testCase "S" $ xS @=? TTC.fromBS xBS-    , testCase "T" $ xT @=? TTC.fromBS xBS-    , testCase "TL" $ xTL @=? TTC.fromBS xBS-    , testCase "TLB" $ xTLB @=? TTC.fromBS xBS-    , testCase "ST" $ xST @=? TTC.fromBS xBS-    , testCase "BS" $ xBS @=? TTC.fromBS xBS-    , testCase "BSL" $ xBSL @=? TTC.fromBS xBS-    , testCase "BSB" $ xBSB @=? TTC.fromBS xBS-    , testCase "SBS" $ xSBS @=? TTC.fromBS xBS-    ]--testFromBSL :: TestTree-testFromBSL = testGroup "fromBSL"-    [ testCase "S" $ xS @=? TTC.fromBSL xBSL-    , testCase "T" $ xT @=? TTC.fromBSL xBSL-    , testCase "TL" $ xTL @=? TTC.fromBSL xBSL-    , testCase "TLB" $ xTLB @=? TTC.fromBSL xBSL-    , testCase "ST" $ xST @=? TTC.fromBSL xBSL-    , testCase "BS" $ xBS @=? TTC.fromBSL xBSL-    , testCase "BSL" $ xBSL @=? TTC.fromBSL xBSL-    , testCase "BSB" $ xBSB @=? TTC.fromBSL xBSL-    , testCase "SBS" $ xSBS @=? TTC.fromBSL xBSL-    ]--testFromBSB :: TestTree-testFromBSB = testGroup "fromBSB"-    [ testCase "S" $ xS @=? TTC.fromBSB xBSB-    , testCase "T" $ xT @=? TTC.fromBSB xBSB-    , testCase "TL" $ xTL @=? TTC.fromBSB xBSB-    , testCase "TLB" $ xTLB @=? TTC.fromBSB xBSB-    , testCase "ST" $ xST @=? TTC.fromBSB xBSB-    , testCase "BS" $ xBS @=? TTC.fromBSB xBSB-    , testCase "BSL" $ xBSL @=? TTC.fromBSB xBSB-    , testCase "BSB" $ xBSB @=? TTC.fromBSB xBSB-    , testCase "SBS" $ xSBS @=? TTC.fromBSB xBSB-    ]--testFromSBS :: TestTree-testFromSBS = testGroup "fromSBS"-    [ testCase "S" $ xS @=? TTC.fromSBS xSBS-    , testCase "T" $ xT @=? TTC.fromSBS xSBS-    , testCase "TL" $ xTL @=? TTC.fromSBS xSBS-    , testCase "TLB" $ xTLB @=? TTC.fromSBS xSBS-    , testCase "ST" $ xST @=? TTC.fromSBS xSBS-    , testCase "BS" $ xBS @=? TTC.fromSBS xSBS-    , testCase "BSL" $ xBSL @=? TTC.fromSBS xSBS-    , testCase "BSB" $ xBSB @=? TTC.fromSBS xSBS-    , testCase "SBS" $ xSBS @=? TTC.fromSBS xSBS-    ]--testAsS :: TestTree-testAsS = testGroup "asS"-    [ testCase "S" $ xS @=? TTC.asS id xS-    , testCase "T" $ xS @=? TTC.asS id xT-    , testCase "TL" $ xS @=? TTC.asS id xTL-    , testCase "TLB" $ xS @=? TTC.asS id xTLB-    , testCase "ST" $ xS @=? TTC.asS id xST-    , testCase "BS" $ xS @=? TTC.asS id xBS-    , testCase "BSL" $ xS @=? TTC.asS id xBSL-    , testCase "BSB" $ xS @=? TTC.asS id xBSB-    , testCase "SBS" $ xS @=? TTC.asS id xSBS-    ]--testAsT :: TestTree-testAsT = testGroup "asT"-    [ testCase "S" $ xT @=? TTC.asT id xS-    , testCase "T" $ xT @=? TTC.asT id xT-    , testCase "TL" $ xT @=? TTC.asT id xTL-    , testCase "TLB" $ xT @=? TTC.asT id xTLB-    , testCase "ST" $ xT @=? TTC.asT id xST-    , testCase "BS" $ xT @=? TTC.asT id xBS-    , testCase "BSL" $ xT @=? TTC.asT id xBSL-    , testCase "BSB" $ xT @=? TTC.asT id xBSB-    , testCase "SBS" $ xT @=? TTC.asT id xSBS-    ]--testAsTL :: TestTree-testAsTL = testGroup "asTL"-    [ testCase "S" $ xTL @=? TTC.asTL id xS-    , testCase "T" $ xTL @=? TTC.asTL id xT-    , testCase "TL" $ xTL @=? TTC.asTL id xTL-    , testCase "TLB" $ xTL @=? TTC.asTL id xTLB-    , testCase "ST" $ xTL @=? TTC.asTL id xST-    , testCase "BS" $ xTL @=? TTC.asTL id xBS-    , testCase "BSL" $ xTL @=? TTC.asTL id xBSL-    , testCase "BSB" $ xTL @=? TTC.asTL id xBSB-    , testCase "SBS" $ xTL @=? TTC.asTL id xSBS-    ]--testAsTLB :: TestTree-testAsTLB = testGroup "asTLB"-    [ testCase "S" $ xTLB @=? TTC.asTLB id xS-    , testCase "T" $ xTLB @=? TTC.asTLB id xT-    , testCase "TL" $ xTLB @=? TTC.asTLB id xTL-    , testCase "TLB" $ xTLB @=? TTC.asTLB id xTLB-    , testCase "ST" $ xTLB @=? TTC.asTLB id xST-    , testCase "BS" $ xTLB @=? TTC.asTLB id xBS-    , testCase "BSL" $ xTLB @=? TTC.asTLB id xBSL-    , testCase "BSB" $ xTLB @=? TTC.asTLB id xBSB-    , testCase "SBS" $ xTLB @=? TTC.asTLB id xSBS-    ]--testAsBS :: TestTree-testAsBS = testGroup "asBS"-    [ testCase "S" $ xBS @=? TTC.asBS id xS-    , testCase "T" $ xBS @=? TTC.asBS id xT-    , testCase "TL" $ xBS @=? TTC.asBS id xTL-    , testCase "TLB" $ xBS @=? TTC.asBS id xTLB-    , testCase "ST" $ xBS @=? TTC.asBS id xST-    , testCase "BS" $ xBS @=? TTC.asBS id xBS-    , testCase "BSL" $ xBS @=? TTC.asBS id xBSL-    , testCase "BSB" $ xBS @=? TTC.asBS id xBSB-    , testCase "SBS" $ xBS @=? TTC.asBS id xSBS-    ]--testAsBSL :: TestTree-testAsBSL = testGroup "asBSL"-    [ testCase "S" $ xBSL @=? TTC.asBSL id xS-    , testCase "T" $ xBSL @=? TTC.asBSL id xT-    , testCase "TL" $ xBSL @=? TTC.asBSL id xTL-    , testCase "TLB" $ xBSL @=? TTC.asBSL id xTLB-    , testCase "ST" $ xBSL @=? TTC.asBSL id xST-    , testCase "BS" $ xBSL @=? TTC.asBSL id xBS-    , testCase "BSL" $ xBSL @=? TTC.asBSL id xBSL-    , testCase "BSB" $ xBSL @=? TTC.asBSL id xBSB-    , testCase "SBS" $ xBSL @=? TTC.asBSL id xSBS-    ]--testAsBSB :: TestTree-testAsBSB = testGroup "asBSB"-    [ testCase "S" $ xBSB @=? TTC.asBSB id xS-    , testCase "T" $ xBSB @=? TTC.asBSB id xT-    , testCase "TL" $ xBSB @=? TTC.asBSB id xTL-    , testCase "TLB" $ xBSB @=? TTC.asBSB id xTLB-    , testCase "ST" $ xBSB @=? TTC.asBSB id xST-    , testCase "BS" $ xBSB @=? TTC.asBSB id xBS-    , testCase "BSL" $ xBSB @=? TTC.asBSB id xBSL-    , testCase "BSB" $ xBSB @=? TTC.asBSB id xBSB-    , testCase "SBS" $ xBSB @=? TTC.asBSB id xSBS-    ]--testAsSBS :: TestTree-testAsSBS = testGroup "asSBS"-    [ testCase "S" $ xSBS @=? TTC.asSBS id xS-    , testCase "T" $ xSBS @=? TTC.asSBS id xT-    , testCase "TL" $ xSBS @=? TTC.asSBS id xTL-    , testCase "TLB" $ xSBS @=? TTC.asSBS id xTLB-    , testCase "ST" $ xSBS @=? TTC.asSBS id xST-    , testCase "BS" $ xSBS @=? TTC.asSBS id xBS-    , testCase "BSL" $ xSBS @=? TTC.asSBS id xBSL-    , testCase "BSB" $ xSBS @=? TTC.asSBS id xBSB-    , testCase "SBS" $ xSBS @=? TTC.asSBS id xSBS-    ]----------------------------------------------------------------------------------- $Render--testRender :: TestTree-testRender = testGroup "render"-    [ testCase "S" $ answerS @=? TTC.render answer-    , testCase "T" $ answerT @=? TTC.render answer-    , testCase "TL" $ answerTL @=? TTC.render answer-    , testCase "TLB" $ answerTLB @=? TTC.render answer-    , testCase "ST" $ answerST @=? TTC.render answer-    , testCase "BS" $ answerBS @=? TTC.render answer-    , testCase "BSL" $ answerBSL @=? TTC.render answer-    , testCase "BSB" $ answerBSB @=? TTC.render answer-    , testCase "SBS" $ answerSBS @=? TTC.render answer-    ]--testRenderDefault :: TestTree-testRenderDefault = testGroup "RenderDefault"-    [ testCase "Char" $ "*" @=? TTC.renderS '*'-    , let x = 3.14159 :: Double-      in  testCase "Double" $ show x @=? TTC.renderS x-    , let x = 3.14159 :: Float-      in  testCase "Float" $ show x @=? TTC.renderS x-    , let n = 42 :: Int-      in  testCase "Int" $ show n @=? TTC.renderS n-    , let n = 42 :: Int8-      in  testCase "Int8" $ show n @=? TTC.renderS n-    , let n = 42 :: Int16-      in  testCase "Int16" $ show n @=? TTC.renderS n-    , let n = 42 :: Int32-      in  testCase "Int32" $ show n @=? TTC.renderS n-    , let n = 42 :: Int64-      in  testCase "Int64" $ show n @=? TTC.renderS n-    , let n = 42 :: Integer-      in  testCase "Integer" $ show n @=? TTC.renderS n-    , let w = 42 :: Word-      in  testCase "Word" $ show w @=? TTC.renderS w-    , let w = 42 :: Word8-      in  testCase "Word8" $ show w @=? TTC.renderS w-    , let w = 42 :: Word16-      in  testCase "Word16" $ show w @=? TTC.renderS w-    , let w = 42 :: Word32-      in  testCase "Word32" $ show w @=? TTC.renderS w-    , let w = 42 :: Word64-      in  testCase "Word64" $ show w @=? TTC.renderS w-    , testCase "String" $ xS @=? TTC.renderS xS-    , testCase "BSL.ByteString" $ xS @=? TTC.renderS xBSL-    , testCase "BS.ByteString" $ xS @=? TTC.renderS xBS-    , testCase "TL.Text" $ xS @=? TTC.renderS xTL-    , testCase "T.Text" $ xS @=? TTC.renderS xT-    ]--testRenderS :: TestTree-testRenderS = testCase "renderS" $ answerS @=? TTC.renderS answer--testRenderT :: TestTree-testRenderT = testCase "renderT" $ answerT @=? TTC.renderT answer--testRenderTL :: TestTree-testRenderTL = testCase "renderTL" $ answerTL @=? TTC.renderTL answer--testRenderTLB :: TestTree-testRenderTLB = testCase "renderTLB" $ answerTLB @=? TTC.renderTLB answer--testRenderST :: TestTree-testRenderST = testCase "renderST" $ answerST @=? TTC.renderST answer--testRenderBS :: TestTree-testRenderBS = testCase "renderBS" $ answerBS @=? TTC.renderBS answer--testRenderBSL :: TestTree-testRenderBSL = testCase "renderBSL" $ answerBSL @=? TTC.renderBSL 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-    , testCase "T" $ answerT @=? TTC.renderWithShow answerZ-    , testCase "TL" $ answerTL @=? TTC.renderWithShow answerZ-    , testCase "TLB" $ answerTLB @=? TTC.renderWithShow answerZ-    , testCase "ST" $ answerST @=? TTC.renderWithShow answerZ-    , testCase "BS" $ answerBS @=? TTC.renderWithShow answerZ-    , testCase "BSL" $ answerBSL @=? TTC.renderWithShow answerZ-    , testCase "BSB" $ answerBSB @=? TTC.renderWithShow answerZ-    , testCase "SBS" $ answerSBS @=? TTC.renderWithShow answerZ-    ]----------------------------------------------------------------------------------- $Parse--testParse :: TestTree-testParse = testGroup "parse"-    [ testCase "S" $ Just answer @=? TTC.parseMaybe answerS-    , testCase "T" $ Just answer @=? TTC.parseMaybe answerT-    , testCase "TL" $ Just answer @=? TTC.parseMaybe answerTL-    , testCase "TLB" $ Just answer @=? TTC.parseMaybe answerTLB-    , testCase "ST" $ Just answer @=? TTC.parseMaybe answerST-    , testCase "BS" $ Just answer @=? TTC.parseMaybe answerBS-    , testCase "BSL" $ Just answer @=? TTC.parseMaybe answerBSL-    , testCase "BSB" $ Just answer @=? TTC.parseMaybe answerBSB-    , testCase "SBS" $ Just answer @=? TTC.parseMaybe answerSBS-    , testCase "negative" $ Left "not positive" @=?-        (TTC.parse ('-' : answerS) :: Either String PosInt)-    , testCase "invalid" $ Left "not an integer" @=?-        (TTC.parse ('a' : answerS) :: Either String PosInt)-    ]--testParseDefault :: TestTree-testParseDefault = testGroup "ParseDefault"-    [ let parse = TTC.parse :: String -> Either String Char-      in  testGroup "Char"-            [ testCase "OK" $ Right '*' @=? parse "*"-            , testCase "empty" $ Left "invalid Char" @=? parse ""-            , testCase "multiple" $ Left "invalid Char" @=? parse "**"-            ]-    , let parse = TTC.parse :: String -> Either String Double-          s = show (3.14159 :: Double)-      in  testGroup "Double"-            [ testCase "OK" $ Right (read s) @=? parse s-            , testCase "invalid" $ Left "invalid Double" @=? parse "invalid"-            ]-    , let parse = TTC.parse :: String -> Either String Float-          s = show (3.14159 :: Float)-      in  testGroup "Float"-            [ testCase "OK" $ Right (read s) @=? parse s-            , testCase "invalid" $ Left "invalid Float" @=? parse "invalid"-            ]-    , let parse = TTC.parse :: String -> Either String Int-          s = show (42 :: Int)-      in  testGroup "Int"-            [ testCase "OK" $ Right (read s) @=? parse s-            , testCase "invalid" $ Left "invalid Int" @=? parse "invalid"-            ]-    , let parse = TTC.parse :: String -> Either String Int8-          s = show (42 :: Int8)-      in  testGroup "Int8"-            [ testCase "OK" $ Right (read s) @=? parse s-            , testCase "invalid" $ Left "invalid Int8" @=? parse "invalid"-            ]-    , let parse = TTC.parse :: String -> Either String Int16-          s = show (42 :: Int16)-      in  testGroup "Int16"-            [ testCase "OK" $ Right (read s) @=? parse s-            , testCase "invalid" $ Left "invalid Int16" @=? parse "invalid"-            ]-    , let parse = TTC.parse :: String -> Either String Int32-          s = show (42 :: Int32)-      in  testGroup "Int32"-            [ testCase "OK" $ Right (read s) @=? parse s-            , testCase "invalid" $ Left "invalid Int32" @=? parse "invalid"-            ]-    , let parse = TTC.parse :: String -> Either String Int64-          s = show (42 :: Int64)-      in  testGroup "Int64"-            [ testCase "OK" $ Right (read s) @=? parse s-            , testCase "invalid" $ Left "invalid Int64" @=? parse "invalid"-            ]-    , let parse = TTC.parse :: String -> Either String Integer-          s = show (42 :: Integer)-      in  testGroup "Integer"-            [ testCase "OK" $ Right (read s) @=? parse s-            , testCase "invalid" $ Left "invalid Integer" @=? parse "invalid"-            ]-    , let parse = TTC.parse :: String -> Either String Word-          s = show (42 :: Word)-      in  testGroup "Word"-            [ testCase "OK" $ Right (read s) @=? parse s-            , testCase "invalid" $ Left "invalid Word" @=? parse "invalid"-            ]-    , let parse = TTC.parse :: String -> Either String Word8-          s = show (42 :: Word8)-      in  testGroup "Word8"-            [ testCase "OK" $ Right (read s) @=? parse s-            , testCase "invalid" $ Left "invalid Word8" @=? parse "invalid"-            ]-    , let parse = TTC.parse :: String -> Either String Word16-          s = show (42 :: Word16)-      in  testGroup "Word16"-            [ testCase "OK" $ Right (read s) @=? parse s-            , testCase "invalid" $ Left "invalid Word16" @=? parse "invalid"-            ]-    , let parse = TTC.parse :: String -> Either String Word32-          s = show (42 :: Word32)-      in  testGroup "Word32"-            [ testCase "OK" $ Right (read s) @=? parse s-            , testCase "invalid" $ Left "invalid Word32" @=? parse "invalid"-            ]-    , let parse = TTC.parse :: String -> Either String Word64-          s = show (42 :: Word64)-      in  testGroup "Word64"-            [ testCase "OK" $ Right (read s) @=? parse s-            , testCase "invalid" $ Left "invalid Word64" @=? parse "invalid"-            ]-    , let parse = TTC.parse :: String -> Either String String-      in  testGroup "String"-            [ testCase "empty" $ Right "" @=? parse ""-            , testCase "nonempty" $ Right xS @=? parse xS-            ]-    , let parse = TTC.parse :: String -> Either String BSL.ByteString-      in  testGroup "BSL.ByteString"-            [ testCase "empty" $ Right BSL.empty @=? parse ""-            , testCase "nonempty" $ Right xBSL @=? parse xS-            ]-    , let parse = TTC.parse :: String -> Either String BS.ByteString-      in  testGroup "BS.ByteString"-            [ testCase "empty" $ Right BS.empty @=? parse ""-            , testCase "nonempty" $ Right xBS @=? parse xS-            ]-    , let parse = TTC.parse :: String -> Either String TL.Text-      in  testGroup "TL.Text"-            [ testCase "empty" $ Right TL.empty @=? parse ""-            , testCase "nonempty" $ Right xTL @=? parse xS-            ]-    , let parse = TTC.parse :: String -> Either String T.Text-      in  testGroup "T.Text"-            [ testCase "empty" $ Right T.empty @=? parse ""-            , testCase "nonempty" $ Right xT @=? parse xS-            ]-    ]--testParseS :: TestTree-testParseS =-    let parseS = TTC.parseS :: String -> Either String PosInt-    in  testCase "parseS" $ Right answer @=? parseS answerS--testParseT :: TestTree-testParseT =-    let parseT = TTC.parseT :: T.Text -> Either String PosInt-    in  testCase "parseT" $ Right answer @=? parseT answerT--testParseTL :: TestTree-testParseTL =-    let parseTL = TTC.parseTL :: TL.Text -> Either String PosInt-    in  testCase "parseTL" $ Right answer @=? parseTL answerTL--testParseTLB :: TestTree-testParseTLB =-    let parseTLB = TTC.parseTLB :: TLB.Builder -> Either String PosInt-    in  testCase "parseTLB" $ Right answer @=? parseTLB answerTLB--testParseST :: TestTree-testParseST =-    let parseST = TTC.parseST :: ST.ShortText -> Either String PosInt-    in  testCase "parseST" $ Right answer @=? parseST answerST--testParseBS :: TestTree-testParseBS =-    let parseBS = TTC.parseBS :: BS.ByteString -> Either String PosInt-    in  testCase "parseBS" $ Right answer @=? parseBS answerBS--testParseBSL :: TestTree-testParseBSL =-    let parseBSL = TTC.parseBSL :: BSL.ByteString -> Either String PosInt-    in  testCase "parseBSL" $ Right answer @=? parseBSL answerBSL--testParseBSB :: TestTree-testParseBSB =-    let parseBSB = TTC.parseBSB :: BSB.Builder -> Either String PosInt-    in  testCase "parseBSB" $ Right answer @=? parseBSB answerBSB--testParseSBS :: TestTree-testParseSBS =-    let parseSBS = TTC.parseSBS :: SBS.ShortByteString -> Either String PosInt-    in  testCase "parseSBS" $ Right answer @=? parseSBS answerSBS--testParseMaybe :: TestTree-testParseMaybe = testGroup "parseMaybe"-    [ testCase "S" $ Just answer @=? TTC.parseMaybe answerS-    , testCase "T" $ Just answer @=? TTC.parseMaybe answerT-    , testCase "TL" $ Just answer @=? TTC.parseMaybe answerTL-    , testCase "TLB" $ Just answer @=? TTC.parseMaybe answerTLB-    , testCase "ST" $ Just answer @=? TTC.parseMaybe answerST-    , testCase "BS" $ Just answer @=? TTC.parseMaybe answerBS-    , testCase "BSL" $ Just answer @=? TTC.parseMaybe answerBSL-    , testCase "BSB" $ Just answer @=? TTC.parseMaybe answerBSB-    , testCase "SBS" $ Just answer @=? TTC.parseMaybe answerSBS-    -- successful 'parseMaybe' does not have any error type conversion:-    , testCase "noerror" $-        Just (PartialParser "test") @=? TTC.parseMaybe ("test" :: String)-    , testCase "negative" $-        Nothing @=? (TTC.parseMaybe ('-' : answerS) :: Maybe PosInt)-    , testCase "invalid" $-        Nothing @=? (TTC.parseMaybe ('a' : answerS) :: Maybe PosInt)-    ]--testParseMaybeS :: TestTree-testParseMaybeS = testCase "parseMaybeS" $-    Just answer @=? TTC.parseMaybeS answerS--testParseMaybeT :: TestTree-testParseMaybeT = testCase "parseMaybeT" $-    Just answer @=? TTC.parseMaybeT answerT--testParseMaybeTL :: TestTree-testParseMaybeTL = testCase "parseMaybeTL" $-    Just answer @=? TTC.parseMaybeTL answerTL--testParseMaybeTLB :: TestTree-testParseMaybeTLB = testCase "parseMaybeTLB" $-    Just answer @=? TTC.parseMaybeTLB answerTLB--testParseMaybeST :: TestTree-testParseMaybeST = testCase "parseMaybeST" $-    Just answer @=? TTC.parseMaybeST answerST--testParseMaybeBS :: TestTree-testParseMaybeBS = testCase "parseMaybeBS" $-    Just answer @=? TTC.parseMaybeBS answerBS--testParseMaybeBSL :: TestTree-testParseMaybeBSL = testCase "parseMaybeBSL" $-    Just answer @=? TTC.parseMaybeBSL answerBSL--testParseMaybeBSB :: TestTree-testParseMaybeBSB = testCase "parseMaybeBSB" $-    Just answer @=? TTC.parseMaybeBSB answerBSB--testParseMaybeSBS :: TestTree-testParseMaybeSBS = testCase "parseMaybeSBS" $-    Just answer @=? TTC.parseMaybeSBS answerSBS--testParseOrFail :: TestTree-testParseOrFail = testGroup "parseOrFail"-    [ testCase "S" $ Just answer @=? TTC.parseOrFail answerS-    , testCase "T" $ Just answer @=? TTC.parseOrFail answerT-    , testCase "TL" $ Just answer @=? TTC.parseOrFail answerTL-    , testCase "TLB" $ Just answer @=? TTC.parseOrFail answerTLB-    , testCase "ST" $ Just answer @=? TTC.parseOrFail answerST-    , testCase "BS" $ Just answer @=? TTC.parseOrFail answerBS-    , testCase "BSL" $ Just answer @=? TTC.parseOrFail answerBSL-    , testCase "BSB" $ Just answer @=? TTC.parseOrFail answerBSB-    , testCase "SBS" $ Just answer @=? TTC.parseOrFail answerSBS-    -- successful 'parseOrFail' does not have any error type conversion:-    , testCase "noerror" $-        Just (PartialParser "test") @=? TTC.parseOrFail ("test" :: String)-    , testCase "negative" $-        Nothing @=? (TTC.parseOrFail ('-' : answerS) :: Maybe PosInt)-    , testCase "invalid" $-        Nothing @=? (TTC.parseOrFail ('a' : answerS) :: Maybe PosInt)-    ]--testParseOrFailS :: TestTree-testParseOrFailS = testCase "parseOrFailS" $-    Just answer @=? TTC.parseOrFailS answerS--testParseOrFailT :: TestTree-testParseOrFailT = testCase "parseOrFailT" $-    Just answer @=? TTC.parseOrFailT answerT--testParseOrFailTL :: TestTree-testParseOrFailTL = testCase "parseOrFailTL" $-    Just answer @=? TTC.parseOrFailTL answerTL--testParseOrFailTLB :: TestTree-testParseOrFailTLB = testCase "parseOrFailTLB" $-    Just answer @=? TTC.parseOrFailTLB answerTLB--testParseOrFailST :: TestTree-testParseOrFailST = testCase "parseOrFailST" $-    Just answer @=? TTC.parseOrFailST answerST--testParseOrFailBS :: TestTree-testParseOrFailBS = testCase "parseOrFailBS" $-    Just answer @=? TTC.parseOrFailBS answerBS--testParseOrFailBSL :: TestTree-testParseOrFailBSL = testCase "parseOrFailBSL" $-    Just answer @=? TTC.parseOrFailBSL answerBSL--testParseOrFailBSB :: TestTree-testParseOrFailBSB = testCase "parseOrFailBSB" $-    Just answer @=? TTC.parseOrFailBSB answerBSB--testParseOrFailSBS :: TestTree-testParseOrFailSBS = testCase "parseOrFailSBS" $-    Just answer @=? TTC.parseOrFailSBS answerSBS--testParseUnsafe :: TestTree-testParseUnsafe = testGroup "parseUnsafe"-    [ testCase "S" $ answer @=? TTC.parseUnsafe answerS-    , testCase "T" $ answer @=? TTC.parseUnsafe answerT-    , testCase "TL" $ answer @=? TTC.parseUnsafe answerTL-    , testCase "TLB" $ answer @=? TTC.parseUnsafe answerTLB-    , testCase "ST" $ answer @=? TTC.parseUnsafe answerST-    , testCase "BS" $ answer @=? TTC.parseUnsafe answerBS-    , testCase "BSL" $ answer @=? TTC.parseUnsafe answerBSL-    , testCase "BSB" $ answer @=? TTC.parseUnsafe answerBSB-    , testCase "SBS" $ answer @=? TTC.parseUnsafe answerSBS-    , testCase "negative" $ assertRaises (Proxy :: Proxy ErrorCall)-        (TTC.parseUnsafe ('-' : answerS) :: PosInt)-    , testCase "invalid" $ assertRaises (Proxy :: Proxy ErrorCall)-        (TTC.parseUnsafe ('a' : answerS) :: PosInt)-    ]--testParseUnsafeS :: TestTree-testParseUnsafeS = testCase "parseUnsafeS" $-    answer @=? TTC.parseUnsafeS answerS--testParseUnsafeT :: TestTree-testParseUnsafeT = testCase "parseUnsafeT" $-    answer @=? TTC.parseUnsafeT answerT--testParseUnsafeTL :: TestTree-testParseUnsafeTL = testCase "parseUnsafeTL" $-    answer @=? TTC.parseUnsafeTL answerTL--testParseUnsafeTLB :: TestTree-testParseUnsafeTLB = testCase "parseUnsafeTLB" $-    answer @=? TTC.parseUnsafeTLB answerTLB--testParseUnsafeST :: TestTree-testParseUnsafeST = testCase "parseUnsafeST" $-    answer @=? TTC.parseUnsafeST answerST--testParseUnsafeBS :: TestTree-testParseUnsafeBS = testCase "parseUnsafeBS" $-    answer @=? TTC.parseUnsafeBS answerBS--testParseUnsafeBSL :: TestTree-testParseUnsafeBSL = testCase "parseUnsafeBSL" $-    answer @=? TTC.parseUnsafeBSL answerBSL--testParseUnsafeBSB :: TestTree-testParseUnsafeBSB = testCase "parseUnsafeBSB" $-    answer @=? TTC.parseUnsafeBSB answerBSB--testParseUnsafeSBS :: TestTree-testParseUnsafeSBS = testCase "parseUnsafeSBS" $-    answer @=? TTC.parseUnsafeSBS answerSBS--testWithError :: TestTree-testWithError = testGroup "withError"-    [ testCase "OK" $ Right answer @=?-        (TTC.withError undefString (Just answer) :: Either T.Text PosInt)-    , testCase "S" $ Left "err" @=?-        (TTC.withErrorS "err" Nothing :: Either T.Text PosInt)-    , testCase "T" $ Left "err" @=?-        (TTC.withErrorT "err" Nothing :: Either String PosInt)-    , testCase "TL" $ Left "err" @=?-        (TTC.withErrorTL "err" Nothing :: Either String PosInt)-    , testCase "TLB" $ Left "err" @=?-        (TTC.withErrorTLB "err" Nothing :: Either String PosInt)-    , testCase "ST" $ Left "err" @=?-        (TTC.withErrorST "err" Nothing :: Either String PosInt)-    , testCase "BS" $ Left "err" @=?-        (TTC.withErrorBS "err" Nothing :: Either String PosInt)-    , testCase "BSL" $ Left "err" @=?-        (TTC.withErrorBSL "err" Nothing :: Either String PosInt)-    , testCase "BSB" $ Left "err" @=?-        (TTC.withErrorBSB "err" Nothing :: Either String PosInt)-    , testCase "SBS" $ Left "err" @=?-        (TTC.withErrorSBS "err" Nothing :: Either String PosInt)-    ]-  where-    undefString :: String-    undefString = undefined--testPrefixError :: TestTree-testPrefixError = testGroup "prefixError"-    [ testCase "OK" $ Right answer @=?-        (TTC.prefixError undefString (Right answer) :: Either String PosInt)-    , testCase "S" $ Left err @=?-        (TTC.prefixErrorS "error: " (Left "uh-oh") :: Either String PosInt)-    , testCase "T" $ Left err @=?-        (TTC.prefixErrorT "error: " (Left "uh-oh") :: Either String PosInt)-    , testCase "TL" $ Left err @=?-        (TTC.prefixErrorTL "error: " (Left "uh-oh") :: Either String PosInt)-    , testCase "TLB" $ Left err @=?-        (TTC.prefixErrorTLB "error: " (Left "uh-oh") :: Either String PosInt)-    , testCase "ST" $ Left err @=?-        (TTC.prefixErrorTLB "error: " (Left "uh-oh") :: Either String PosInt)-    , testCase "BS" $ Left err @=?-        (TTC.prefixErrorTL "error: " (Left "uh-oh") :: Either String PosInt)-    , testCase "BSL" $ Left err @=?-        (TTC.prefixErrorTL "error: " (Left "uh-oh") :: Either String PosInt)-    , testCase "BSB" $ Left err @=?-        (TTC.prefixErrorTL "error: " (Left "uh-oh") :: Either String PosInt)-    , testCase "SBS" $ Left err @=?-        (TTC.prefixErrorTL "error: " (Left "uh-oh") :: Either String PosInt)-    ]-  where-    undefString, err :: String-    undefString = undefined-    err = "error: uh-oh"--testParseWithRead :: TestTree-testParseWithRead = testGroup "parseWithRead"-    [ testCase "S" $ Right answerZ @=? TTC.parseWithRead IntInvalid answerS-    , testCase "T" $ Right answerZ @=? TTC.parseWithRead IntInvalid answerT-    , testCase "TL" $ Right answerZ @=? TTC.parseWithRead IntInvalid answerTL-    , testCase "TLB" $-        Right answerZ @=? TTC.parseWithRead IntInvalid answerTLB-    , testCase "ST" $ Right answerZ @=? TTC.parseWithRead IntInvalid answerST-    , testCase "BS" $ Right answerZ @=? TTC.parseWithRead IntInvalid answerBS-    , testCase "BSL" $-        Right answerZ @=? TTC.parseWithRead IntInvalid answerBSL-    , testCase "BSB" $-        Right answerZ @=? TTC.parseWithRead IntInvalid answerBSB-    , testCase "SBS" $-        Right answerZ @=? TTC.parseWithRead IntInvalid answerSBS-    , testCase "invalid" $ Left IntInvalid @=?-        (TTC.parseWithRead IntInvalid ('a' : answerS) :: Either IntError Int)-    ]--testParseWithRead' :: TestTree-testParseWithRead' = testGroup "parseWithRead'"-    [ testCase "S" $ Right answerZ @=? parseWithRead' answerS-    , testCase "T" $ Right answerZ @=? parseWithRead' answerT-    , testCase "TL" $ Right answerZ @=? parseWithRead' answerTL-    , testCase "TLB" $ Right answerZ @=? parseWithRead' answerTLB-    , testCase "ST" $ Right answerZ @=? parseWithRead' answerST-    , testCase "BS" $ Right answerZ @=? parseWithRead' answerBS-    , testCase "BSL" $ Right answerZ @=? parseWithRead' answerBSL-    , testCase "BSB" $ Right answerZ @=? parseWithRead' answerBSB-    , testCase "SBS" $ Right answerZ @=? parseWithRead' answerSBS-    , testCase "invalid" $-        Left "invalid Int" @=? parseWithRead' ('a' : answerS)-    ]-  where-    parseWithRead' :: TTC.Textual t => t -> Either String Int-    parseWithRead' = TTC.parseWithRead' "Int"--testMaybeParseWithRead :: TestTree-testMaybeParseWithRead = testGroup "maybeParseWithRead"-    [ testCase "S" $ Just answerZ @=? TTC.maybeParseWithRead answerS-    , testCase "T" $ Just answerZ @=? TTC.maybeParseWithRead answerT-    , testCase "TL" $ Just answerZ @=? TTC.maybeParseWithRead answerTL-    , testCase "TLB" $ Just answerZ @=? TTC.maybeParseWithRead answerTLB-    , testCase "ST" $ Just answerZ @=? TTC.maybeParseWithRead answerST-    , testCase "BS" $ Just answerZ @=? TTC.maybeParseWithRead answerBS-    , testCase "BSL" $ Just answerZ @=? TTC.maybeParseWithRead answerBSL-    , testCase "BSB" $ Just answerZ @=? TTC.maybeParseWithRead answerBSB-    , testCase "SBS" $ Just answerZ @=? TTC.maybeParseWithRead answerSBS-    , testCase "invalid" $ Nothing @=?-        (TTC.maybeParseWithRead ('a' : answerS) :: Maybe Int)-    ]--testParseEnum :: TestTree-testParseEnum = testGroup "parseEnum"-    [ testCase "S" $ Right Red @=? parse False False redS-    , testCase "T" $ Right Red @=? parse False False redT-    , testCase "TL" $ Right Red @=? parse False False redTL-    , testCase "TLB" $ Right Red @=? parse False False redTLB-    , testCase "ST" $ Right Red @=? parse False False redST-    , testCase "BS" $ Right Red @=? parse False False redBS-    , testCase "BSL" $ Right Red @=? parse False False redBSL-    , testCase "BSB" $ Right Red @=? parse False False redBSB-    , testCase "SBS" $ Right Red @=? parse False False redSBS-    , testCase "CI" $ Right Red @=? parse True False ("Red" :: String)-    , testCase "!CI" $ Left ColorInvalid @=?-        parse False False ("Red" :: String)-    , testCase "prefix" $ Right Red @=? parse False True ("r" :: String)-    , testCase "ambiguous" $ Left ColorAmbiguous @=?-        parse False True ("bl" :: String)-    ]-  where-    parse :: TTC.Textual t => Bool -> Bool -> t -> Either ColorError Color-    parse allowCI allowPrefix =-      TTC.parseEnum allowCI allowPrefix ColorInvalid ColorAmbiguous--testParseEnum' :: TestTree-testParseEnum' = testGroup "parseEnum'"-    [ testCase "S" $ Right Red @=? parse False False redS-    , testCase "T" $ Right Red @=? parse False False redT-    , testCase "TL" $ Right Red @=? parse False False redTL-    , testCase "TLB" $ Right Red @=? parse False False redTLB-    , testCase "ST" $ Right Red @=? parse False False redST-    , testCase "BS" $ Right Red @=? parse False False redBS-    , testCase "BSL" $ Right Red @=? parse False False redBSL-    , testCase "BSB" $ Right Red @=? parse False False redBSB-    , testCase "SBS" $ Right Red @=? parse False False redSBS-    , testCase "CI" $ Right Red @=? parse True False ("Red" :: String)-    , testCase "!CI" $ Left "invalid Color" @=?-        parse False False ("Red" :: String)-    , testCase "prefix" $ Right Red @=? parse False True ("r" :: String)-    , testCase "ambiguous" $ Left "ambiguous Color" @=?-        parse False True ("bl" :: String)-    ]-  where-    parse :: TTC.Textual t => Bool -> Bool -> t -> Either String Color-    parse = TTC.parseEnum' "Color"--testReadsWithParse :: TestTree-testReadsWithParse = testGroup "readsWithParse"-    [ testCase "valid" $ [(answer, "")] @=? TTC.readsWithParse answerS-    , testCase "invalid" $ [] @=? (TTC.readsWithParse :: ReadS PosInt) "-42"-    ]--testReadsEnum :: TestTree-testReadsEnum = testGroup "readsEnum"-    [ testCase "valid" $ Just Red @=? readMaybe "R"-    , testCase "invalid" $ Nothing @=? (readMaybe "bl" :: Maybe Color)-    ]----------------------------------------------------------------------------------- $Valid--testValid :: TestTree-testValid = testCase "valid" $ TestString "test" @=? validConst-  where-    validConst :: TestString-    validConst = $$(TTC.valid "test")--testValidIsString :: TestTree-testValidIsString =-    testCase "validIsString" $ TestString "test" @=? validConst-  where-    validConst :: TestString-    validConst = $$("test")--testValidOf :: TestTree-testValidOf = testCase "validOf" $-    TestString "test" @=? $$(TTC.validOf (Proxy :: Proxy TestString) "test")--testMkValid :: TestTree-testMkValid = testCase "mkValid" $-    TestString "test" @=? $$(TestString.valid "test")--testUntypedValidOf :: TestTree-testUntypedValidOf = testCase "untypedValidOf" $-    TestString "test" @=?-      $(TTC.untypedValidOf (Proxy :: Proxy TestString) "test")--testMkUntypedValid :: TestTree-testMkUntypedValid = testCase "mkUntypedValid" $-    TestString "test" @=? $(TestString.untypedValid "test")--testMkUntypedValidQQ :: TestTree-testMkUntypedValidQQ = testCase "mkUntypedValidQQ" $-    TestString "test" @=? [TestString.untypedValidQQ|test|]----------------------------------------------------------------------------------tests :: TestTree-tests = testGroup "Data.TTC"-    [ testGroup "Textual"-        [ testToS-        , testToT-        , testToTL-        , testToTLB-        , testToST-        , testToBS-        , testToBSL-        , testToBSB-        , testToSBS-        , testConvert-        , testFromS-        , testFromT-        , testFromTL-        , testFromTLB-        , testFromBS-        , testFromBSL-        , testFromBSB-        , testFromSBS-        , testAsS-        , testAsT-        , testAsTL-        , testAsTLB-        , testAsBS-        , testAsBSL-        , testAsBSB-        , testAsSBS-        ]-    , testGroup "Render"-        [ testRender-        , testRenderDefault-        , testRenderS-        , testRenderT-        , testRenderTL-        , testRenderTLB-        , testRenderST-        , testRenderBS-        , testRenderBSL-        , testRenderBSB-        , testRenderSBS-        , testRenderWithShow-        ]-    , testGroup "Parse"-        [ testParse-        , testParseDefault-        , testParseS-        , testParseT-        , testParseTL-        , testParseTLB-        , testParseST-        , testParseBS-        , testParseBSL-        , testParseBSB-        , testParseSBS-        , testParseMaybe-        , testParseMaybeS-        , testParseMaybeT-        , testParseMaybeTL-        , testParseMaybeTLB-        , testParseMaybeST-        , testParseMaybeBS-        , testParseMaybeBSL-        , testParseMaybeBSB-        , testParseMaybeSBS-        , testParseOrFail-        , testParseOrFailS-        , testParseOrFailT-        , testParseOrFailTL-        , testParseOrFailTLB-        , testParseOrFailST-        , testParseOrFailBS-        , testParseOrFailBSL-        , testParseOrFailBSB-        , testParseOrFailSBS-        , testParseUnsafe-        , testParseUnsafeS-        , testParseUnsafeT-        , testParseUnsafeTL-        , testParseUnsafeTLB-        , testParseUnsafeST-        , testParseUnsafeBS-        , testParseUnsafeBSL-        , testParseUnsafeBSB-        , testParseUnsafeSBS-        , testWithError-        , testPrefixError-        , testParseWithRead-        , testParseWithRead'-        , testMaybeParseWithRead-        , testParseEnum-        , testParseEnum'+{-# LANGUAGE LambdaCase #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE QuasiQuotes #-}+{-# LANGUAGE RankNTypes #-}+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE TemplateHaskell #-}+{-# LANGUAGE TypeApplications #-}++{-# OPTIONS_GHC -fno-warn-orphans #-}++module Data.TTC.Test (tests) where++-- https://hackage.haskell.org/package/base+import Control.Exception (ErrorCall, Exception, evaluate, handle)+import Data.Int (Int8, Int16, Int32, Int64)+import Data.Proxy (Proxy(Proxy), asProxyTypeOf)+import Data.String (IsString)+import Data.Word (Word8, Word16, Word32, Word64)+import GHC.Stack (HasCallStack)+import Text.Read (readMaybe)++-- https://hackage.haskell.org/package/bytestring+import qualified Data.ByteString as BS+import qualified Data.ByteString.Builder as BSB+import qualified Data.ByteString.Lazy as BSL+import qualified Data.ByteString.Short as SBS++-- https://hackage.haskell.org/package/tasty+import Test.Tasty (TestName, TestTree, testGroup)++-- https://hackage.haskell.org/package/tasty-hunit+import Test.Tasty.HUnit ((@=?), Assertion, assertFailure, testCase)++-- https://hackage.haskell.org/package/text+import qualified Data.Text as T+import qualified Data.Text.Lazy as TL+import qualified Data.Text.Lazy.Builder as TLB++-- https://hackage.haskell.org/package/text-short+import qualified Data.Text.Short as ST++-- (ttc)+import qualified Data.TTC as TTC++-- (ttc:test)+import qualified TestTypes.Ex as Ex+import TestTypes.Ex (Ex(Ex))++------------------------------------------------------------------------------+-- $Instances++TTC.defaultRenderAndParseInstances+  [ ''Bool, ''Char, ''Double, ''Float, ''Integer+  , ''Int, ''Int8, ''Int16, ''Int32, ''Int64+  , ''Word, ''Word8, ''Word16, ''Word32, ''Word64+  , ''String+  , ''T.Text, ''TL.Text, ''TLB.Builder, ''ST.ShortText+  , ''BS.ByteString, ''BSL.ByteString, ''BSB.Builder, ''SBS.ShortByteString+  ]++------------------------------------------------------------------------------++instance Eq BSB.Builder where+  x == y = BSB.toLazyByteString x == BSB.toLazyByteString y++#if !MIN_VERSION_bytestring(0,11,1)+instance Show BSB.Builder where+  show = show . BSB.toLazyByteString+#endif++------------------------------------------------------------------------------+-- $HelperFunctions++assertRaises+  :: (HasCallStack, Exception e, Show a)+  => Proxy e+  -> a+  -> Assertion+assertRaises proxy x =+    handle+      (const (return ()) . (`asProxyTypeOf` proxy))+      (assertFailure . ("expected exception; got: " ++) . show =<< evaluate x)++------------------------------------------------------------------------------+-- $TestData++xS :: String+xS = "test テスト"++xT :: T.Text+xT = "test テスト"++xTL :: TL.Text+xTL = "test テスト"++xTLB :: TLB.Builder+xTLB = "test テスト"++xST :: ST.ShortText+xST = "test テスト"++xBS :: BS.ByteString+xBS = "test \xe3\x83\x86\xe3\x82\xb9\xe3\x83\x88"++xBSL :: BSL.ByteString+xBSL = "test \xe3\x83\x86\xe3\x82\xb9\xe3\x83\x88"++xBSB :: BSB.Builder+xBSB = "test テスト"++xSBS :: SBS.ShortByteString+xSBS = "test \xe3\x83\x86\xe3\x82\xb9\xe3\x83\x88"++-- U+FFFD is the Unicode replacement character+xiS :: String+xiS = "test \xfffd"++xiT :: T.Text+xiT = T.pack xiS++xiTL :: TL.Text+xiTL = TL.pack xiS++xiTLB :: TLB.Builder+xiTLB = TLB.fromString xiS++xiST :: ST.ShortText+xiST = ST.pack xiS++-- Lone continuation byte is invalid+xiBS :: BS.ByteString+xiBS = "test \xe3"++xiBSL :: BSL.ByteString+xiBSL = BSL.fromStrict xiBS++xiBSB :: BSB.Builder+xiBSB = BSB.byteString xiBS++xiSBS :: SBS.ShortByteString+xiSBS = SBS.toShort xiBS++------------------------------------------------------------------------------++newtype PosInt = PosInt Int+  deriving (Eq, Show)++instance TTC.Parse PosInt where+  parse = TTC.asS $ \ s -> case readMaybe s of+    Just i+      | i >= 0 -> Right $ PosInt i+      | otherwise -> Left $ TTC.fromS "not positive"+    Nothing -> Left $ TTC.fromS "not an integer"++instance TTC.Render PosInt where+  render (PosInt i) = TTC.convert $ show i++answer :: PosInt+answer = PosInt 42++answerS :: String+answerS = "42"++answerT :: T.Text+answerT = "42"++answerTL :: TL.Text+answerTL = "42"++answerTLB :: TLB.Builder+answerTLB = "42"++answerST :: ST.ShortText+answerST = "42"++answerBS :: BS.ByteString+answerBS = "42"++answerBSL :: BSL.ByteString+answerBSL = "42"++answerBSB :: BSB.Builder+answerBSB = "42"++answerSBS :: SBS.ShortByteString+answerSBS = "42"++answerZ :: Int+answerZ = 42++data IntError = IntInvalid+  deriving (Eq, Show)++------------------------------------------------------------------------------++data Color+  = Red+  | Green+  | Blue+  | White+  | Black+  deriving (Bounded, Enum, Eq, Show)++instance Read Color where+  readsPrec _ = TTC.readsEnum True True++instance TTC.Render Color where+  render = TTC.fromT . \case+    Red   -> "red"+    Green -> "green"+    Blue  -> "blue"+    White -> "white"+    Black -> "black"++data ColorError+  = ColorInvalid+  | ColorAmbiguous+  deriving (Eq, Show)++redS :: String+redS = "red"++redT :: T.Text+redT = "red"++redTL :: TL.Text+redTL = "red"++redTLB :: TLB.Builder+redTLB = "red"++redST :: ST.ShortText+redST = "red"++redBS :: BS.ByteString+redBS = "red"++redBSL :: BSL.ByteString+redBSL = "red"++redBSB :: BSB.Builder+redBSB = "red"++redSBS :: SBS.ShortByteString+redSBS = "red"++------------------------------------------------------------------------------++newtype PartialParser = PartialParser String+  deriving (Eq, Show)++instance TTC.Parse PartialParser where+  parse = TTC.asS $ \case+    "" -> Left $ TTC.fromT undefined+    s  -> Right $ PartialParser s++------------------------------------------------------------------------------+-- $Textual++testConvert :: TestTree+testConvert = testGroup "convert" $+    [ testCase "@@" $+        "test テスト" @=? TTC.convert @String @String "test テスト"+    , testCase "@_" $ xT @=? TTC.convert @String "test テスト"+    , testCase "_@" $ "test テスト" @=? TTC.convert @_ @TL.Text xT+    ]+    ++ mkTests "S"   xS+    ++ mkTests "T"   xT+    ++ mkTests "TL"  xTL+    ++ mkTests "TLB" xTLB+    ++ mkTests "ST"  xST+    ++ mkTests "BS"  xBS+    ++ mkTests "BSL" xBSL+    ++ mkTests "BSB" xBSB+    ++ mkTests "SBS" xSBS+  where+    mkTests :: TTC.Textual a => String -> a -> [TestTree]+    mkTests s x =+      [ testCase (s ++ "->S")   $ xS   @=? TTC.convert x+      , testCase (s ++ "->T")   $ xT   @=? TTC.convert x+      , testCase (s ++ "->TL")  $ xTL  @=? TTC.convert x+      , testCase (s ++ "->TLB") $ xTLB @=? TTC.convert x+      , testCase (s ++ "->ST")  $ xST  @=? TTC.convert x+      , testCase (s ++ "->BS")  $ xBS  @=? TTC.convert x+      , testCase (s ++ "->BSL") $ xBSL @=? TTC.convert x+      , testCase (s ++ "->BSB") $ xBSB @=? TTC.convert x+      , testCase (s ++ "->SBS") $ xSBS @=? TTC.convert x+      ]++------------------------------------------------------------------------------++testToX :: TestTree+testToX = testGroup "to*"+    [ mkTests "toS"   TTC.toS   xS   xiS+    , mkTests "toT"   TTC.toT   xT   xiT+    , mkTests "toTL"  TTC.toTL  xTL  xiTL+    , mkTests "toTLB" TTC.toTLB xTLB xiTLB+    , mkTests "toST"  TTC.toST  xST  xiST+    , mkTests "toBS"  TTC.toBS  xBS  xiBS+    , mkTests "toBSL" TTC.toBSL xBSL xiBSL+    , mkTests "toBSB" TTC.toBSB xBSB xiBSB+    , mkTests "toSBS" TTC.toSBS xSBS xiSBS+    ]+  where+    mkTests+      :: (Eq a, Show a)+      => TestName+      -> (forall t. TTC.Textual t => t -> a)+      -> a+      -> a+      -> TestTree+    mkTests testName f x xi = testGroup testName+      [ testCase "@"           $ x  @=? f @T.Text "test テスト"+      , testCase "S"           $ x  @=? f         xS+      , testCase "T"           $ x  @=? f         xT+      , testCase "TL"          $ x  @=? f         xTL+      , testCase "TLB"         $ x  @=? f         xTLB+      , testCase "ST"          $ x  @=? f         xST+      , testCase "BS"          $ x  @=? f         xBS+      , testCase "BSL"         $ x  @=? f         xBSL+      , testCase "BSB"         $ x  @=? f         xBSB+      , testCase "SBS"         $ x  @=? f         xSBS+      , testCase "BS/invalid"  $ xi @=? f         xiBS+      , testCase "BSL/invalid" $ xi @=? f         xiBSL+      , testCase "BSB/invalid" $ xi @=? f         xiBSB+      , testCase "SBS/invalid" $ xi @=? f         xiSBS+      ]++------------------------------------------------------------------------------++testFromX :: TestTree+testFromX = testGroup "from*"+    [ mkTests "fromS"   TTC.fromS   xS   Nothing+    , mkTests "fromT"   TTC.fromT   xT   Nothing+    , mkTests "fromTL"  TTC.fromTL  xTL  Nothing+    , mkTests "fromTLB" TTC.fromTLB xTLB Nothing+    , mkTests "fromST"  TTC.fromST  xST  Nothing+    , mkTests "fromBS"  TTC.fromBS  xBS  (Just xiBS)+    , mkTests "fromBSL" TTC.fromBSL xBSL (Just xiBSL)+    , mkTests "fromBSB" TTC.fromBSB xBSB (Just xiBSB)+    , mkTests "fromSBS" TTC.fromSBS xSBS (Just xiSBS)+    ]+  where+    mkTests+      :: (Eq a, Show a)+      => TestName+      -> (forall t. TTC.Textual t => a -> t)+      -> a+      -> Maybe a+      -> TestTree+    mkTests testName f x mXi = testGroup testName $+      [ testCase "@"   $ "test テスト" @=? f @String x+      , testCase "S"   $ xS            @=? f         x+      , testCase "T"   $ xT            @=? f         x+      , testCase "TL"  $ xTL           @=? f         x+      , testCase "TLB" $ xTLB          @=? f         x+      , testCase "ST"  $ xST           @=? f         x+      , testCase "BS"  $ xBS           @=? f         x+      , testCase "BSL" $ xBSL          @=? f         x+      , testCase "BSB" $ xBSB          @=? f         x+      , testCase "SBS" $ xSBS          @=? f         x+      ] +++      case mXi of+        Nothing -> []+        Just xi ->+          [ testCase "S/Invalid"   $ xiS   @=? f xi+          , testCase "T/Invalid"   $ xiT   @=? f xi+          , testCase "TL/Invalid"  $ xiTL  @=? f xi+          , testCase "TLB/Invalid" $ xiTLB @=? f xi+          , testCase "ST/Invalid"  $ xiST  @=? f xi+          , testCase "BS/Invalid"  $ xiBS  @=? f xi+          , testCase "BSL/Invalid" $ xiBSL @=? f xi+          , testCase "BSB/Invalid" $ xiBSB @=? f xi+          , testCase "SBS/Invalid" $ xiSBS @=? f xi+          ]++------------------------------------------------------------------------------++testAsX :: TestTree+testAsX = testGroup "as*"+    [ mkTests "asS"   TTC.asS   xS   xiS+    , mkTests "asT"   TTC.asT   xT   xiT+    , mkTests "asTL"  TTC.asTL  xTL  xiTL+    , mkTests "asTLB" TTC.asTLB xTLB xiTLB+    , mkTests "asST"  TTC.asST  xST  xiST+    , mkTests "asBS"  TTC.asBS  xBS  xiBS+    , mkTests "asBSL" TTC.asBSL xBSL xiBSL+    , mkTests "asBSB" TTC.asBSB xBSB xiBSB+    , mkTests "asSBS" TTC.asSBS xSBS xiSBS+    ]+  where+    mkTests+      :: (Eq a, Show a)+      => TestName+      -> (forall t. TTC.Textual t => (a -> a) -> t -> a)+      -> a+      -> a+      -> TestTree+    mkTests testName f x xi = testGroup testName+      [ testCase "@"           $ x  @=? f @T.Text id "test テスト"+      , testCase "S"           $ x  @=? f         id xS+      , testCase "T"           $ x  @=? f         id xT+      , testCase "TL"          $ x  @=? f         id xTL+      , testCase "TLB"         $ x  @=? f         id xTLB+      , testCase "ST"          $ x  @=? f         id xST+      , testCase "BS"          $ x  @=? f         id xBS+      , testCase "BSL"         $ x  @=? f         id xBSL+      , testCase "BSB"         $ x  @=? f         id xBSB+      , testCase "SBS"         $ x  @=? f         id xSBS+      , testCase "BS/invalid"  $ xi @=? f         id xiBS+      , testCase "BSL/invalid" $ xi @=? f         id xiBSL+      , testCase "BSB/invalid" $ xi @=? f         id xiBSB+      , testCase "SBS/invalid" $ xi @=? f         id xiSBS+      ]++------------------------------------------------------------------------------+-- $Render++testRender :: TestTree+testRender = testGroup "render"+    [ testCase "_@"  $ "42"      @=? TTC.render @_ @String answer+    , testCase "S"   $ answerS   @=? TTC.render            answer+    , testCase "T"   $ answerT   @=? TTC.render            answer+    , testCase "TL"  $ answerTL  @=? TTC.render            answer+    , testCase "TLB" $ answerTLB @=? TTC.render            answer+    , testCase "ST"  $ answerST  @=? TTC.render            answer+    , testCase "BS"  $ answerBS  @=? TTC.render            answer+    , testCase "BSL" $ answerBSL @=? TTC.render            answer+    , testCase "BSB" $ answerBSB @=? TTC.render            answer+    , testCase "SBS" $ answerSBS @=? TTC.render            answer+    ]++------------------------------------------------------------------------------++testRenderDefault :: TestTree+testRenderDefault = testGroup "RenderDefault"+    [ testCase "Bool" $ "True" @=? TTC.renderS True+    , testCase "Char" $ "*"    @=? TTC.renderS '*'+    , mkTestShow @Double  "Double"  3.14159+    , mkTestShow @Float   "Float"   3.14159+    , mkTestShow @Integer "Integer" 42+    , mkTestShow @Int     "Int"     42+    , mkTestShow @Int8    "Int8"    42+    , mkTestShow @Int16   "Int16"   42+    , mkTestShow @Int32   "Int32"   42+    , mkTestShow @Int64   "Int64"   42+    , mkTestShow @Word    "Word"    42+    , mkTestShow @Word8   "Word8"   42+    , mkTestShow @Word16  "Word16"  42+    , mkTestShow @Word32  "Word32"  42+    , mkTestShow @Word64  "Word64"  42+    , testCase "String"              $ xS @=? TTC.renderS xS+    , testCase "T.Text"              $ xS @=? TTC.renderS xT+    , testCase "TL.Text"             $ xS @=? TTC.renderS xTL+    , testCase "TLB.Builder"         $ xS @=? TTC.renderS xTLB+    , testCase "ST.ShortText"        $ xS @=? TTC.renderS xST+    , testCase "BS.ByteString"       $ xS @=? TTC.renderS xBS+    , testCase "BSL.ByteString"      $ xS @=? TTC.renderS xBSL+    , testCase "BSB.Builder"         $ xS @=? TTC.renderS xBSB+    , testCase "SBS.ShortByteString" $ xS @=? TTC.renderS xSBS+    ]+  where+    mkTestShow :: (Show a, TTC.Render a) => TestName -> a -> TestTree+    mkTestShow testName x = testCase testName $ show x @=? TTC.renderS x++------------------------------------------------------------------------------++testRenderWithShow :: TestTree+testRenderWithShow = testGroup "renderWithShow"+    [ testCase "@"   $ "42"      @=? TTC.renderWithShow @String answerZ+    , testCase "S"   $ answerS   @=? TTC.renderWithShow         answerZ+    , testCase "T"   $ answerT   @=? TTC.renderWithShow         answerZ+    , testCase "TL"  $ answerTL  @=? TTC.renderWithShow         answerZ+    , testCase "TLB" $ answerTLB @=? TTC.renderWithShow         answerZ+    , testCase "ST"  $ answerST  @=? TTC.renderWithShow         answerZ+    , testCase "BS"  $ answerBS  @=? TTC.renderWithShow         answerZ+    , testCase "BSL" $ answerBSL @=? TTC.renderWithShow         answerZ+    , testCase "BSB" $ answerBSB @=? TTC.renderWithShow         answerZ+    , testCase "SBS" $ answerSBS @=? TTC.renderWithShow         answerZ+    ]++------------------------------------------------------------------------------++testRenderX :: TestTree+testRenderX = testGroup "render*"+    [ testCase "renderS"   $ answerS   @=? TTC.renderS   answer+    , testCase "renderT"   $ answerT   @=? TTC.renderT   answer+    , testCase "renderTL"  $ answerTL  @=? TTC.renderTL  answer+    , testCase "renderTLB" $ answerTLB @=? TTC.renderTLB answer+    , testCase "renderST"  $ answerST  @=? TTC.renderST  answer+    , testCase "renderBS"  $ answerBS  @=? TTC.renderBS  answer+    , testCase "renderBSL" $ answerBSL @=? TTC.renderBSL answer+    , testCase "renderBSB" $ answerBSB @=? TTC.renderBSB answer+    , testCase "renderSBS" $ answerSBS @=? TTC.renderSBS answer+    ]++------------------------------------------------------------------------------+-- $Parse++testParse :: TestTree+testParse = testGroup "parse"+    [ testCase "_@@" $ Right answer @=? TTC.parse @_ @String @String "42"+    , testCase "S"   $ Right answer @=? parse answerS+    , testCase "T"   $ Right answer @=? parse answerT+    , testCase "TL"  $ Right answer @=? parse answerTL+    , testCase "TLB" $ Right answer @=? parse answerTLB+    , testCase "ST"  $ Right answer @=? parse answerST+    , testCase "BS"  $ Right answer @=? parse answerBS+    , testCase "BSL" $ Right answer @=? parse answerBSL+    , testCase "BSB" $ Right answer @=? parse answerBSB+    , testCase "SBS" $ Right answer @=? parse answerSBS+    , testCase "negative" $ Left "not positive"   @=? parse @String "-42"+    , testCase "invalid"  $ Left "not an integer" @=? parse @String "4a2"+    ]+  where+    parse :: TTC.Textual t => t -> Either String PosInt+    parse = TTC.parse++------------------------------------------------------------------------------++testParseDefault :: TestTree+testParseDefault = testGroup "ParseDefault"+    [ testGroup "Bool"+        [ testCase "True"    $ Right True          @=? parse       "True"+        , testCase "False"   $ Right False         @=? parse       "False"+        , testCase "invalid" $ Left "invalid Bool" @=? parse @Bool "false"+        ]+    , testGroup "Char"+        [ testCase "valid"    $ Right '*'           @=? parse       "*"+        , testCase "empty"    $ Left "invalid Char" @=? parse @Char ""+        , testCase "multiple" $ Left "invalid Char" @=? parse @Char "**"+        ]+    , mkTestsShow @Double  "Double"  3.14159+    , mkTestsShow @Float   "Float"   3.14159+    , mkTestsShow @Integer "Integer" 42+    , mkTestsShow @Int     "Int"     42+    , mkTestsShow @Int8    "Int8"    42+    , mkTestsShow @Int16   "Int16"   42+    , mkTestsShow @Int32   "Int32"   42+    , mkTestsShow @Int64   "Int64"   42+    , mkTestsShow @Word    "Word"    42+    , mkTestsShow @Word8   "Word8"   42+    , mkTestsShow @Word16  "Word16"  42+    , mkTestsShow @Word32  "Word32"  42+    , mkTestsShow @Word64  "Word64"  42+    , mkTestsTextual @String              "String"              xS+    , mkTestsTextual @T.Text              "T.Text"              xT+    , mkTestsTextual @TL.Text             "TL.Text"             xTL+    , mkTestsTextual @TLB.Builder         "TLB.Builder"         xTLB+    , mkTestsTextual @ST.ShortText        "ST.ShortText"        xST+    , mkTestsTextual @BS.ByteString       "BS.ByteString"       xBS+    , mkTestsTextual @BSL.ByteString      "BSL.ByteString"      xBSL+    , mkTestsTextual @BSB.Builder         "BSB.Builder"         xBSB+    , mkTestsTextual @SBS.ShortByteString "SBS.ShortByteString" xSBS+    ]+  where+    mkTestsShow+      :: forall a. (Eq a, Show a, TTC.Parse a)+      => TestName+      -> a+      -> TestTree+    mkTestsShow testName x = testGroup testName+      [ testCase "valid" $ Right x @=? parse (show x)+      , testCase "invalid" $+          Left ("invalid " ++ testName) @=? parse @a "invalid"+      ]++    mkTestsTextual+      :: forall a. (Eq a, IsString a, Show a, TTC.Parse a)+      => TestName+      -> a+      -> TestTree+    mkTestsTextual testName x = testGroup testName+      [ testCase "empty"    $ Right "" @=? parse @a ""+      , testCase "nonempty" $ Right x  @=? parse xS+      ]++    parse :: TTC.Parse a => String -> Either String a+    parse = TTC.parse++------------------------------------------------------------------------------++testWithError :: TestTree+testWithError = testGroup "withError"+    [ testCase "valid" $+        Right answer @=? TTC.withError @String @String undefined (Just answer)+    , testCase "invalid" $+        Left "err" @=? TTC.withError @String @String @PosInt "err" Nothing+    ]++testWithErrorX :: TestTree+testWithErrorX = testGroup "withError*"+    [ mkTests "withErrorS"   TTC.withErrorS+    , mkTests "withErrorT"   TTC.withErrorT+    , mkTests "withErrorTL"  TTC.withErrorTL+    , mkTests "withErrorTLB" TTC.withErrorTLB+    , mkTests "withErrorST"  TTC.withErrorST+    , mkTests "withErrorBS"  TTC.withErrorBS+    , mkTests "withErrorBSL" TTC.withErrorBSL+    , mkTests "withErrorBSB" TTC.withErrorBSB+    , mkTests "withErrorSBS" TTC.withErrorSBS+    ]+  where+    mkTests+      :: IsString e'+      => TestName+      -> (e' -> Maybe PosInt -> Either String PosInt)+      -> TestTree+    mkTests testName f = testGroup testName+      [ testCase "valid"   $ Right answer @=? f undefined (Just answer)+      , testCase "invalid" $ Left "err"   @=? f "err"     Nothing+      ]++------------------------------------------------------------------------------++testPrefixError :: TestTree+testPrefixError = testGroup "prefixError"+    [ testCase "valid" $+        Right answer+          @=? TTC.prefixError @String @String "oops: " (Right answer)+    , testCase "invalid" $+        Left "oops: err"+          @=? TTC.prefixError @String @String @PosInt "oops: " (Left "err")+    ]++testPrefixErrorX :: TestTree+testPrefixErrorX = testGroup "prefixError*"+    [ mkTests "prefixErrorS"   TTC.prefixErrorS+    , mkTests "prefixErrorT"   TTC.prefixErrorT+    , mkTests "prefixErrorTL"  TTC.prefixErrorTL+    , mkTests "prefixErrorTLB" TTC.prefixErrorTLB+    , mkTests "prefixErrorST"  TTC.prefixErrorST+    , mkTests "prefixErrorBS"  TTC.prefixErrorBS+    , mkTests "prefixErrorBSL" TTC.prefixErrorBSL+    , mkTests "prefixErrorBSB" TTC.prefixErrorBSB+    , mkTests "prefixErrorSBS" TTC.prefixErrorSBS+    ]+  where+    mkTests+      :: IsString e'+      => TestName+      -> (e' -> Either e' PosInt -> Either String PosInt)+      -> TestTree+    mkTests testName f = testGroup testName+      [ testCase "valid"   $ Right answer     @=? f "oops: " (Right answer)+      , testCase "invalid" $ Left "oops: err" @=? f "oops: " (Left "err")+      ]++------------------------------------------------------------------------------++testParseWithRead :: TestTree+testParseWithRead = testGroup "parseWithRead"+    [ testCase "@" $+        Right answerZ @=? TTC.parseWithRead @String IntInvalid "42"+    , testCase "S"   $ Right answerZ @=? parseWithRead answerS+    , testCase "T"   $ Right answerZ @=? parseWithRead answerT+    , testCase "TL"  $ Right answerZ @=? parseWithRead answerTL+    , testCase "TLB" $ Right answerZ @=? parseWithRead answerTLB+    , testCase "ST"  $ Right answerZ @=? parseWithRead answerST+    , testCase "BS"  $ Right answerZ @=? parseWithRead answerBS+    , testCase "BSL" $ Right answerZ @=? parseWithRead answerBSL+    , testCase "BSB" $ Right answerZ @=? parseWithRead answerBSB+    , testCase "SBS" $ Right answerZ @=? parseWithRead answerSBS+    , testCase "invalid" $ Left IntInvalid @=? parseWithRead @String "4a2"+    ]+  where+    parseWithRead :: TTC.Textual t => t -> Either IntError Int+    parseWithRead = TTC.parseWithRead IntInvalid++testParseWithRead' :: TestTree+testParseWithRead' = testGroup "parseWithRead'"+    [ testCase "@" $+        Right answerZ @=? TTC.parseWithRead' @String @String "Int" "42"+    , testCase "S"   $ Right answerZ @=? parseWithRead' answerS+    , testCase "T"   $ Right answerZ @=? parseWithRead' answerT+    , testCase "TL"  $ Right answerZ @=? parseWithRead' answerTL+    , testCase "TLB" $ Right answerZ @=? parseWithRead' answerTLB+    , testCase "ST"  $ Right answerZ @=? parseWithRead' answerST+    , testCase "BS"  $ Right answerZ @=? parseWithRead' answerBS+    , testCase "BSL" $ Right answerZ @=? parseWithRead' answerBSL+    , testCase "BSB" $ Right answerZ @=? parseWithRead' answerBSB+    , testCase "SBS" $ Right answerZ @=? parseWithRead' answerSBS+    , testCase "invalid" $ Left "invalid Int" @=? parseWithRead' @String "4a2"+    ]+  where+    parseWithRead' :: TTC.Textual t => t -> Either String Int+    parseWithRead' = TTC.parseWithRead' "Int"++testMaybeParseWithRead :: TestTree+testMaybeParseWithRead = testGroup "maybeParseWithRead"+    [ testCase "@" $ Just answerZ @=? TTC.maybeParseWithRead @String "42"+    , testCase "S"   $ Just answerZ @=? TTC.maybeParseWithRead answerS+    , testCase "T"   $ Just answerZ @=? TTC.maybeParseWithRead answerT+    , testCase "TL"  $ Just answerZ @=? TTC.maybeParseWithRead answerTL+    , testCase "TLB" $ Just answerZ @=? TTC.maybeParseWithRead answerTLB+    , testCase "ST"  $ Just answerZ @=? TTC.maybeParseWithRead answerST+    , testCase "BS"  $ Just answerZ @=? TTC.maybeParseWithRead answerBS+    , testCase "BSL" $ Just answerZ @=? TTC.maybeParseWithRead answerBSL+    , testCase "BSB" $ Just answerZ @=? TTC.maybeParseWithRead answerBSB+    , testCase "SBS" $ Just answerZ @=? TTC.maybeParseWithRead answerSBS+    , testCase "invalid" $+        Nothing @=? TTC.maybeParseWithRead @String @Int "4a2"+    ]++------------------------------------------------------------------------------++testParseEnum :: TestTree+testParseEnum = testGroup "parseEnum"+    [ testCase "@" $+        Right Red+          @=? TTC.parseEnum @String+            False False ColorInvalid ColorAmbiguous "red"+    , testCase "S"   $ Right Red @=? parseEnum False False redS+    , testCase "T"   $ Right Red @=? parseEnum False False redT+    , testCase "TL"  $ Right Red @=? parseEnum False False redTL+    , testCase "TLB" $ Right Red @=? parseEnum False False redTLB+    , testCase "ST"  $ Right Red @=? parseEnum False False redST+    , testCase "BS"  $ Right Red @=? parseEnum False False redBS+    , testCase "BSL" $ Right Red @=? parseEnum False False redBSL+    , testCase "BSB" $ Right Red @=? parseEnum False False redBSB+    , testCase "SBS" $ Right Red @=? parseEnum False False redSBS+    , testCase "CI" $ Right Red @=? parseEnum @String True False "Red"+    , testCase "!CI" $+        Left ColorInvalid @=? parseEnum @String False False "Red"+    , testCase "prefix" $ Right Red @=? parseEnum @String False True "r"+    , testCase "ambiguous" $+        Left ColorAmbiguous @=? parseEnum @String False True "bl"+    ]+  where+    parseEnum :: TTC.Textual t => Bool -> Bool -> t -> Either ColorError Color+    parseEnum allowCI allowPrefix =+      TTC.parseEnum allowCI allowPrefix ColorInvalid ColorAmbiguous++testParseEnum' :: TestTree+testParseEnum' = testGroup "parseEnum'"+    [ testCase "@" $+        Right Red+          @=? TTC.parseEnum' @String @String "Color" False False "red"+    , testCase "S"   $ Right Red @=? parseEnum' False False redS+    , testCase "T"   $ Right Red @=? parseEnum' False False redT+    , testCase "TL"  $ Right Red @=? parseEnum' False False redTL+    , testCase "TLB" $ Right Red @=? parseEnum' False False redTLB+    , testCase "ST"  $ Right Red @=? parseEnum' False False redST+    , testCase "BS"  $ Right Red @=? parseEnum' False False redBS+    , testCase "BSL" $ Right Red @=? parseEnum' False False redBSL+    , testCase "BSB" $ Right Red @=? parseEnum' False False redBSB+    , testCase "SBS" $ Right Red @=? parseEnum' False False redSBS+    , testCase "CI" $ Right Red @=? parseEnum' @String True False "Red"+    , testCase "!CI" $+        Left "invalid Color" @=? parseEnum' @String False False "Red"+    , testCase "prefix" $ Right Red @=? parseEnum' @String False True "r"+    , testCase "ambiguous" $+        Left "ambiguous Color" @=? parseEnum' @String False True "bl"+    ]+  where+    parseEnum' :: TTC.Textual t => Bool -> Bool -> t -> Either String Color+    parseEnum' = TTC.parseEnum' "Color"++------------------------------------------------------------------------------++testParseX :: TestTree+testParseX = testGroup "parse*"+    [ mkTests "parseS"   TTC.parseS   answerS+    , mkTests "parseT"   TTC.parseT   answerT+    , mkTests "parseTL"  TTC.parseTL  answerTL+    , mkTests "parseTLB" TTC.parseTLB answerTLB+    , mkTests "parseST"  TTC.parseST  answerST+    , mkTests "parseBS"  TTC.parseBS  answerBS+    , mkTests "parseBSL" TTC.parseBSL answerBSL+    , mkTests "parseBSB" TTC.parseBSB answerBSB+    , mkTests "parseSBS" TTC.parseSBS answerSBS+    ]+  where+    mkTests+      :: IsString a+      => TestName+      -> (a -> Either String PosInt)+      -> a+      -> TestTree+    mkTests testName f x = testGroup testName+      [ testCase "valid"   $ Right answer          @=? f x+      , testCase "invalid" $ Left "not an integer" @=? f "4a2"+      ]++------------------------------------------------------------------------------++testParseMaybe :: TestTree+testParseMaybe = testGroup "parseMaybe"+    [ testCase "@"   $ Just answer @=? TTC.parseMaybe @String "42"+    , testCase "S"   $ Just answer @=? TTC.parseMaybe         answerS+    , testCase "T"   $ Just answer @=? TTC.parseMaybe         answerT+    , testCase "TL"  $ Just answer @=? TTC.parseMaybe         answerTL+    , testCase "TLB" $ Just answer @=? TTC.parseMaybe         answerTLB+    , testCase "ST"  $ Just answer @=? TTC.parseMaybe         answerST+    , testCase "BS"  $ Just answer @=? TTC.parseMaybe         answerBS+    , testCase "BSL" $ Just answer @=? TTC.parseMaybe         answerBSL+    , testCase "BSB" $ Just answer @=? TTC.parseMaybe         answerBSB+    , testCase "SBS" $ Just answer @=? TTC.parseMaybe         answerSBS+    , testCase "noerror" $+        Just (PartialParser "test") @=? TTC.parseMaybe @String "test"+    , testCase "negative" $ Nothing @=? TTC.parseMaybe @String @PosInt "-42"+    , testCase "invalid" $ Nothing @=? TTC.parseMaybe @String @PosInt "4a2"+    ]++testParseMaybeX :: TestTree+testParseMaybeX = testGroup "parseMaybe*"+    [ mkTestsParseMaybe "parseMaybeS"   TTC.parseMaybeS   answerS+    , mkTestsParseMaybe "parseMaybeT"   TTC.parseMaybeT   answerT+    , mkTestsParseMaybe "parseMaybeTL"  TTC.parseMaybeTL  answerTL+    , mkTestsParseMaybe "parseMaybeTLB" TTC.parseMaybeTLB answerTLB+    , mkTestsParseMaybe "parseMaybeST"  TTC.parseMaybeST  answerST+    , mkTestsParseMaybe "parseMaybeBS"  TTC.parseMaybeBS  answerBS+    , mkTestsParseMaybe "parseMaybeBSL" TTC.parseMaybeBSL answerBSL+    , mkTestsParseMaybe "parseMaybeBSB" TTC.parseMaybeBSB answerBSB+    , mkTestsParseMaybe "parseMaybeSBS" TTC.parseMaybeSBS answerSBS+    ]++mkTestsParseMaybe+  :: IsString a+  => TestName+  -> (a -> Maybe PosInt)+  -> a+  -> TestTree+mkTestsParseMaybe testName f x = testGroup testName+    [ testCase "valid"   $ Just answer @=? f x+    , testCase "invalid" $ Nothing     @=? f "4a2"+    ]++------------------------------------------------------------------------------++testParseOrFail :: TestTree+testParseOrFail = testGroup "parseOrFail"+    [ testCase "@"   $ Just answer @=? TTC.parseOrFail @String "42"+    , testCase "S"   $ Just answer @=? TTC.parseOrFail         answerS+    , testCase "T"   $ Just answer @=? TTC.parseOrFail         answerT+    , testCase "TL"  $ Just answer @=? TTC.parseOrFail         answerTL+    , testCase "TLB" $ Just answer @=? TTC.parseOrFail         answerTLB+    , testCase "ST"  $ Just answer @=? TTC.parseOrFail         answerST+    , testCase "BS"  $ Just answer @=? TTC.parseOrFail         answerBS+    , testCase "BSL" $ Just answer @=? TTC.parseOrFail         answerBSL+    , testCase "BSB" $ Just answer @=? TTC.parseOrFail         answerBSB+    , testCase "SBS" $ Just answer @=? TTC.parseOrFail         answerSBS+    , testCase "noerror" $+        Just (PartialParser "test") @=? TTC.parseOrFail @String "test"+    , testCase "negative" $ Nothing @=? TTC.parseOrFail @String @PosInt "-42"+    , testCase "invalid" $ Nothing @=? TTC.parseOrFail @String @PosInt "4a2"+    ]++testParseOrFailX :: TestTree+testParseOrFailX = testGroup "parseOrFail*"+    [ mkTestsParseMaybe "parseOrFailS"   TTC.parseOrFailS   answerS+    , mkTestsParseMaybe "parseOrFailT"   TTC.parseOrFailT   answerT+    , mkTestsParseMaybe "parseOrFailTL"  TTC.parseOrFailTL  answerTL+    , mkTestsParseMaybe "parseOrFailTLB" TTC.parseOrFailTLB answerTLB+    , mkTestsParseMaybe "parseOrFailST"  TTC.parseOrFailST  answerST+    , mkTestsParseMaybe "parseOrFailBS"  TTC.parseOrFailBS  answerBS+    , mkTestsParseMaybe "parseOrFailBSL" TTC.parseOrFailBSL answerBSL+    , mkTestsParseMaybe "parseOrFailBSB" TTC.parseOrFailBSB answerBSB+    , mkTestsParseMaybe "parseOrFailSBS" TTC.parseOrFailSBS answerSBS+    ]++------------------------------------------------------------------------------++testParseUnsafe :: TestTree+testParseUnsafe = testGroup "parseUnsafe"+    [ testCase "@" $ answer @=? TTC.parseUnsafe @String "42"+    , testCase "S" $ answer @=? TTC.parseUnsafe answerS+    , testCase "T" $ answer @=? TTC.parseUnsafe answerT+    , testCase "TL" $ answer @=? TTC.parseUnsafe answerTL+    , testCase "TLB" $ answer @=? TTC.parseUnsafe answerTLB+    , testCase "ST" $ answer @=? TTC.parseUnsafe answerST+    , testCase "BS" $ answer @=? TTC.parseUnsafe answerBS+    , testCase "BSL" $ answer @=? TTC.parseUnsafe answerBSL+    , testCase "BSB" $ answer @=? TTC.parseUnsafe answerBSB+    , testCase "SBS" $ answer @=? TTC.parseUnsafe answerSBS+    , testCase "negative" . assertRaises (Proxy :: Proxy ErrorCall) $+        TTC.parseUnsafe @String @PosInt "-42"+    , testCase "invalid" . assertRaises (Proxy :: Proxy ErrorCall) $+        TTC.parseUnsafe @String @PosInt "4a2"+    ]++testParseUnsafeX :: TestTree+testParseUnsafeX = testGroup "parseUnsafe*"+    [ mkTests "parseUnsafeS"   TTC.parseUnsafeS   answerS+    , mkTests "parseUnsafeT"   TTC.parseUnsafeT   answerT+    , mkTests "parseUnsafeTL"  TTC.parseUnsafeTL  answerTL+    , mkTests "parseUnsafeTLB" TTC.parseUnsafeTLB answerTLB+    , mkTests "parseUnsafeST"  TTC.parseUnsafeST  answerST+    , mkTests "parseUnsafeBS"  TTC.parseUnsafeBS  answerBS+    , mkTests "parseUnsafeBSL" TTC.parseUnsafeBSL answerBSL+    , mkTests "parseUnsafeBSB" TTC.parseUnsafeBSB answerBSB+    , mkTests "parseUnsafeSBS" TTC.parseUnsafeSBS answerSBS+    ]+  where+    mkTests+      :: IsString a+      => TestName+      -> (a -> PosInt)+      -> a+      -> TestTree+    mkTests testName f x = testGroup testName+      [ testCase "valid" $ answer @=? f x+      , testCase "invalid" . assertRaises (Proxy :: Proxy ErrorCall) $ f "4a2"+      ]++------------------------------------------------------------------------------++testReadsWithParse :: TestTree+testReadsWithParse = testGroup "readsWithParse"+    [ testCase "valid"   $ [(answer, "")] @=? TTC.readsWithParse answerS+    , testCase "invalid" $ [] @=? (TTC.readsWithParse :: ReadS PosInt) "-42"+    ]++testReadsEnum :: TestTree+testReadsEnum = testGroup "readsEnum"+    [ testCase "valid"   $ Just Red @=? readMaybe        "R"+    , testCase "invalid" $ Nothing  @=? readMaybe @Color "bl"+    ]++------------------------------------------------------------------------------+-- $Valid++testValid :: TestTree+testValid = testCase "valid" $ Ex "test" @=? validConst+  where+    validConst :: Ex+    validConst = $$(TTC.valid "test")++testValidIsString :: TestTree+testValidIsString =+    testCase "validIsString" $ Ex "test" @=? validConst+  where+    validConst :: Ex+    validConst = $$("test")++testValidOf :: TestTree+testValidOf = testCase "validOf" $+    Ex "test" @=? $$(TTC.validOf (Proxy :: Proxy Ex) "test")++testMkValid :: TestTree+testMkValid = testCase "mkValid" $ Ex "test" @=? $$(Ex.valid "test")++testUntypedValidOf :: TestTree+testUntypedValidOf = testCase "untypedValidOf" $+    Ex "test" @=? $(TTC.untypedValidOf (Proxy :: Proxy Ex) "test")++testMkUntypedValid :: TestTree+testMkUntypedValid = testCase "mkUntypedValid" $+    Ex "test" @=? $(Ex.untypedValid "test")++testMkUntypedValidQQ :: TestTree+testMkUntypedValidQQ = testCase "mkUntypedValidQQ" $+    Ex "test" @=? [Ex.untypedValidQQ|test|]++------------------------------------------------------------------------------++tests :: TestTree+tests = testGroup "Data.TTC"+    [ testGroup "Textual"+        [ testConvert+        , testToX+        , testFromX+        , testAsX+        ]+    , testGroup "Render"+        [ testRender+        , testRenderDefault+        , testRenderWithShow+        , testRenderX+        ]+    , testGroup "Parse"+        [ testParse+        , testParseDefault+        , testWithError+        , testWithErrorX+        , testPrefixError+        , testPrefixErrorX+        , testParseWithRead+        , testParseWithRead'+        , testMaybeParseWithRead+        , testParseEnum+        , testParseEnum'+        , testParseX+        , testParseMaybe+        , testParseMaybeX+        , testParseOrFail+        , testParseOrFailX+        , testParseUnsafe+        , testParseUnsafeX         , testReadsWithParse         , testReadsEnum         ]
+ test/Data/TTC/Wrapper/Test.hs view
@@ -0,0 +1,174 @@+{-# LANGUAGE CPP #-}+{-# LANGUAGE DerivingVia #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE TypeApplications #-}++{-# OPTIONS_GHC -fno-warn-orphans #-}++module Data.TTC.Wrapper.Test (tests) where++-- https://hackage.haskell.org/package/bytestring+import qualified Data.ByteString as BS+import qualified Data.ByteString.Builder as BSB+import qualified Data.ByteString.Lazy as BSL+import qualified Data.ByteString.Short as SBS++-- https://hackage.haskell.org/package/tasty+import Test.Tasty (TestTree, testGroup)++-- https://hackage.haskell.org/package/tasty-hunit+import Test.Tasty.HUnit ((@=?), testCase)++-- https://hackage.haskell.org/package/text+import qualified Data.Text as T+import qualified Data.Text.Lazy as TL+import qualified Data.Text.Lazy.Builder as TLB++-- https://hackage.haskell.org/package/text-short+import qualified Data.Text.Short as ST++-- (ttc)+import qualified Data.TTC as TTC+import qualified Data.TTC.Wrapper as TTCW++------------------------------------------------------------------------------++instance Eq BSB.Builder where+  x == y = BSB.toLazyByteString x == BSB.toLazyByteString y++#if !MIN_VERSION_bytestring(0,11,1)+instance Show BSB.Builder where+  show = show . BSB.toLazyByteString+#endif++------------------------------------------------------------------------------+-- $TestData++xS :: String+xS = "test テスト"++xT :: T.Text+xT = "test テスト"++------------------------------------------------------------------------------+-- $WrapperS++newtype ExS = ExS String+  deriving (Eq, Ord, Show)+  deriving TTC.Parse via TTCW.WrapperS+  deriving TTC.Render via TTCW.WrapperS++testWrapperS :: TestTree+testWrapperS = testCase "WrapperS" $+    Right xT @=? (TTC.render <$> TTC.parse @ExS @_ @String xT)++------------------------------------------------------------------------------+-- $WrapperT++newtype ExT = ExT T.Text+  deriving (Eq, Ord, Show)+  deriving TTC.Parse via TTCW.WrapperT+  deriving TTC.Render via TTCW.WrapperT++testWrapperT :: TestTree+testWrapperT = testCase "WrapperT" $+    Right xS @=? (TTC.render <$> TTC.parse @ExT @_ @String xS)++------------------------------------------------------------------------------+-- $WrapperTL++newtype ExTL = ExTL TL.Text+  deriving (Eq, Ord, Show)+  deriving TTC.Parse via TTCW.WrapperTL+  deriving TTC.Render via TTCW.WrapperTL++testWrapperTL :: TestTree+testWrapperTL = testCase "WrapperTL" $+    Right xS @=? (TTC.render <$> TTC.parse @ExTL @_ @String xS)++------------------------------------------------------------------------------+-- $WrapperTLB++newtype ExTLB = ExTLB TLB.Builder+  deriving (Eq, Ord, Show)+  deriving TTC.Parse via TTCW.WrapperTLB+  deriving TTC.Render via TTCW.WrapperTLB++testWrapperTLB :: TestTree+testWrapperTLB = testCase "WrapperTLB" $+    Right xS @=? (TTC.render <$> TTC.parse @ExTLB @_ @String xS)++------------------------------------------------------------------------------+-- $WrapperST++newtype ExST = ExST ST.ShortText+  deriving (Eq, Ord, Show)+  deriving TTC.Parse via TTCW.WrapperST+  deriving TTC.Render via TTCW.WrapperST++testWrapperST :: TestTree+testWrapperST = testCase "WrapperST" $+    Right xS @=? (TTC.render <$> TTC.parse @ExST @_ @String xS)++------------------------------------------------------------------------------+-- $WrapperBS++newtype ExBS = ExBS BS.ByteString+  deriving (Eq, Ord, Show)+  deriving TTC.Parse via TTCW.WrapperBS+  deriving TTC.Render via TTCW.WrapperBS++testWrapperBS :: TestTree+testWrapperBS = testCase "WrapperBS" $+    Right xS @=? (TTC.render <$> TTC.parse @ExBS @_ @String xS)++------------------------------------------------------------------------------+-- $WrapperBSL++newtype ExBSL = ExBSL BSL.ByteString+  deriving (Eq, Ord, Show)+  deriving TTC.Parse via TTCW.WrapperBSL+  deriving TTC.Render via TTCW.WrapperBSL++testWrapperBSL :: TestTree+testWrapperBSL = testCase "WrapperBSL" $+    Right xS @=? (TTC.render <$> TTC.parse @ExBSL @_ @String xS)++------------------------------------------------------------------------------+-- $WrapperBSB++newtype ExBSB = ExBSB BSB.Builder+  deriving (Eq, Show)+  deriving TTC.Parse via TTCW.WrapperBSB+  deriving TTC.Render via TTCW.WrapperBSB++testWrapperBSB :: TestTree+testWrapperBSB = testCase "WrapperBSB" $+    Right xS @=? (TTC.render <$> TTC.parse @ExBSB @_ @String xS)++------------------------------------------------------------------------------+-- $WrapperSBS++newtype ExSBS = ExSBS SBS.ShortByteString+  deriving (Eq, Ord, Show)+  deriving TTC.Parse via TTCW.WrapperSBS+  deriving TTC.Render via TTCW.WrapperSBS++testWrapperSBS :: TestTree+testWrapperSBS = testCase "WrapperSBS" $+    Right xS @=? (TTC.render <$> TTC.parse @ExSBS @_ @String xS)++------------------------------------------------------------------------------++tests :: TestTree+tests = testGroup "Data.TTC.Wrapper"+    [ testWrapperS+    , testWrapperT+    , testWrapperTL+    , testWrapperTLB+    , testWrapperST+    , testWrapperBS+    , testWrapperBSL+    , testWrapperBSB+    , testWrapperSBS+    ]
test/Spec.hs view
@@ -5,10 +5,12 @@  -- (ttc:test) import qualified Data.TTC.Test+import qualified Data.TTC.Wrapper.Test  ------------------------------------------------------------------------------  main :: IO () main = defaultMain $ testGroup "test"     [ Data.TTC.Test.tests+    , Data.TTC.Wrapper.Test.tests     ]
− test/TestString.hs
@@ -1,31 +0,0 @@-{-# LANGUAGE DeriveLift #-}-{-# LANGUAGE TemplateHaskell #-}--module TestString where---- https://hackage.haskell.org/package/template-haskell-import qualified Language.Haskell.TH.Syntax as THS---- (ttc)-import qualified Data.TTC as TTC----------------------------------------------------------------------------------- $Type--newtype TestString = TestString String-  deriving (Eq, Ord, Show, THS.Lift)--instance TTC.Render TestString where-  render (TestString s) = TTC.convert s--instance TTC.Parse TestString where-  parse = TTC.asS $ Right . TestString----------------------------------------------------------------------------------- $API--$(TTC.mkValid "valid" ''TestString)--$(TTC.mkUntypedValid "untypedValid" ''TestString)--$(TTC.mkUntypedValidQQ "untypedValidQQ" ''TestString)
+ test/TestTypes/Ex.hs view
@@ -0,0 +1,31 @@+{-# LANGUAGE DeriveLift #-}+{-# LANGUAGE TemplateHaskell #-}++module TestTypes.Ex where++-- https://hackage.haskell.org/package/template-haskell+import qualified Language.Haskell.TH.Syntax as THS++-- (ttc)+import qualified Data.TTC as TTC++------------------------------------------------------------------------------+-- $Type++newtype Ex = Ex { exString :: String }+  deriving (Eq, Ord, Show, THS.Lift)++instance TTC.Parse Ex where+  parse = TTC.asS $ pure . Ex++instance TTC.Render Ex where+  render = TTC.convert . exString++------------------------------------------------------------------------------+-- $API++$(TTC.mkValid "valid" ''Ex)++$(TTC.mkUntypedValid "untypedValid" ''Ex)++$(TTC.mkUntypedValidQQ "untypedValidQQ" ''Ex)
ttc.cabal view
@@ -1,37 +1,35 @@-name:           ttc-version:        1.4.0.0-category:       Data, Text-synopsis:       Textual Type Classes+cabal-version:      3.0+name:               ttc+version:            1.5.0.0+synopsis:           Textual Type Classes description:   This library provides type classes for conversion between data types and   textual data types (strings).  Please see the README on GitHub at-  <https://github.com/ExtremaIS/ttc-haskell#readme>.+  <https://github.com/ExtremaIS/ttc-haskell/tree/main/ttc#readme>.+homepage:           https://github.com/ExtremaIS/ttc-haskell/tree/main/ttc#readme+bug-reports:        https://github.com/ExtremaIS/ttc-haskell/issues+license:            MIT+license-file:       LICENSE+author:             Travis Cardwell <travis.cardwell@extrema.is>+maintainer:         Travis Cardwell <travis.cardwell@extrema.is>+copyright:          Copyright (c) 2019-2025 Travis Cardwell+category:           Data, Text+build-type:         Simple -homepage:       https://github.com/ExtremaIS/ttc-haskell#readme-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-2023 Travis Cardwell-license:        MIT-license-file:   LICENSE+extra-doc-files:+  CHANGELOG.md+  README.md -cabal-version:  1.24-build-type:     Simple tested-with:-  GHC ==8.2.2-   || ==8.4.4-   || ==8.6.5-   || ==8.8.4+  GHC ==8.8.4    || ==8.10.7    || ==9.0.2    || ==9.2.8    || ==9.4.8-   || ==9.6.3-   || ==9.8.1--extra-source-files:-  CHANGELOG.md-  README.md+   || ==9.6.6+   || ==9.8.4+   || ==9.10.1+   || ==9.12.1  source-repository head   type: git@@ -41,12 +39,13 @@   hs-source-dirs: src   exposed-modules:       Data.TTC+    , Data.TTC.Wrapper   build-depends:-      base >=4.10.1 && <4.20-    , bytestring >=0.10.8 && <0.13-    , template-haskell >=2.12 && <2.22-    , text >=1.2.2 && <2.2-    , text-short >=0.1 && <0.2+      base >=4.13.0.0 && <4.22+    , bytestring >=0.10.10.1 && <0.13+    , template-haskell >=2.15.0.0 && <2.24+    , text >=1.2.4.0 && <2.2+    , text-short >=0.1.3 && <0.2   default-language: Haskell2010   default-extensions:       OverloadedStrings@@ -58,12 +57,13 @@   main-is: Spec.hs   other-modules:       Data.TTC.Test-    , TestString+    , Data.TTC.Wrapper.Test+    , TestTypes.Ex   build-depends:       base     , bytestring-    , tasty >=0.11 && <1.6-    , tasty-hunit >=0.8 && <0.11+    , tasty >=1.2.3 && <1.6+    , tasty-hunit >=0.10.0.3 && <0.11     , template-haskell     , text     , text-short