Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commitcc6a92f

Browse files
committed
full set of list codecs
1 parentd9e1e2c commitcc6a92f

File tree

2 files changed

+243
-23
lines changed

2 files changed

+243
-23
lines changed

‎src/embed_tests/Codecs.cs

Lines changed: 62 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,7 @@ public void ListCodecTest()
100100
//maybe there can be a flag on listcodec to allow it.
101101
Assert.IsFalse(codec.CanDecode(x,typeof(List<int>)));
102102

103-
Action<System.Collections.IEnumerable>checkPlainEnumerable=(System.Collections.IEnumerableenumerable)=>
103+
Action<System.Collections.IEnumerable>checkUsingEnumerable=(System.Collections.IEnumerableenumerable)=>
104104
{
105105
Assert.IsNotNull(enumerable);
106106
IList<object>list=null;
@@ -111,14 +111,69 @@ public void ListCodecTest()
111111
Assert.AreEqual(list[2],3);
112112
};
113113

114+
Action<System.Collections.IEnumerable>checkEmptyUsingEnumerable=(System.Collections.IEnumerableenumerable)=>
115+
{
116+
Assert.IsNotNull(enumerable);
117+
IList<object>list=null;
118+
list=enumerable.Cast<object>().ToList();
119+
Assert.AreEqual(list.Count,0);
120+
};
121+
114122
//ensure a PyList can be converted to a plain IEnumerable
115123
System.Collections.IEnumerableplainEnumerable1=null;
116124
Assert.DoesNotThrow(()=>{codec.TryDecode<System.Collections.IEnumerable>(x,outplainEnumerable1);});
117-
checkPlainEnumerable(plainEnumerable1);
125+
checkUsingEnumerable(plainEnumerable1);
126+
127+
//can convert to any generic ienumerable. If the type is not assignable from the python element
128+
//it will be an exception during TryDecode
129+
Assert.IsTrue(codec.CanDecode(x,typeof(IEnumerable<int>)));
130+
Assert.IsTrue(codec.CanDecode(x,typeof(IEnumerable<double>)));
131+
Assert.IsTrue(codec.CanDecode(x,typeof(IEnumerable<string>)));
132+
133+
//cannot convert to ICollection or IList of any type since the python type is only iterable
134+
Assert.IsTrue(codec.CanDecode(x,typeof(ICollection<string>)));
135+
Assert.IsTrue(codec.CanDecode(x,typeof(ICollection<int>)));
136+
Assert.IsTrue(codec.CanDecode(x,typeof(IList<int>)));
137+
138+
IEnumerable<int>intEnumerable=null;
139+
Assert.DoesNotThrow(()=>{codec.TryDecode<IEnumerable<int>>(x,outintEnumerable);});
140+
checkUsingEnumerable(intEnumerable);
141+
142+
Runtime.CheckExceptionOccurred();
143+
144+
IEnumerable<double>doubleEnumerable=null;
145+
Assert.DoesNotThrow(()=>{codec.TryDecode<IEnumerable<double>>(x,outdoubleEnumerable);});
146+
checkUsingEnumerable(doubleEnumerable);
147+
148+
Runtime.CheckExceptionOccurred();
149+
150+
IEnumerable<string>stringEnumerable=null;
151+
Assert.DoesNotThrow(()=>{codec.TryDecode<IEnumerable<string>>(x,outstringEnumerable);});
152+
checkEmptyUsingEnumerable(stringEnumerable);
153+
154+
Runtime.CheckExceptionOccurred();
155+
156+
ICollection<string>stringCollection=null;
157+
Assert.DoesNotThrow(()=>{codec.TryDecode<ICollection<string>>(x,outstringCollection);});
158+
checkEmptyUsingEnumerable(stringCollection);
159+
160+
Runtime.CheckExceptionOccurred();
161+
162+
ICollection<int>intCollection=null;
163+
Assert.DoesNotThrow(()=>{codec.TryDecode<ICollection<int>>(x,outintCollection);});
164+
checkUsingEnumerable(intCollection);
165+
166+
Runtime.CheckExceptionOccurred();
167+
168+
IList<int>intList=null;
169+
Assert.DoesNotThrow(()=>{codec.TryDecode<IList<int>>(x,outintList);});
170+
checkUsingEnumerable(intList);
118171

