@@ -7,13 +7,15 @@
7-- Stability : experimental
7-- Stability : experimental
8-- Portability : GHC
8-- Portability : GHC
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.
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 @@
28module Streamly.String
30module Streamly.String
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+ -- * Encoding and Decoding
36+ , encodeChar8Unchecked
37 , encodeUtf8
39 , encodeUtf8
38 , decodeUtf8
40 , decodeUtf8
@@ -57,14 +59,18 @@ module Streamly.String
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)
71+import qualified Streamly.Prelude as S
67−type String = List Char
73+-- type String = List Char
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-------------------------------------------------------------------------------
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)
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
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
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)
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