File: Base.hs

package info (click to toggle)
haskell-encoding 0.10.2-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 3,392 kB
  • sloc: haskell: 4,372; ansic: 11; makefile: 4
file content (101 lines) | stat: -rw-r--r-- 3,473 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
{-# LANGUAGE ExistentialQuantification #-}
module Data.Encoding.Base where

import Data.Encoding.Exception
import Data.Encoding.ByteSource
import Data.Encoding.ByteSink

import Control.Throws
import Data.Array.Unboxed as Array
import Data.Map as Map hiding ((!))
import Data.Word
import Data.Char
import Data.Typeable

{- | The base class for all encodings. At least decodeChar, encodeChar and encodeable must be implemented.
 -}
class Encoding enc where
    -- | Read a single character of a ByteSource
    decodeChar :: ByteSource m => enc -> m Char
    -- | Encode a single character and write it to a ByteSink
    encodeChar :: ByteSink m => enc -> Char -> m ()
    -- | Read characters from a ByteSource until it is empty
    decode :: ByteSource m => enc -> m String
    decode e = untilM sourceEmpty (decodeChar e)
    -- | Encode a String and write it to a ByteSink
    encode :: ByteSink m => enc -> String -> m ()
    encode e = mapM_ (encodeChar e)
    -- | Tests whether a given character is representable in the Encoding.
    --   If this yields True, encodeChar must not fail.
    --   If it yields False, encodeChar _must_ throw an exception.
    encodeable :: enc -> Char -> Bool

{- | Wraps all possible encoding types into one data type.
     Used when a function needs to return an encoding.
 -}
data DynEncoding = forall enc. (Encoding enc,Eq enc,Typeable enc,Show enc) => DynEncoding enc

instance Show DynEncoding where
    show (DynEncoding enc) = show enc

instance Encoding DynEncoding where
    decodeChar (DynEncoding e) = decodeChar e
    encodeChar (DynEncoding e) = encodeChar e
    decode (DynEncoding e) = decode e
    encode (DynEncoding e) = encode e
    encodeable (DynEncoding e) = encodeable e

instance Eq DynEncoding where
    (DynEncoding e1) == (DynEncoding e2) = case cast e2 of
                                             Nothing -> False
                                             Just e2' -> e1==e2'

untilM :: Monad m => m Bool -> m a -> m [a]
untilM check act = do
  end <- check
  if end
    then return []
    else (do
           x <- act
           xs <- untilM check act
           return (x:xs)
         )

untilM_ :: Monad m => m Bool -> m a -> m ()
untilM_ check act = untilM check act >> return ()

encodeWithMap :: ByteSink m => Map Char Word8 -> Char -> m ()
encodeWithMap mp c = case Map.lookup c mp of
                       Nothing -> throwException $ HasNoRepresentation c
                       Just v -> pushWord8 v

encodeWithMap2 :: ByteSink m => Map Char (Word8,Word8) -> Char -> m ()
encodeWithMap2 mp c = case Map.lookup c mp of
                        Nothing -> throwException $ HasNoRepresentation c
                        Just (w1,w2) -> do
                          pushWord8 w1
                          pushWord8 w2

encodeableWithMap :: Map Char a -> Char -> Bool
encodeableWithMap = flip Map.member

decodeWithArray :: ByteSource m => UArray Word8 Int -> m Char
decodeWithArray arr = do
  w <- fetchWord8
  let res = arr!w
  if res < 0
    then throwException $ IllegalCharacter w
    else return $ chr res

decodeWithArray2 :: ByteSource m => UArray (Word8,Word8) Int -> m Char
decodeWithArray2 arr = do
  w1 <- fetchWord8
  w2 <- fetchWord8
  if inRange (bounds arr) (w1,w2)
    then (do
           let res = arr!(w1,w2)
           if res < 0
             then throwException $ IllegalCharacter w1
             else return $ chr res
         )
    else throwException $ IllegalCharacter w1