119172
//ensure a python class which implements the iterator protocol can be converter to a plain IEnumerable
120-
varlocals=newPyDict();
121-
PythonEngine.Exec(@"
173+
varlocals=newPyDict();
174+
using(Py.GIL())
175+
{
176+
PythonEngine.Exec(@"
122177
class foo():
123178
def __init__(self):
124179
self.counter = 0
@@ -131,11 +186,12 @@ raise StopIteration
131186
return self.counter
132187
foo_instance = foo()
133188
",null,locals.Handle);
189+
}
134190

135191
varfoo=locals.GetItem("foo_instance");
136192
System.Collections.IEnumerableplainEnumerable2=null;
137193
Assert.DoesNotThrow(()=>{codec.TryDecode<System.Collections.IEnumerable>(x,outplainEnumerable2);});
138-
checkPlainEnumerable(plainEnumerable2);
194+
checkUsingEnumerable(plainEnumerable2);
139195

140196
//can convert to any generic ienumerable. If the type is not assignable from the python element
141197
//it will be an exception during TryDecode
@@ -148,9 +204,8 @@ raise StopIteration
148204
Assert.IsFalse(codec.CanDecode(foo,typeof(ICollection<int>)));
149205
Assert.IsFalse(codec.CanDecode(foo,typeof(IList<int>)));
150206

151-
IEnumerable<int>intEnumerable=null;
152207
Assert.DoesNotThrow(()=>{codec.TryDecode<IEnumerable<int>>(x,outintEnumerable);});
153-
checkPlainEnumerable(intEnumerable);
208+
checkUsingEnumerable(intEnumerable);
154209
}
155210
}
156211
}

‎src/runtime/Codecs/ListCodec.cs

Lines changed: 181 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,8 @@ private Tuple<CollectionRank, Type> GetRankAndType(Type collectionType)
7575

7676
publicboolCanDecode(PyObjectobjectType,TypetargetType)
7777
{
78+
//TODO - convert pyTuple to IReadOnlyList
79+
7880
//get the python object rank
7981
varpyRank=GetRank(objectType);
8082
if(pyRank==CollectionRank.None)
@@ -92,12 +94,14 @@ public bool CanDecode(PyObject objectType, Type targetType)
9294
return(int)pyRank>=(int)clrRank;
9395
}
9496

95-
privateclassGenericPyEnumerable<T>:IEnumerable<T>
97+
privateclassPyEnumerable<T>:IEnumerable<T>
9698
{
9799
protectedPyObjectiterObject;
100+
protectedPyObjectpyObject;
98101

99-
internalGenericPyEnumerable(PyObjectpyObj)
102+
publicPyEnumerable(PyObjectpyObj)
100103
{
104+
pyObject=pyObj;
101105
iterObject=newPyObject(Runtime.PyObject_GetIter(pyObj.Handle));
102106
}
103107

@@ -109,6 +113,7 @@ IEnumerator IEnumerable.GetEnumerator()
109113
objectobj=null;
110114
if(!Converter.ToManaged(item,typeof(object),outobj,true))
111115
{
116+
Exceptions.Clear();
112117
Runtime.XDecref(item);
113118
break;
114119
}
@@ -126,6 +131,7 @@ public IEnumerator<T> GetEnumerator()
126131
objectobj=null;
127132
if(!Converter.ToManaged(item,typeof(T),outobj,true))
128133
{
134+
Exceptions.Clear();
129135
Runtime.XDecref(item);
130136
break;
131137
}
@@ -136,35 +142,194 @@ public IEnumerator<T> GetEnumerator()
136142
}
137143
}
138144

