@@ -1,4 +1,5 @@
11{-# LANGUAGE BangPatterns, CPP, GeneralizedNewtypeDeriving #-}
2+{-# LANGUAGE JavaScriptFFI, ForeignFunctionInterface, UnliftedFFITypes, MagicHash #-}
23-- |
34-- Module : Data.Text.Foreign
45-- Copyright : (c) 2009, 2010 Bryan O'Sullivan
@@ -50,6 +51,13 @@ import Foreign.Marshal.Alloc (allocaBytes)
5051import Foreign.Ptr (Ptr, castPtr, plusPtr)
5152import Foreign.Storable (peek, poke)
5253import qualified Data.Text.Array as A
54+#ifdef __GHCJS__
55+import Data.JSString (JSString)
56+import GHC.Exts (ByteArray#, Int#)
57+import GHC.Prim (int2Word#)
58+import GHC.Int (Int(..))
59+import GHC.Word (Word16(..))
60+#endif
5361
5462-- $interop
5563--
@@ -74,11 +82,15 @@ fromPtr :: Ptr Word16 -- ^ source array
7482 -> I16 -- ^ length of source array (in 'Word16' units)
7583 -> IO Text
7684fromPtr _ (I16 0) = return empty
77−fromPtr ptr (I16 len) =
85+fromPtr ptr (I16 (len@(I# len#))) =
7886#if defined(ASSERTS)
7987 assert (len > 0) $
8088#endif
89+#if defined(__GHCJS__)
90+ return $! Text (js_toString (A.aBA arr) 0# len#)
91+#else
8192 return $! Text arr 0 len
93+#endif
8294 where
8395 arr = A.run (A.new len >>= copy)
8496 copy marr = loop ptr 0
@@ -102,14 +114,30 @@ fromPtr ptr (I16 len) =
102114-- end of the prefix will be advanced by one additional 'Word16' unit
103115-- to maintain its validity.
104116takeWord16 :: I16 -> Text -> Text
117+#ifdef __GHCJS__
118+takeWord16 (I16 n@(I# n#)) t@(Text jss)
119+ | n <= 0 = empty
120+ | n >= len || m >= len = t
121+ | otherwise = Text (js_substr 0# n# jss)
122+#else
105123takeWord16 (I16 n) t@(Text arr off len)
106124 | n <= 0 = empty
107125 | n >= len || m >= len = t
108126 | otherwise = Text arr off m
127+#endif
109128 where
129+#ifdef __GHCJS__
130+ len = js_length jss
131+ arr = js_length jss
132+ m@(I# m#) | w < 0xD800 || w > 0xDBFF = n
133+ | otherwise = n+1
134+ w = I# w#
135+ w# = js_charCodeAt (n-1) jss
136+#else
110137 m | w < 0xD800 || w > 0xDBFF = n
111138 | otherwise = n+1
112139 w = A.unsafeIndex arr (off+n-1)
140+#endif
113141
114142-- | /O(1)/ Return the suffix of the 'Text', with @n@ 'Word16' units
115143-- dropped from its beginning.
@@ -118,18 +146,45 @@ takeWord16 (I16 n) t@(Text arr off len)
118146-- beginning of the suffix will be advanced by one additional 'Word16'
119147-- unit to maintain its validity.
120148dropWord16 :: I16 -> Text -> Text
149+#ifdef __GHCJS__
150+dropWord16 (I16 n@(I# n#)) t@(Text jss)
151+ | n <= 0 = t
152+ | n >= len || m >= len = empty
153+ | otherwise = Text (js_substr1 n# jss)
154+#else
121155dropWord16 (I16 n) t@(Text arr off len)
122156 | n <= 0 = t
123157 | n >= len || m >= len = empty
124158 | otherwise = Text arr (off+m) (len-m)
159+#endif
125160 where
161+#ifdef __GHCJS__
162+ len = js_length jss
163+ arr = js_length jss
164+ m@(I# m#) | w < 0xD800 || w > 0xDBFF = n
165+ | otherwise = n+1
166+ w = I# w#
167+ w# = js_charCodeAt (n-1) jss
168+#else
126169 m | w < 0xD800 || w > 0xDBFF = n
127170 | otherwise = n+1
128171 w = A.unsafeIndex arr (off+n-1)
172+#endif
129173
130174-- | /O(n)/ Copy a 'Text' to an array. The array is assumed to be big
131175-- enough to hold the contents of the entire 'Text'.
132176unsafeCopyToPtr :: Text -> Ptr Word16 -> IO ()
177+#ifdef __GHCJS__
178+unsafeCopyToPtr (Text jst) ptr = loop ptr off
179+ where
180+ end = off + len
181+ loop !p !i | i == end = return ()
182+ | otherwise = do
183+ poke p (W16# (int2Word# (js_charCodeAt i jst)))
184+ loop (p `plusPtr` 2) (i + 1)
185+ off = 0
186+ len = js_length jst
187+#else
133188unsafeCopyToPtr (Text arr off len) ptr = loop ptr off
134189 where
135190 end = off + len
@@ -137,21 +192,38 @@ unsafeCopyToPtr (Text arr off len) ptr = loop ptr off
137192 | otherwise = do
138193 poke p (A.unsafeIndex arr i)
139194 loop (p `plusPtr` 2) (i + 1)
195+#endif
140196
141197-- | /O(n)/ Perform an action on a temporary, mutable copy of a
142198-- 'Text'. The copy is freed as soon as the action returns.
143199useAsPtr :: Text -> (Ptr Word16 -> I16 -> IO a) -> IO a
200+#ifdef __GHCJS__
201+useAsPtr t@(Text jst) action =
202+ allocaBytes (len * 2) $ \buf -> do
203+ unsafeCopyToPtr t buf
204+ action (castPtr buf) (fromIntegral len)
205+ where len = js_length jst
206+#else
144207useAsPtr t@(Text _arr _off len) action =
145208 allocaBytes (len * 2) $ \buf -> do
146209 unsafeCopyToPtr t buf
147210 action (castPtr buf) (fromIntegral len)
211+#endif
148212
149213-- | /O(n)/ Make a mutable copy of a 'Text'.
150214asForeignPtr :: Text -> IO (ForeignPtr Word16, I16)
215+#ifdef __GHCJS__
216+asForeignPtr t@(Text jst) = do
217+ fp <- mallocForeignPtrArray len
218+ withForeignPtr fp $ unsafeCopyToPtr t
219+ return (fp, I16 len)
220+ where len = js_length jst
221+#else
151222asForeignPtr t@(Text _arr _off len) = do
152223 fp <- mallocForeignPtrArray len
153224 withForeignPtr fp $ unsafeCopyToPtr t
154225 return (fp, I16 len)
226+#endif
155227
156228-- | /O(n)/ Decode a C string with explicit length, which is assumed
157229-- to have been encoded as UTF-8. If decoding fails, a
@@ -174,3 +246,17 @@ peekCStringLen cs = do
174246-- @since 1.0.0.0
175247withCStringLen :: Text -> (CStringLen -> IO a) -> IO a
176248withCStringLen t act = unsafeUseAsCStringLen (encodeUtf8 t) act
249+
250+#ifdef __GHCJS__
251+foreign import javascript unsafe
252+ "h$textToString($1,$2,$3)"
253+ js_toString :: ByteArray# -> Int# -> Int# -> JSString
254+foreign import javascript unsafe
255+ "$3.substr($1,$2)" js_substr :: Int# -> Int# -> JSString -> JSString
256+foreign import javascript unsafe
257+ "$2.substr($1)" js_substr1 :: Int# -> JSString -> JSString
258+foreign import javascript unsafe
259+ "$1.length" js_length :: JSString -> Int
260+foreign import javascript unsafe
261+ "$2.charCodeAt($1)" js_charCodeAt :: Int -> JSString -> Int#
262+#endif