1- {-# LANGUAGE CPP #-}
21{-# LANGUAGE ForeignFunctionInterface #-}
32{-# LANGUAGE MagicHash #-}
43{-# LANGUAGE QuasiQuotes #-}
54{-# LANGUAGE TemplateHaskell #-}
5+ {-# LANGUAGE UnliftedFFITypes #-}
66-- |
77-- Conversion between haskell data types and python values
88module Python.Inline.Literal
@@ -34,18 +34,22 @@ import Data.Text.Lazy qualified as TL
3434import Data.Vector.Generic qualified as VG
3535import Data.Vector.Generic.Mutable qualified as MVG
3636import Data.Vector qualified as V
37- #if MIN_VERSION_vector(0,13,2)
3837import Data.Vector.Strict qualified as VV
39- #endif
4038import Data.Vector.Storable qualified as VS
4139import Data.Vector.Primitive qualified as VP
4240import Data.Vector.Unboxed qualified as VU
41+ import Data.Primitive.ByteArray qualified as BA
42+ import Data.Primitive.Types (Prim (.. ))
43+ import Numeric.Natural (Natural )
4344import Foreign.Ptr
4445import Foreign.C.Types
4546import Foreign.Storable
4647import Foreign.Marshal.Alloc (alloca ,mallocBytes )
4748import Foreign.Marshal.Utils (copyBytes )
4849import GHC.Float (float2Double , double2Float )
50+ import GHC.Exts (Int (.. ),Word (.. ),sizeofByteArray #,ByteArray #)
51+ import GHC.Num.Natural qualified
52+ import GHC.Num.Integer qualified
4953import Data.Complex (Complex ((:+) ))
5054
5155import Language.C.Inline qualified as C
@@ -290,6 +294,121 @@ instance FromPy Word32 where
290294 | otherwise -> throwM OutOfRange
291295
292296
297+
298+ -- NOTE: [Integer encoding/decoding]
299+ -- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
300+ --
301+ -- Interfacing between arbitrary precision integers in haskell and
302+ -- python is pain: they have different representations. And python got
303+ -- API for working with large numbers only in 3.13. We have to use
304+ -- internal API for earlier versions.
305+ --
306+ -- Only large number are discussed below. Small are straightforward
307+ -- enough.
308+ --
309+ -- + GHC's Integer use sign + little endian sequence of Word#. Since
310+ -- all supported platforms are LE it's same as little endian
311+ -- sequence of bytes.
312+ --
313+ -- + Important invariant: highest word must be nonzero!
314+ --
315+ -- + Python uses two-complement.
316+ --
317+ -- One problem is computation of required buffer size. (8byte word is
318+ -- assumed). For example 2^63 requires 9 bytes in two-complement
319+ -- encoding since we need one bit for sign. But 8 bytes enough for
320+ -- Integer's encoding. Sign is stored separately.
321+
322+
323+ -- | @since 0.2.1.0
324+ instance ToPy Integer where
325+ basicToPy (GHC.Num.Integer. IS i) = basicToPy (I # i)
326+ basicToPy (GHC.Num.Integer. IP p) = Py $ do
327+ let n = fromIntegral (I # (sizeofByteArray# p)) :: CSize
328+ inline_py_Integer_ToPy p n 0
329+ basicToPy (GHC.Num.Integer. IN p) = Py $ do
330+ let n = fromIntegral (I # (sizeofByteArray# p)) :: CSize
331+ inline_py_Integer_ToPy p n 1
332+
333+ -- | @since 0.2.1.0
334+ instance ToPy Natural where
335+ basicToPy (GHC.Num.Natural. NS i) = basicToPy (W # i)
336+ basicToPy (GHC.Num.Natural. NB p) = Py $ do
337+ let n = fromIntegral (I # (sizeofByteArray# p)) :: CSize
338+ inline_py_Integer_ToPy p n 0
339+
340+ -- | @since 0.2.1.0
341+ instance FromPy Integer where
342+ basicFromPy p = runProgram $ do
343+ progIO [CU. exp | int { PyLong_Check($(PyObject *p)) } |] >>= \ case
344+ 0 -> progIO $ throwM BadPyType
345+ _ -> pure ()
346+ -- At this point we know that p is number
347+ p_overflow <- withPyAlloca
348+ n <- progIO [CU. exp | long long { PyLong_AsLongLongAndOverflow($(PyObject* p), $(int* p_overflow)) } |]
349+ progIO (peek p_overflow) >>= \ case
350+ -- Number fits into long long
351+ 0 -> return $! fromIntegral n
352+ -- Number is positive
353+ 1 -> do
354+ BA. ByteArray ba <- progIO $ decodePositiveInteger p
355+ pure $ GHC.Num.Integer. IP ba
356+ -- Number is negative
357+ - 1 -> do
358+ neg <- takeOwnership
359+ <=< progPy
360+ $ throwOnNULL =<< Py [CU. exp | PyObject* { PyNumber_Negative( $(PyObject *p) ) } |]
361+ BA. ByteArray ba <- progIO $ decodePositiveInteger neg
362+ pure $ GHC.Num.Integer. IN ba
363+ -- Unreachable
364+ _ -> error " inline-py: FromPy Integer: INTERNAL ERROR"
365+ where
366+
367+ -- | @since 0.2.1.0
368+ instance FromPy Natural where
369+ basicFromPy p = runProgram $ do
370+ progIO [CU. exp | int { PyLong_Check($(PyObject *p)) } |] >>= \ case
371+ 0 -> progIO $ throwM BadPyType
372+ _ -> pure ()
373+ p_overflow <- withPyAlloca
374+ n <- progIO [CU. exp | long long { PyLong_AsLongLongAndOverflow($(PyObject* p), $(int* p_overflow)) } |]
375+ progIO (peek p_overflow) >>= \ case
376+ -- Number fits into long long
377+ 0 | n < 0 -> progIO $ throwM OutOfRange
378+ | otherwise -> return $! fromIntegral n
379+ -- Number is negative
380+ - 1 -> progIO $ throwM OutOfRange
381+ -- Number is positive.
382+ --
383+ -- NOTE that if size of bytearray is equal to size of word we
384+ -- need to return small constructor
385+ 1 -> progIO $ decodePositiveInteger p >>= \ case
386+ BA. ByteArray ba
387+ | I # (sizeofByteArray# ba) == (finiteBitSize (0 :: Word ) `div` 8 )
388+ -> pure $! case indexByteArray# ba 0 # of
389+ W # w -> GHC.Num.Natural. NS w
390+ | otherwise
391+ -> pure $! GHC.Num.Natural. NB ba
392+ -- Unreachable
393+ _ -> error " inline-py: FromPy Natural: INTERNAL ERROR"
394+
395+ -- Decode large positive number:
396+ -- + Must be instance of PyLong
397+ -- + Must be positive
398+ decodePositiveInteger :: Ptr PyObject -> IO BA. ByteArray
399+ decodePositiveInteger p_num = do
400+ sz <- [CU. exp | int { inline_py_Long_ByteSize( $(PyObject *p_num) ) } |]
401+ buf@ (BA. MutableByteArray ptr_buf) <- BA. newByteArray (fromIntegral sz)
402+ _ <- inline_py_Integer_FromPy p_num ptr_buf (fromIntegral sz)
403+ BA. unsafeFreezeByteArray buf
404+
405+
406+
407+ foreign import ccall unsafe " inline_py_Integer_ToPy"
408+ inline_py_Integer_ToPy :: ByteArray # -> CSize -> CInt -> IO (Ptr PyObject )
409+ foreign import ccall unsafe " inline_py_Integer_FromPy"
410+ inline_py_Integer_FromPy :: Ptr PyObject -> BA. MutableByteArray# MVG. RealWorld -> CSize -> IO CInt
411+
293412-- | Encoded as 1-character string
294413instance ToPy Char where
295414 basicToPy c = do
@@ -308,8 +427,7 @@ instance FromPy Char where
308427 r <- Py [CU. block | int {
309428 PyObject* p = $(PyObject *p);
310429 if( !PyUnicode_Check(p) )
311- return -1;
312- if( 1 != PyUnicode_GET_LENGTH(p) )
430+ return -1; if( 1 != PyUnicode_GET_LENGTH(p) )
313431 return -1;
314432 switch( PyUnicode_KIND(p) ) {
315433 case PyUnicode_1BYTE_KIND:
@@ -515,11 +633,9 @@ instance (ToPy a, VP.Prim a) => ToPy (VP.Vector a) where
515633-- | Converts to python's list
516634instance (ToPy a , VU. Unbox a ) => ToPy (VU. Vector a ) where
517635 basicToPy = vectorToPy
518- #if MIN_VERSION_vector(0,13,2)
519636-- | Converts to python's list
520637instance (ToPy a ) => ToPy (VV. Vector a ) where
521638 basicToPy = vectorToPy
522- #endif
523639
524640-- | Accepts python's sequence (@len@ and indexing)
525641instance FromPy a => FromPy (V. Vector a ) where
@@ -533,11 +649,9 @@ instance (FromPy a, VP.Prim a) => FromPy (VP.Vector a) where
533649-- | Accepts python's sequence (@len@ and indexing)
534650instance (FromPy a , VU. Unbox a ) => FromPy (VU. Vector a ) where
535651 basicFromPy = vectorFromPy
536- #if MIN_VERSION_vector(0,13,2)
537652-- | Accepts python's sequence (@len@ and indexing)
538653instance FromPy a => FromPy (VV. Vector a ) where
539654 basicFromPy = vectorFromPy
540- #endif
541655
542656
543657-- | Fold over python's iterator. Function takes ownership over iterator.
0 commit comments