on master help sign in
Add char8 string encoding/decoding routines
0663aebHarendra Kumar
Changelog.md+2
@@ -14,6 +14,8 @@
14 unzipping and nesting features without breaking streaming. See the haddock
14 unzipping and nesting features without breaking streaming. See the haddock
15 docs for the module.
15 docs for the module.
16* MAJOR: Add `Streamly.FileSystem.File` module to support file IO.
16* MAJOR: Add `Streamly.FileSystem.File` module to support file IO.
17+* Add `Streamly.String` module for encoding/decoding character streams and
18+ other character stream operations.
17* Add the following to `Streamly.Prelude`:
19* Add the following to `Streamly.Prelude`:
18 * `foldrS` to fold a stream to a stream
20 * `foldrS` to fold a stream to a stream
19 * `foldrT` to fold a stream to an arbitrary transformer monad
21 * `foldrT` to fold a stream to an arbitrary transformer monad
src/Streamly/String.hs+47−17
@@ -7,13 +7,15 @@
7-- Stability : experimental
7-- Stability : experimental
8-- Portability : GHC
8-- Portability : GHC
9--
9--
10−-- Strings are simply character streams. Stream of 'Char' are the equivalent of
10+-- Stream of 'Char' are the equivalent of Haskell Strings but without any
11−-- Haskell Strings but without any performance issues that are usually
11+-- performance issues that are usually associated with the 'String' type.
12+-- Haskell lists are not suitable for storage in GC memory. We use streams for
12−-- associated with the 'String' type. We can use the usual stream processing
13+-- processing and arrays for storing. We can use the usual stream processing
13−-- routines in these 'Char' streams. The processing of streams is very
14+-- routines on these 'Char' streams. Stream processing is very efficient due to
14−-- efficient in terms of CPU and space usage. Streamly employs stream fusion
15+-- stream fusion. If strings are to be stored or buffered in memory, they can
15−-- which makes all the stream operations extremely fast.
16+-- be encoded to 'Word8' arrays using the encoding routines provided in the
16−--
17+-- module. Therefore, a separate type for text representation is not required.
18+
17-- The 'String' type in this module is just a synonym for the type @List Char@.
19-- The 'String' type in this module is just a synonym for the type @List Char@.
18-- It provides better performance compared to the standard Haskell @String@
20-- It provides better performance compared to the standard Haskell @String@
19-- type and can be used almost as a drop-in replacement, especially when used
21-- type and can be used almost as a drop-in replacement, especially when used
@@ -26,13 +28,13 @@
26-- vector.
28-- vector.
27--
29--
28module Streamly.String
30module Streamly.String
31+ (
29− ( String
32+ -- String
30− -- * Encoding and Decoding
31− -- | Streams of 'Word8' read from a file handle can be decoded into a
32− -- stream of unicode characters, similalrly before we write unicode text to
33− -- a file we can use an encoding routine to convert it to a stream of bytes
34− -- before writing.
35
33
34+ -- * Encoding and Decoding
35+ encodeChar8
36+ , encodeChar8Unchecked
37+ , decodeChar8
36{-
38{-
37 , encodeUtf8
39 , encodeUtf8
38 , decodeUtf8
40 , decodeUtf8
@@ -57,14 +59,18 @@ module Streamly.String
57 )
59 )
58where
60where
59
61
62+import Data.Char (ord)
60−-- import Data.Word (Word8)
63+import Data.Word (Word8)
64+import GHC.Base (unsafeChr)
61−-- import Streamly (IsStream)
65+import Streamly (IsStream)
62−import Streamly.List (List)
66+-- import Streamly.List (List)
63import Prelude hiding (String, lines, words, unlines, unwords)
67import Prelude hiding (String, lines, words, unlines, unwords)
64-- import Streamly.Fold (Fold)
68-- import Streamly.Fold (Fold)
65-- import Streamly.Array (Array)
69-- import Streamly.Array (Array)
66
70
71+import qualified Streamly.Prelude as S
72+
67−type String = List Char
73+-- type String = List Char
68
74
69-------------------------------------------------------------------------------
75-------------------------------------------------------------------------------
70-- Encoding/Decoding Characters
76-- Encoding/Decoding Characters
@@ -77,6 +83,30 @@ type String = List Char
77-- Encoding/Decoding Unicode Characters
83-- Encoding/Decoding Unicode Characters
78-------------------------------------------------------------------------------
84-------------------------------------------------------------------------------
79
85
86+-- | Decode a stream of bytes to Unicode characters by mapping each byte to a
87+-- corresponding Unicode 'Char' in 0-255 range.
88+decodeChar8 :: (IsStream t, Monad m) => t m Word8 -> t m Char
89+decodeChar8 = S.map (unsafeChr . fromIntegral)
90+
91+-- | Encode a stream of Unicode characters to bytes by mapping each character
92+-- to a byte in 0-255 range. Throws an error if the input stream contains
93+-- characters beyond 255.
94+encodeChar8 :: (IsStream t, Monad m) => t m Char -> t m Word8
95+encodeChar8 = S.map convert
96+ where
97+ convert c =
98+ let codepoint = ord c
99+ in if codepoint > 255
100+ then error $ "Streamly.String.encodeChar8 invalid \
101+ \input char codepoint " ++ show codepoint
102+ else fromIntegral codepoint
103+
104+-- | Like 'encodeChar8' but silently truncates and maps input characters beyond
105+-- 255 to (incorrect) chars in 0-255 range. No error or exception is thrown
106+-- when such truncation occurs.
107+encodeChar8Unchecked :: (IsStream t, Monad m) => t m Char -> t m Word8
108+encodeChar8Unchecked = S.map (fromIntegral . ord)
109+
80{-
110{-
81-- | Decode a UTF-8 encoded bytestream to a stream of Unicode characters.
111-- | Decode a UTF-8 encoded bytestream to a stream of Unicode characters.
82decodeUtf8 :: IsStream t => t m Word8 -> t m Char
112decodeUtf8 :: IsStream t => t m Word8 -> t m Char
streamly.cabal+3−1
@@ -200,7 +200,6 @@ library
200
200
201 -- Pure streams
201 -- Pure streams
202 , Streamly.List
202 , Streamly.List
203− , Streamly.String
204
203
205 -- Folds
204 -- Folds
206 , Streamly.Fold.Types
205 , Streamly.Fold.Types
@@ -212,6 +211,9 @@ library
212 , Streamly
211 , Streamly
213 , Streamly.Fold
212 , Streamly.Fold
214
213
214+ , Streamly.String
215+
216+ -- IO devices
215 , Streamly.Mem.Array
217 , Streamly.Mem.Array
216 , Streamly.FileSystem.File
218 , Streamly.FileSystem.File
217 , Streamly.Network.Socket
219 , Streamly.Network.Socket