iconv-typed (empty) → 0.1.0.0
raw patch · 8 files changed
+278/−0 lines, 8 filesdep +basedep +bytestringdep +iconvsetup-changed
Dependencies added: base, bytestring, iconv, iconv-typed, shelly, template-haskell, text
Files
- LICENSE +30/−0
- Setup.hs +2/−0
- iconv-typed.cabal +79/−0
- src/Codec/Text/IConv/Typed.hs +78/−0
- src/Codec/Text/IConv/Typed/MacOSX.hs +14/−0
- src/Codec/Text/IConv/Typed/TH.hs +59/−0
- src/Codec/Text/IConv/Typed/Unix.hs +14/−0
- test/Spec.hs +2/−0
+ LICENSE view
@@ -0,0 +1,30 @@+Copyright Author name here (c) 2016++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 Author name here nor the names of other+ contributors may be used to endorse or promote products derived+ from this software without specific prior written permission.++THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ Setup.hs view
@@ -0,0 +1,2 @@+import Distribution.Simple+main = defaultMain
+ iconv-typed.cabal view
@@ -0,0 +1,79 @@+name: iconv-typed+version: 0.1.0.0+synopsis: Type safe iconv wrapper+homepage: https://github.com/adinapoli/iconv-typed#readme+license: BSD3+license-file: LICENSE+author: Alfredo Di Napoli+maintainer: alfredo.dinapoli@gmail.com+copyright: 2016 Alfredo Di Napoli+category: Web+build-type: Simple+cabal-version: >=1.10++description:+ [iconv-typed]+ .+ An experiment in bringing type safety to the <http://hackage.haskell.org/package/iconv iconv> package.+ .+ [Usage Example]+ This is _almost_ a drop-in replacement. Compare the original code from `iconv`:+ .+ > {-# LANGUAGE KindSignatures #-}+ > {-# LANGUAGE DataKinds #-}+ > {-# LANGUAGE OverloadedStrings #-}+ > module Main where+ >+ > import Codec.Text.IConv+ >+ > main :: IO ()+ > main = print $ convert "UTF-8" "LATIN1" "hello"+ .+ With the equivalent in `iconv-typed`:+ .+ > {-# LANGUAGE KindSignatures #-}+ > {-# LANGUAGE DataKinds #-}+ > {-# LANGUAGE OverloadedStrings #-}+ > module Main where+ >+ > import Codec.Text.IConv.Typed+ >+ > main :: IO ()+ > main = print $ convert (E :: E "UTF-8") (E :: E "LATIN1") "hello"+ .+ As a result, this code will compile and run only if the passed encoding resolves to a supported+ encoding (as retrieved at compile time by calling `iconv -l`). For example, the following won't compile:+ .+ > main = print $ convert (E :: E "UFT-8") (E :: E "LATIN1") "hello"+ .+ As `UFT` is mispelled.++library+ hs-source-dirs: src+ exposed-modules: Codec.Text.IConv.Typed+ Codec.Text.IConv.Typed.TH+ build-depends: base >= 4.7 && < 5,+ iconv < 0.5,+ shelly < 1.8.0.0,+ text < 1.4.0.0,+ template-haskell < 3.0.0.0,+ bytestring+ default-language: Haskell2010+ ghc-options: -Wall+ if os(darwin)+ other-modules: Codec.Text.IConv.Typed.MacOSX+ else+ other-modules: Codec.Text.IConv.Typed.Unix++test-suite iconv-typed-test+ type: exitcode-stdio-1.0+ hs-source-dirs: test+ main-is: Spec.hs+ build-depends: base+ , iconv-typed+ ghc-options: -threaded -rtsopts -with-rtsopts=-N+ default-language: Haskell2010++source-repository head+ type: git+ location: https://github.com/adinapoli/iconv-typed
+ src/Codec/Text/IConv/Typed.hs view
@@ -0,0 +1,78 @@+{-# LANGUAGE TemplateHaskell #-}+{-# LANGUAGE AllowAmbiguousTypes #-}+{-# LANGUAGE DataKinds #-}+{-# LANGUAGE TypeFamilies #-}+{-# LANGUAGE KindSignatures #-}+{-# OPTIONS_GHC -fno-warn-redundant-constraints #-}+module Codec.Text.IConv.Typed+ ( E(..)+ , ValidEncoding+ , convert+ , convertFuzzy+ , convertStrictly+ , convertLazily+ -- * Handy re-exports+ , I.reportConversionError+ , I.Fuzzy(..)+ , I.ConversionError(..)+ , I.Span(..)+ ) where++import qualified Codec.Text.IConv as I+import Codec.Text.IConv.Typed.TH+import Data.ByteString.Lazy+import GHC.TypeLits++$(generateEncodings)++--------------------------------------------------------------------------------+convert :: ( KnownSymbol k1+ , KnownSymbol k2+ , ValidEncoding k1 ~ 'True+ , ValidEncoding k2 ~ 'True+ )+ => E k1 -- ^ Name of input string encoding+ -> E k2 -- ^ Name of output string encoding+ -> ByteString -- ^ Input text+ -> ByteString -- ^ Output text+convert e1 e2 input = I.convert (reifyEncoding e1) (reifyEncoding e2) input++--------------------------------------------------------------------------------+convertFuzzy :: ( KnownSymbol k1+ , KnownSymbol k2+ , ValidEncoding k1 ~ 'True+ , ValidEncoding k2 ~ 'True+ )+ => I.Fuzzy -- ^ Whether to try and transliterate or+ -- discard characters with no direct conversion+ -> E k1 -- ^ Name of input string encoding+ -> E k2 -- ^ Name of output string encoding+ -> ByteString -- ^ Input text+ -> ByteString -- ^ Output text+convertFuzzy fuzzy fromEncoding toEncoding input =+ I.convertFuzzy fuzzy (reifyEncoding fromEncoding) (reifyEncoding toEncoding) input++--------------------------------------------------------------------------------+convertStrictly :: ( KnownSymbol k1+ , KnownSymbol k2+ , ValidEncoding k1 ~ 'True+ , ValidEncoding k2 ~ 'True+ )+ => E k1 -- ^ Name of input string encoding+ -> E k2 -- ^ Name of output string encoding+ -> ByteString -- ^ Input text+ -> Either ByteString I.ConversionError -- ^ Output text or conversion error+convertStrictly fromEncoding toEncoding input =+ I.convertStrictly (reifyEncoding fromEncoding) (reifyEncoding toEncoding) input++--------------------------------------------------------------------------------+convertLazily :: ( KnownSymbol k1+ , KnownSymbol k2+ , ValidEncoding k1 ~ 'True+ , ValidEncoding k2 ~ 'True+ )+ => E k1 -- ^ Name of input string encoding+ -> E k2 -- ^ Name of output string encoding+ -> ByteString -- ^ Input text+ -> [I.Span] -- ^ Output text spans+convertLazily fromEncoding toEncoding input = I.convertLazily (reifyEncoding fromEncoding) (reifyEncoding toEncoding) input
+ src/Codec/Text/IConv/Typed/MacOSX.hs view
@@ -0,0 +1,14 @@+{-# LANGUAGE OverloadedStrings #-}+module Codec.Text.IConv.Typed.MacOSX+ ( getAvailableEncodings+ ) where++import Codec.Text.IConv (EncodingName)+import System.IO.Unsafe (unsafePerformIO)+import qualified Data.Text as T+import Shelly++getAvailableEncodings :: [EncodingName]+getAvailableEncodings = unsafePerformIO $ shelly $ silently $ escaping False $ do+ map T.unpack . mconcat . map T.words . T.lines . T.strip <$> run "iconv" ["-l"]+{-# NOINLINE getAvailableEncodings #-}
+ src/Codec/Text/IConv/Typed/TH.hs view
@@ -0,0 +1,59 @@+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE DataKinds #-}+{-# LANGUAGE KindSignatures #-}+{-# LANGUAGE CPP #-}+module Codec.Text.IConv.Typed.TH where++#if defined darwin_HOST_OS+import Codec.Text.IConv.Typed.MacOSX+#else+import Codec.Text.IConv.Typed.Unix+#endif++import Codec.Text.IConv+import Data.List (foldl')+import Data.Maybe+import qualified Data.Text as T+import GHC.TypeLits+import Language.Haskell.TH+import Text.Read++data E (k :: Symbol) = E++reifyEncoding :: KnownSymbol k => E k -> String+reifyEncoding = symbolVal++filterNumericEncoding :: [EncodingName] -> [EncodingName]+filterNumericEncoding = filter (not . numerical)+ where+ numerical x = isJust (readMaybe x :: Maybe Int)++--------------------------------------------------------------------------------+replacementRules :: [(T.Text, T.Text)]+replacementRules = [ ("-", "__")+ , (".", "____")+ , (":", "___")+ ]++--------------------------------------------------------------------------------+applyRule :: T.Text -> (T.Text, T.Text) -> T.Text+applyRule t (input, output) = T.replace input output t++--------------------------------------------------------------------------------+convertName :: EncodingName -> EncodingName+convertName = T.unpack . (\t -> foldl' applyRule t replacementRules) . T.pack++-- closedTypeFamilyD :: Name -> [TyVarBndr] -> FamilyResultSig -> Maybe InjectivityAnn -> [TySynEqnQ] -> DecQ+++--------------------------------------------------------------------------------+generateEncodings :: Q [Dec]+generateEncodings = do+ let encs = getAvailableEncodings+ let k = mkName "k"+ let symbol = mkName "Symbol"+ let validEncoding = mkName "ValidEncoding"+ let bool = mkName "Bool"+ let instances = flip map encs $ \eName -> do+ return $ TySynEqn [LitT (StrTyLit eName)] (PromotedT (mkName "True"))+ (: []) <$> closedTypeFamilyD validEncoding [KindedTV k (ConT symbol)] (KindSig (ConT bool)) Nothing instances
+ src/Codec/Text/IConv/Typed/Unix.hs view
@@ -0,0 +1,14 @@+{-# LANGUAGE OverloadedStrings #-}+module Codec.Text.IConv.Typed.Unix+ ( getAvailableEncodings+ ) where++import Codec.Text.IConv (EncodingName)+import System.IO.Unsafe (unsafePerformIO)+import qualified Data.Text as T+import Shelly++getAvailableEncodings :: [EncodingName]+getAvailableEncodings = unsafePerformIO $ shelly $ silently $ escaping False $ do+ map T.unpack . T.splitOn "," . T.strip <$> run "iconv" ["-l"]+{-# NOINLINE getAvailableEncodings #-}
+ test/Spec.hs view
@@ -0,0 +1,2 @@+main :: IO ()+main = putStrLn "Test suite not yet implemented"