{-# LANGUAGE BangPatterns, CPP, GeneralizedNewtypeDeriving #-}-- |-- Module : Data.Text.Foreign-- Copyright : (c) 2009, 2010 Bryan O'Sullivan---- License : BSD-style-- Maintainer : bos@serpentine.com, rtomharper@googlemail.com,-- duncan@haskell.org-- Stability : experimental-- Portability : GHC---- Support for using 'Text' data with native code via the Haskell-- foreign function interface.moduleData.Text.Foreign(-- * Interoperability with native code-- $interopI16-- * Safe conversion functions,fromPtr,useAsPtr,asForeignPtr-- * Unsafe conversion code,lengthWord16,unsafeCopyToPtr-- * Low-level manipulation-- $lowlevel,dropWord16,takeWord16)where#ifdefined(ASSERTS)importControl.Exception(assert)#endifimportControl.Monad.ST(unsafeIOToST)importData.Text.Internal(Text(..),empty)importData.Text.Unsafe(lengthWord16)importqualifiedData.Text.ArrayasAimportData.Word(Word16)importForeign.Marshal.Alloc(allocaBytes)importForeign.Ptr(Ptr,castPtr,plusPtr)importForeign.ForeignPtr(ForeignPtr,mallocForeignPtrArray,withForeignPtr)importForeign.Storable(peek,poke)-- $interop---- The 'Text' type is implemented using arrays that are not guaranteed-- to have a fixed address in the Haskell heap. All communication with-- native code must thus occur by copying data back and forth.---- The 'Text' type's internal representation is UTF-16, using the-- platform's native endianness. This makes copied data suitable for-- use with native libraries that use a similar representation, such-- as ICU. To interoperate with native libraries that use different-- internal representations, such as UTF-8 or UTF-32, consider using-- the functions in the 'Data.Text.Encoding' module.-- | A type representing a number of UTF-16 code units.newtypeI16=I16Intderiving(Bounded,Enum,Eq,Integral,Num,Ord,Read,Real,Show)-- | /O(n)/ Create a new 'Text' from a 'Ptr' 'Word16' by copying the-- contents of the array.fromPtr::PtrWord16-- ^ source array->I16-- ^ length of source array (in 'Word16' units)->IOTextfromPtr_(I160)=returnemptyfromPtrptr(I16len)=#ifdefined(ASSERTS)assert(len>0)$#endifreturn$!Textarr0lenwherearr=A.run(A.newlen>>=copy)copymarr=loopptr0whereloop!p!i|i==len=returnmarr|otherwise=doA.unsafeWritemarri=<<unsafeIOToST(peekp)loop(p`plusPtr`2)(i+1)-- $lowlevel---- Foreign functions that use UTF-16 internally may return indices in-- units of 'Word16' instead of characters. These functions may-- safely be used with such indices, as they will adjust offsets if-- necessary to preserve the validity of a Unicode string.-- | /O(1)/ Return the prefix of the 'Text' of @n@ 'Word16' units in-- length.---- If @n@ would cause the 'Text' to end inside a surrogate pair, the-- end of the prefix will be advanced by one additional 'Word16' unit-- to maintain its validity.takeWord16::I16->Text->TexttakeWord16(I16n)t@(Textarrofflen)|n<=0=empty|n>=len||m>=len=t|otherwise=Textarroffmwherem|w<0xDB00||w>0xD8FF=n|otherwise=n+1w=A.unsafeIndexarr(off+n-1)-- | /O(1)/ Return the suffix of the 'Text', with @n@ 'Word16' units-- dropped from its beginning.---- If @n@ would cause the 'Text' to begin inside a surrogate pair, the-- beginning of the suffix will be advanced by one additional 'Word16'-- unit to maintain its validity.dropWord16::I16->Text->TextdropWord16(I16n)t@(Textarrofflen)|n<=0=t|n>=len||m>=len=empty|otherwise=Textarr(off+m)(len-m)wherem|w<0xD800||w>0xDBFF=n|otherwise=n+1w=A.unsafeIndexarr(off+n-1)-- | /O(n)/ Copy a 'Text' to an array. The array is assumed to be big-- enough to hold the contents of the entire 'Text'.unsafeCopyToPtr::Text->PtrWord16->IO()unsafeCopyToPtr(Textarrofflen)ptr=loopptroffwhereend=off+lenloop!p!i|i==end=return()|otherwise=dopokep(A.unsafeIndexarri)loop(p`plusPtr`2)(i+1)-- | /O(n)/ Perform an action on a temporary, mutable copy of a-- 'Text'. The copy is freed as soon as the action returns.useAsPtr::Text->(PtrWord16->I16->IOa)->IOauseAsPtrt@(Text_arr_offlen)action=allocaBytes(len*2)$\buf->dounsafeCopyToPtrtbufaction(castPtrbuf)(fromIntegrallen)-- | /O(n)/ Make a mutable copy of a 'Text'.asForeignPtr::Text->IO(ForeignPtrWord16,I16)asForeignPtrt@(Text_arr_offlen)=dofp<-mallocForeignPtrArraylenwithForeignPtrfp$unsafeCopyToPtrtreturn(fp,I16len)