139-
privateobjectToPlainEnumerable(PyObjectpyObj)
145+
privateclassPyCollection<T>:PyEnumerable<T>,ICollection<T>
140146
{
141-
returnnewGenericPyEnumerable<object>(pyObj);
147+
publicPyCollection(PyObjectpyObj):base(pyObj)
148+
{
149+
150+
}
151+
152+
publicintCount
153+
{
154+
get
155+
{
156+
return(int)Runtime.PySequence_Size(pyObject.Handle);
157+
}
158+
}
159+
160+
publicvirtualboolIsReadOnly=>false;
161+
162+
publicvirtualvoidAdd(Titem)
163+
{
164+
//not implemented for Python sequence rank
165+
thrownewNotImplementedException();
166+
}
167+
168+
publicvoidClear()
169+
{
170+
if(IsReadOnly)
171+
thrownewNotImplementedException();
172+
varresult=Runtime.PySequence_DelSlice(pyObject.Handle,0,Count);
173+
if(result==-1)
174+
thrownewException("failed to clear sequence");
175+
}
176+
177+
publicboolContains(Titem)
178+
{
179+
//not sure if IEquatable is implemented and this will work!
180+
foreach(varelementinthis)
181+
if(element.Equals(item))returntrue;
182+
183+
returnfalse;
184+
}
185+
186+
protectedTgetItem(intindex)
187+
{
188+
IntPtritem=Runtime.PySequence_GetItem(pyObject.Handle,index);
189+
objectobj;
190+
191+
if(!Converter.ToManaged(item,typeof(T),outobj,true))
192+
{
193+
Exceptions.Clear();
194+
Runtime.XDecref(item);
195+
Exceptions.RaiseTypeError("wrong type in sequence");
196+
}
197+
198+
return(T)obj;
199+
}
200+
201+
publicvoidCopyTo(T[]array,intarrayIndex)
202+
{
203+
for(intindex=0;index<Count;index++)
204+
{
205+
array[index+arrayIndex]=getItem(index);
206+
}
207+
}
208+
209+
protectedboolremoveAt(intindex)
210+
{
211+
if(IsReadOnly)
212+
thrownewNotImplementedException();
213+
if(index>=Count||index<0)
214+
thrownewIndexOutOfRangeException();
215+
216+
returnRuntime.PySequence_DelItem(pyObject.Handle,index)!=0;
217+
}
218+
219+
protectedintindexOf(Titem)
220+
{
221+
varindex=0;
222+
foreach(varelementinthis)
223+
{
224+
if(element.Equals(item))returnindex;
225+
index++;
226+
}
227+
228+
return-1;
229+
}
230+
231+
publicboolRemove(Titem)
232+
{
233+
returnremoveAt(indexOf(item));
234+
}
142235
}
143-
privateobjectToEnumerable<T>(PyObjectpyObj)
236+
237+
privateclassPyList<T>:PyCollection<T>,IList<T>
144238
{
145-
returnnewGenericPyEnumerable<T>(pyObj);
239+
publicPyList(PyObjectpyObj):base(pyObj)
240+
{
241+
242+
}
243+
244+
publicTthis[intindex]
245+
{
246+
get
247+
{
248+
IntPtritem=Runtime.PySequence_GetItem(pyObject.Handle,index);
249+
objectobj;
250+
251+
if(!Converter.ToManaged(item,typeof(T),outobj,true))
252+
{
253+
Exceptions.Clear();
254+
Runtime.XDecref(item);
255+
Exceptions.RaiseTypeError("wrong type in sequence");
256+
}
257+
258+
return(T)obj;
259+
}
260+
set
261+
{
262+
IntPtrpyItem=Converter.ToPython(value,typeof(T));
263+
if(pyItem==IntPtr.Zero)
264+
thrownewException("failed to set item");
265+
266+
varresult=Runtime.PySequence_SetItem(pyObject.Handle,index,pyItem);
267+
Runtime.XDecref(pyItem);
268+
if(result==-1)
269+
thrownewException("failed to set item");
270+
}
271+
}
272+
273+
publicintIndexOf(Titem)
274+
{
275+
returnindexOf(item);
276+
}
277+
278+
publicvoidInsert(intindex,Titem)
279+
{
280+
if(IsReadOnly)
281+
thrownewNotImplementedException();
282+
283+
IntPtrpyItem=Converter.ToPython(item,typeof(T));
284+
if(pyItem==IntPtr.Zero)
285+
thrownewException("failed to insert item");
286+
287+
varresult=Runtime.PyList_Insert(pyObject.Handle,index,pyItem);
288+
Runtime.XDecref(pyItem);
289+
if(result==-1)
290+
thrownewException("failed to insert item");
291+
}
292+
293+
publicvoidRemoveAt(intindex)
294+
{
295+
removeAt(index);
296+
}
146297
}
147298

148299
publicboolTryDecode<T>(PyObjectpyObj,outTvalue)
149300
{
150-
objectvar=null;
151301
//first see if T is a plan IEnumerable
152302
if(typeof(T)==typeof(System.Collections.IEnumerable))
153303
{
154-
var=newGenericPyEnumerable<object>(pyObj);
304+
objectenumerable=newPyEnumerable<object>(pyObj);
305+
value=(T)enumerable;
306+
returntrue;
155307
}
156308

157309
//next use the rank to return the appropriate type
158-
varclrRank=GetRank(typeof(T));
159-
if(clrRank==CollectionRank.Iterable)
160-
var=newGenericPyEnumerable<int>(pyObj);
161-
else
310+
varrankAndType=GetRankAndType(typeof(T));
311+
if(rankAndType.Item1==CollectionRank.None)
312+
thrownewException("expected collection rank");
313+
314+
315+
varitemType=rankAndType.Item2;
316+
TypecollectionType=null;
317+
if(rankAndType.Item1==CollectionRank.Iterable)
162318
{
163-
//var =null;
319+
collectionType=typeof(PyEnumerable<>).MakeGenericType(itemType);
164320
}
165-
166-
value=(T)var;
167-
returnfalse;
321+
elseif(rankAndType.Item1==CollectionRank.Sequence)
322+
{
323+
collectionType=typeof(PyCollection<>).MakeGenericType(itemType);
324+
}
325+
elseif(rankAndType.Item1==CollectionRank.List)
326+
{
327+
collectionType=typeof(PyList<>).MakeGenericType(itemType);
328+
}
329+
330+
varinstance=Activator.CreateInstance(collectionType,new[]{pyObj});
331+
value=(T)instance;
332+
returntrue;
168333
}
169334

170335
publicstaticListCodecInstance{get;}=newListCodec();

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp