8000 Add the 'Iterator' protocol · packetloop/haskell-cpython@8b1ad2c · GitHub
[go: up one dir, main page]

Skip to content

Commit 8b1ad2c

Browse files
committed
Add the 'Iterator' protocol
1 parent fd2e2ee commit 8b1ad2c

File tree

Original file line numberDiff line numberDiff line change
@@ -56,10 +56,20 @@ module CPython.Internal
5656
, checkIntReturn
5757

5858
-- * Other classes
59+
-- ** Mapping
5960
, Mapping (..)
6061
, SomeMapping (..)
62+
, unsafeCastToMapping
63+
64+
-- ** Sequence
6165
, Sequence (..)
6266
, SomeSequence (..)
67+
, unsafeCastToSequence
68+
69+
-- ** Iterator
70+
, Iterator (..)
71+
, SomeIterator (..)
72+
, unsafeCastToIterator
6373
) where
6474
import Control.Applicative ((<$>))
6575
import qualified Control.Exception as E
@@ -208,7 +218,51 @@ data SomeMapping = forall a. (Mapping a) => SomeMapping (ForeignPtr a)
208218
class Object a => Mapping a where
209219
toMapping :: a -> SomeMapping
210220

221+
instance Object SomeMapping where
222+
toObject (SomeMapping x) = SomeObject x
223+
fromForeignPtr = SomeMapping
224+
225+
instance Mapping SomeMapping where
226+
toMapping = id
227+
228+
unsafeCastToMapping :: Object a => a -> SomeMapping
229+
unsafeCastToMapping x = case toObject x of
230+
SomeObject ptr -> let
231+
ptr' = castForeignPtr ptr :: ForeignPtr SomeMapping
232+
in SomeMapping ptr'
233+
211234
data SomeSequence = forall a. (Sequence a) => SomeSequence (ForeignPtr a)
212235

213236
class Object a => Sequence a where
214237
toSequence :: a -> SomeSequence
238+
239+
instance Object SomeSequence where
240+
toObject (SomeSequence x) = SomeObject x
241+
fromForeignPtr = SomeSequence
242+
243+
instance Sequence SomeSequence where
244+
toSequence = id
245+
246+
unsafeCastToSequence :: Object a => a -> SomeSequence
247+
unsafeCastToSequence x = case toObject x of
248+
SomeObject ptr -> let
249+
ptr' = castForeignPtr ptr :: ForeignPtr SomeSequence
250+
in SomeSequence ptr'
251+
252+
data SomeIterator = forall a. (Iterator a) => SomeIterator (ForeignPtr a)
253+
254+
class Object a => Iterator a where
255+
toIterator :: a -> SomeIterator
256+
257+
instance Object SomeIterator where
258+
toObject (SomeIterator x) = SomeObject x
259+
fromForeignPtr = SomeIterator
260+
261+
instance Iterator SomeIterator where
262+
toIterator = id
263+
264+
unsafeCastToIterator :: Object a => a -> SomeIterator
265+
unsafeCastToIterator x = case toObject x of
266+
SomeObject ptr -> let
267+
ptr' = castForeignPtr ptr :: ForeignPtr SomeIterator
268+
in SomeIterator ptr'
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
-- Copyright (C) 2009 John Millikin <jmillikin@gmail.com>
2+
--
3+
-- This program is free software: you can redistribute it and/or modify
4+
-- it under the terms of the GNU General Public License as published by
5+
-- the Free Software Foundation, either version 3 of the License, or
6+
-- any later version.
7+
--
8+
-- This program is distributed in the hope that it will be useful,
9+
-- but WITHOUT ANY WARRANTY; without even the implied warranty of
10+
-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+
-- GNU General Public License for more details.
12+
--
13+
-- You should have received a copy of the GNU General Public License
14+
-- along with this program. If not, see <http://www.gnu.org/licenses/>.
15+
--
16+
{-# LANGUAGE ForeignFunctionInterface #-}
17+
module CPython.Protocols.Iterator
18+
( Iterator (..)
19+
, SomeIterator
20+
, castToIterator
21+
, next
22+
) where
23+
import CPython.Internal
24+
25+
#include <hscpython-shim.h>
26+
27+
-- | Attempt to convert an object to a generic 'Iterator'. If the object does
28+
-- not implement the iterator protocol, returns 'Nothing'.
29+
--
30+
castToIterator :: Object a => a -> IO (Maybe SomeIterator)
31+
castToIterator obj =
32+
withObject obj $ \objPtr -> do
33+
isIter <- fmap cToBool $ {# call hscpython_PyIter_Check as ^ #} objPtr
34+
return $ if isIter
35+
then Just $ unsafeCastToIterator obj
36+
else Nothing
37+
38+
-- | Return the next value from the iteration, or 'Nothing' if there are no
39+
-- remaining items.
40+
--
41+
next :: Iterator iter => iter -> IO (Maybe SomeObject)
42+
next iter =
43+
withObject iter $ \iterPtr -> do
44+
raw <- {# call PyIter_Next as ^ #} iterPtr
45+
if raw == nullPtr
46+
then do
47+
err <- {# call PyErr_Occurred as ^ #}
48+
exceptionIf $ err /= nullPtr
49+
return Nothing
50+
else fmap Just $ stealObject raw
Original file line numberDiff line numberDiff line change
@@ -31,22 +31,9 @@ import CPython.Internal
3131

3232
#include <hscpython-shim.h>
3333

34-
instance Object SomeMapping where
35-
toObject (SomeMapping x) = SomeObject x
36-
fromForeignPtr = SomeMapping
37-
38-
instance Mapping SomeMapping where
39-
toMapping = id
40-
4134
instance Mapping Dictionary where
4235
toMapping = unsafeCastToMapping
4336

44-
unsafeCastToMapping :: Object a => a -> SomeMapping
45-
unsafeCastToMapping x = case toObject x of
46-
SomeObject ptr -> let
47-
ptr' = castForeignPtr ptr :: ForeignPtr SomeMapping
48-
in SomeMapping ptr'
49-
5037
castToMapping :: Object a => a -> IO (Maybe SomeMapping)
5138
castToMapping obj =
5239
withObject obj $ \objPtr -> do
Original file line numberDiff line numberDiff line change
@@ -45,13 +45,6 @@ import CPython.Types.Unicode (Unicode)
4545

4646
#include <hscpython-shim.h>
4747

48-
instance Object SomeSequence where
49-
toObject (SomeSequence x) = SomeObject x
50-
fromForeignPtr = SomeSequence
51-
52-
instance Sequence SomeSequence where
53-
toSequence = id
54-
5548
instance Sequence ByteArray where
5649
toSequence = unsafeCastToSequence
5750

@@ -67,12 +60,6 @@ instance Sequence Tuple where
6760
instance Sequence Unicode where
6861
toSequence = unsafeCastToSequence
6962

70-
unsafeCastToSequence :: Object a => a -> SomeSequence
71-
unsafeCastToSequence x = case toObject x of
72-
SomeObject ptr -> let
73-
ptr' = castForeignPtr ptr :: ForeignPtr SomeSequence
74-
in SomeSequence ptr'
75-
7663
-- | Attempt to convert an object to a generic 'Sequence'. If the object does
7764
-- not implement the sequence protocol, returns 'Nothing'.
7865
--
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,6 @@ module CPython.Types
3030
, CPython.Types.Integer.Integer
3131
, SequenceIterator
3232
, CallableIterator
33-
, Iterator
3433
, List
3534
, Method
3635
, Module
Original file line numberDiff line numberDiff line change
@@ -15,26 +15,23 @@
1515
--
1616
{-# LANGUAGE ForeignFunctionInterface #-}
1717
module CPython.Types.Iterator
18-
( Iterator
19-
, SequenceIterator
18+
( SequenceIterator
2019
, sequenceIteratorType
2120
, sequenceIteratorNew
2221

2322
, CallableIterator
2423
, callableIteratorType
2524
, callableIteratorNew
26-
27-
, next
2825
) where
2926
import CPython.Internal
3027

3128
#include <hscpython-shim.h>
3229

33-
class Object a => Iterator a
34-
3530
newtype SequenceIterator = SequenceIterator (ForeignPtr SequenceIterator)
3631

37-
instance Iterator SequenceIterator
32+
instance Iterator SequenceIterator where
33+
toIterator = unsafeCastToIterator
34+
3835
instance Object SequenceIterator where
3936
toObject (SequenceIterator x) = SomeObject x
4037
fromForeignPtr = SequenceIterator
@@ -44,7 +41,9 @@ instance Concrete SequenceIterator where
4441

4542
newtype CallableIterator = CallableIterator (ForeignPtr CallableIterator)
4643

47-
instance Iterator CallableIterator
44+
instance Iterator CallableIterator where
45+
toIterator = unsafeCastToIterator
46+
4847
instance Object CallableIterator where
4948
toObject (CallableIterator x) = SomeObject x
5049
fromForeignPtr = CallableIterator
@@ -58,7 +57,7 @@ instance Concrete CallableIterator where
5857
{# fun pure hscpython_PyCallIter_Type as callableIteratorType
5958
{} -> `Type' peekStaticObject* #}
6059

61-
-- | Return an iterator that works with a general sequence object, /seq/.
60+
-- | Return an 'Iterator' that works with a general sequence object, /seq/.
6261
-- The iteration ends when the sequence raises @IndexError@ for the
6362
-- subscripting operation.
6463
--
@@ -67,7 +66,7 @@ instance Concrete CallableIterator where
6766
{ withObject* `seq'
6867
} -> `SequenceIterator' stealObject* #}
6968

70-
-- | Return a new iterator. The first parameter, /callable/, can be any
69+
-- | Return a new 'Iterator'. The first parameter, /callable/, can be any
7170
-- Python callable object that can be called with no parameters; each call
7271
-- to it should return the next item in the iteration. When /callable/
7372
-- returns a value equal to /sentinel/, the iteration will be terminated.
@@ -77,17 +76,3 @@ instance Concrete CallableIterator where
7776
{ withObject* `callable'
7877
, withObject* `sentinel'
7978
} -> `CallableIterator' stealObject* #}
80-
81-
-- | Return the next value from the iteration, or 'Nothing' if there are no
82-
-- remaining items.
83-
--
84-
next :: Iterator iter => iter -> IO (Maybe SomeObject)
85-
next iter =
86-
withObject iter $ \iterPtr -> do
87-
raw <- {# call PyIter_Next as ^ #} iterPtr
88-
if raw == nullPtr
89-
then do
90-
err <- {# call PyErr_Occurred as ^ #}
91-
exceptionIf $ err /= nullPtr
92-
return Nothing
93-
else fmap Just $ stealObject raw
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
name: cpython
2-
version: 3.1.1.0
2+
version: 3.1.2.0
33
synopsis: Bindings for libpython
44
license: GPL-3
55
license-file: license.txt
@@ -64,6 +64,7 @@ library
6464
CPython.Types.Type
6565
CPython.Types.Unicode
6666
CPython.Types.WeakReference
67+
CPython.Protocols.Iterator
6768
CPython.Protocols.Mapping
6869
CPython.Protocols.Number
6970
CPython.Protocols.Object
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,9 @@ int hscpython_PyObject_DelAttr(PyObject *o, PyObject *name)
5959
int hscpython_PyObject_TypeCheck (PyObject *o, PyTypeObject *type)
6060
{ return PyObject_TypeCheck (o, type); }
6161

62+
int hscpython_PyIter_Check(PyObject *o)
63+
{ return PyIter_Check(o); }
64+
6265
/* Types */
6366
PyTypeObject *hscpython_PyType_Type ()
6467
{ return &PyType_Type; }
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ void hscpython_Py_INCREF (PyObject *);
1212
void hscpython_Py_DECREF (PyObject *);
1313
int hscpython_PyObject_DelAttr(PyObject *, PyObject *);
1414
int hscpython_PyObject_TypeCheck (PyObject *, PyTypeObject *);
15+
int hscpython_PyIter_Check(PyObject *);
1516

1617
enum HSCPythonComparisonEnum
1718
{ HSCPYTHON_LT = Py_LT