enum-utf8 (empty) → 0.1.0.0
raw patch · 6 files changed
+287/−0 lines, 6 filesdep +arraydep +basedep +bytestringsetup-changed
Dependencies added: array, base, bytestring, hashable, possibly, render-utf8, unordered-containers
Files
- ChangeLog.md +3/−0
- LICENSE +30/−0
- README.md +37/−0
- Setup.hs +2/−0
- enum-utf8.cabal +46/−0
- src/Text/Enum/Utf8.hs +169/−0
+ ChangeLog.md view
@@ -0,0 +1,3 @@+# 0.1.0.0++ * first release
+ LICENSE view
@@ -0,0 +1,30 @@+Copyright Chris Dornan (c) 2019++All rights reserved.++Redistribution and use in source and binary forms, with or without+modification, are permitted provided that the following conditions are met:++ * Redistributions of source code must retain the above copyright+ notice, this list of conditions and the following disclaimer.++ * Redistributions in binary form must reproduce the above+ copyright notice, this list of conditions and the following+ disclaimer in the documentation and/or other materials provided+ with the distribution.++ * Neither the name of Chris Dornan nor the names of other+ contributors may be used to endorse or promote products derived+ from this software without specific prior written permission.++THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ README.md view
@@ -0,0 +1,37 @@+# enum-utf8++An experimental toolkit for rendering enumerated types into `Utf8` from+the [`render-utf8`](http://hackage.haskell.org/package/render-utf8) package)+and parsing them back again with the provided `Utf8Parsable` type class.+It is based on the `render-utf8` and+[`enum-text`](http://hackage.haskell.org/package/enum-text) packages.++To get the `Buildable` and `TextParsable` instances for an enumerated data type+use the following pattern:++```+import Text.Enum.Utf8+import Text.Utf8++data Foo = FOO_bar | FOO_bar_baz+ deriving (Bounded,Enum,Eq,Ord,Show)++instance EnumUtf8 Foo+instance Renderable Foo where render = renderEnumUtf8+instance Utf8Parsable Foo where parseUtf8 = parseEnumUtf8++main :: IO ()+main = mapM_ (cvtLn . render) [minBound..maxBound::Foo]+```++This will use the default configuration for generating the text of each+enumeration from the derived `show` text, namely:++ * removing the prefix upto and including the first underscore (`_`);+ * converting each subsequent underscore (`_`) into a dash (`-`).++See the Haddocks for details on how to override this default configuration for+any given enumeration type.++Functions for generating and parsing UTF-8 encoded ByteStrings (suitable for+cassava), as are `Hashable` functions.
+ Setup.hs view
@@ -0,0 +1,2 @@+import Distribution.Simple+main = defaultMain
+ enum-utf8.cabal view
@@ -0,0 +1,46 @@+cabal-version: 1.12++-- This file has been generated from package.yaml by hpack version 0.31.1.+--+-- see: https://github.com/sol/hpack+--+-- hash: e211f4d5f7164b70e08701690bca40f5199d475d0d41b94e006c0e44404db94f++name: enum-utf8+version: 0.1.0.0+synopsis: An experimental Utf8 parsing toolkit for enumerated types+description: An experimental Utf8 rendering and parsing toolkit for enumerated types based on enum-text and render-utf8. Please see the README on GitHub at <https://github.com/cdornan/enum-text#readme>+category: Text+homepage: https://github.com/cdornan/enum-text#readme+bug-reports: https://github.com/cdornan/enum-text/issues+author: Chris Dornan+maintainer: chris@chrisdornan.com+copyright: 2019 Chris Dornan+license: BSD3+license-file: LICENSE+build-type: Simple+extra-source-files:+ README.md+ ChangeLog.md++source-repository head+ type: git+ location: https://github.com/cdornan/enum-text++library+ exposed-modules:+ Text.Enum.Utf8+ other-modules:+ Paths_enum_utf8+ hs-source-dirs:+ src+ ghc-options: -Wall+ build-depends:+ array+ , base >=4.8.2 && <10+ , bytestring+ , hashable+ , possibly+ , render-utf8+ , unordered-containers+ default-language: Haskell2010
+ src/Text/Enum/Utf8.hs view
@@ -0,0 +1,169 @@+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE RecordWildCards #-}+{-# LANGUAGE ScopedTypeVariables #-}++module Text.Enum.Utf8+ ( EnumUtf8(..)+ , Utf8Parsable(..)+ , EnumUtf8Config(..)+ , defaultEnumUtf8Config+ ) where++import Data.Array+import qualified Data.ByteString.Char8 as B+import qualified Data.ByteString.Lazy as BL+import qualified Data.ByteString.Builder as BB+import Data.Coerce+import Data.Hashable+import Data.Possibly+import qualified Data.HashMap.Strict as HM+import Data.String+import Text.Utf8+++-- | a class for 'T.Text' parsers.+class Utf8Parsable a where+ parseUtf8 :: Utf8 -> Possibly a++{- | our toolkit for enumerated types which should be defined as follows:++@+import Text.Enum.Utf8+import Text.Utf8++data Foo = FOO_bar | FOO_bar_baz+ deriving (Bounded,Enum,Eq,Ord,Show)++instance EnumUtf8 Foo+instance Renderable Foo where render = renderEnumUtf8+instance Utf8Parsable Foo where parseUtf8 = parseEnumUtf8++main :: IO ()+main = mapM_ (cvtLn . render) [minBound..maxBound::Foo]+@++-}+class ( Renderable e+ , Bounded e+ , Enum e+ , Eq e+ , Ord e+ , Show e+ , Utf8Parsable e+ ) => EnumUtf8 e where++ -- | Configures the textual representation of @e@ generated by renderEnumUtf8.+ configEnumUtf8 :: e -> EnumUtf8Config+ configEnumUtf8 _ = defaultEnumUtf8Config++ -- | Generate the standard textual representation according to+ -- 'configEnumUtf8' by default.+ renderEnumUtf8 :: e -> Utf8+ renderEnumUtf8 e = enumUtf8Array ! I e++ -- | Parses an @e@ according to the 'renderEnumUtf8' render.+ parseEnumUtf8 :: Utf8 -> Possibly e+ parseEnumUtf8 u = maybe (Left m) Right $ HM.lookup b hashmap_b+ where+ m = "parseEnumUtf8: enumeration not recognised: "++show b+ b = utf8_to_bs u++ -- | A cassava field encoder, using 'the renderEnumUtf8' format.+ toFieldEnumUtf8 :: e -> B.ByteString+ toFieldEnumUtf8 e = enumByteStringArray ! I e++ -- | A cassava field parser using the 'renderEnumUtf8' format.+ fromFieldEnumUtf8_ :: Monad m => B.ByteString -> m e+ fromFieldEnumUtf8_ bs = maybe (fail msg) return $ HM.lookup bs hashmap_b+ where+ msg = "fromFieldEnumUtf8_: enumeration not recognised: "++show bs++ -- | For hashing @e@ with the 'renderEnumUtf8' representation.+ hashWithSaltEnumUtf8 :: Int -> e -> Int+ hashWithSaltEnumUtf8 n = hashWithSalt n . toFieldEnumUtf8+++-------------------------------------------------------------------------------+-- EnumUtf8Config, defaultEnumUtf8Config+-------------------------------------------------------------------------------++-- | configures the default implementation of 'renderEnumUtf8'+data EnumUtf8Config =+ EnumUtf8Config+ { _etc_text_prep :: String -> String -- ^ applied to the output of 'show';+ -- by default strips each data+ -- constructor up to and including+ -- the first '_'+ , _etc_char_prep :: Char -> Char -- ^ applied to each character of+ -- the outpout of '_etc_text_prep'+ }++defaultEnumUtf8Config :: EnumUtf8Config+defaultEnumUtf8Config =+ EnumUtf8Config+ { _etc_text_prep = defaultTextPrep+ , _etc_char_prep = defaultCharPrep+ }++defaultTextPrep :: String -> String+defaultTextPrep s =+ case dropWhile (/='_') s of+ _:rst@(_:_) -> fromString rst+ _ -> error $ "defaultTextPrep: bad data constructor: "++s++defaultCharPrep :: Char -> Char+defaultCharPrep c = case c of+ '_' -> '-'+ _ -> c+++-------------------------------------------------------------------------------+-- arrays+-------------------------------------------------------------------------------++newtype I a = I { _I :: a }+ deriving (Eq,Ord)++instance EnumUtf8 e => Ix (I e) where+ range (l,h) = coerce [_I l.._I h]+ index (l,_) x = fromEnum (_I x) - fromEnum (_I l)+ inRange (l,h) x = _I l <= _I x && _I x <= _I h++-- | array of texts constructed with 'configEnumUtf8'+enumUtf8Array :: forall e . EnumUtf8 e => Array (I e) Utf8+enumUtf8Array =+ listArray (I minBound,I maxBound)+ [ fromString $ map _etc_char_prep $ _etc_text_prep $ show e+ | e <- [minBound..maxBound :: e]+ ]+ where+ EnumUtf8Config{..} = configEnumUtf8 (minBound :: e)++-- | array of 'B.ByteString' generated from 'renderEnumUtf8'+enumByteStringArray :: forall e . EnumUtf8 e => Array (I e) B.ByteString+enumByteStringArray =+ listArray (I minBound,I maxBound)+ [ utf8_to_bs $ renderEnumUtf8 e+ | e <- [minBound..maxBound :: e]+ ]+++-------------------------------------------------------------------------------+-- hashmap+-------------------------------------------------------------------------------++-- | 'B.ByteString' 'HM.HashMap' based on 'renderEnumUtf8' representation+hashmap_b :: EnumUtf8 e => HM.HashMap B.ByteString e+hashmap_b =+ HM.fromList+ [ (utf8_to_bs $ renderEnumUtf8 c,c)+ | c <- [minBound..maxBound]+ ]+++-------------------------------------------------------------------------------+-- utf8_to_bs+-------------------------------------------------------------------------------++utf8_to_bs :: Utf8 -> B.ByteString+utf8_to_bs = BL.toStrict . BB.toLazyByteString . coerce