@@ -0,0 +1,89 @@
1+{-# LANGUAGE BangPatterns #-}
2+-- |
3+-- Module : Data.Text.Foreign
4+-- Copyright : (c) Bryan O'Sullivan 2009
5+--
6+-- License : BSD-style
7+-- Maintainer : rtharper@aftereternity.co.uk, bos@serpentine.com,
8+-- duncan@haskell.org
9+-- Stability : experimental
10+-- Portability : GHC
11+--
12+-- Support for using 'Text' data with native code via the Haskell
13+-- foreign function interface.
14+
15+module Data.Text.Foreign
16+ (
17+ -- * Interoperability with native code
18+ -- $interop
19+
20+ -- * Safe conversion functions
21+ fromPtr
22+ , useAsPtr
23+ -- * Unsafe conversion code
24+ , lengthWord16
25+ , unsafeCopyToPtr
26+ ) where
27+
28+import Control.Exception (assert)
29+import Control.Monad.ST (unsafeIOToST)
30+import Data.Text.Internal (Text(..), empty)
31+import qualified Data.Text.Array as A
32+import Data.Word (Word16)
33+import Foreign.Marshal.Alloc (allocaBytes)
34+import Foreign.Ptr (Ptr, castPtr, plusPtr)
35+import Foreign.Storable (peek, poke)
36+
37+-- $interop
38+--
39+-- The 'Text' type is implemented using arrays that are not guaranteed
40+-- to have a fixed address in the Haskell heap. All communication with
41+-- native code must thus occur by copying data back and forth.
42+--
43+-- The 'Text' type's internal representation is UTF-16, using the
44+-- platform's native endianness. This makes copied data suitable for
45+-- use with native libraries that use a similar representation, such
46+-- as ICU. To interoperate with native libraries that use different
47+-- internal representations, such as UTF-8 or UTF-32, consider using
48+-- the functions in the 'Data.Text.Encoding' module.
49+
50+-- | /O(n)/ Create a new 'Text' from a 'Ptr' 'Word16' by copying the
51+-- contents of the array.
52+fromPtr :: Ptr Word16 -- ^ source array
53+ -> Int -- ^ length of source array (in 'Word16' units)
54+ -> IO Text
55+fromPtr _ 0 = return empty
56+fromPtr ptr len = assert (len > 0) $ return (Text arr 0 len)
57+ where
58+ arr = A.run (A.unsafeNew len >>= copy)
59+ copy marr = loop ptr 0
60+ where
61+ loop !p !i | i == len = return marr
62+ | otherwise = do
63+ A.unsafeWrite marr i =<< unsafeIOToST (peek p)
64+ loop (p `plusPtr` 2) (i + 1)
65+
66+-- | /O(1)/ Return the length of a 'Text' in units of 'Word16'. This
67+-- is useful for sizing a target array appropriately before using
68+-- 'unsafeCopyToPtr'.
69+lengthWord16 :: Text -> Int
70+lengthWord16 (Text _arr _off len) = len
71+
72+-- | /O(n)/ Copy a 'Text' to an array. The array is assumed to be big
73+-- enough to hold the contents of the entire 'Text'.
74+unsafeCopyToPtr :: Text -> Ptr Word16 -> IO ()
75+unsafeCopyToPtr (Text arr off len) ptr = loop ptr off
76+ where
77+ end = off + len
78+ loop !p !i | i == end = return ()
79+ | otherwise = do
80+ poke p (A.unsafeIndex arr i)
81+ loop (p `plusPtr` 2) (i + 1)
82+
83+-- | /O(n)/ Perform an action on a temporary, mutable copy of a
84+-- 'Text'. The copy is freed as soon as the action returns.
85+useAsPtr :: Text -> (Ptr Word16 -> Int -> IO a) -> IO a
86+useAsPtr t@(Text _arr _off len) action =
87+ allocaBytes (len * 2) $ \buf -> do
88+ unsafeCopyToPtr t buf
89+ action (castPtr buf) len