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

Commitd0d0ce8

Browse files
committed
added Codecs: EncoderGroup and DecoderGroup
These classes would help to manage codec layers. For example, a library could register its own codecs, but also allow anyone to inject their codecs before library's own:public static EncoderGroup BeforeLibraryEncoders { get; } = new EncoderGroup();void LibraryRegisterCodecs(){ PyObjectConversions.RegisterEncoder(BeforeLibraryEncoders); PyObjectConversions.RegisterEncoder(LibraryEncoder.Instance);}Then in a program using that library:Library.BeforeLibraryEncoders.Encoders.Add(preencoder);
1 parentd145ab1 commitd0d0ce8

File tree

7 files changed

+326
-4
lines changed

7 files changed

+326
-4
lines changed

‎src/embed_tests/CodecGroups.cs

Lines changed: 132 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,132 @@
1+
namespacePython.EmbeddingTest
2+
{
3+
usingSystem;
4+
usingSystem.Linq;
5+
usingNUnit.Framework;
6+
usingPython.Runtime;
7+
usingPython.Runtime.Codecs;
8+
9+
publicclassCodecGroups
10+
{
11+
[Test]
12+
publicvoidGetEncodersByType()
13+
{
14+
varencoder1=newFakeEncoder<Uri>();
15+
varencoder2=newFakeEncoder<Uri>();
16+
vargroup=newEncoderGroup{
17+
newFakeEncoder<Tuple<int>>(),
18+
encoder1,
19+
encoder2,
20+
};
21+
22+
vargot=group.GetEncoders(typeof(Uri)).ToArray();
23+
CollectionAssert.AreEqual(new[]{encoder1,encoder2},got);
24+
}
25+
26+
[Test]
27+
publicvoidCanEncode()
28+
{
29+
vargroup=newEncoderGroup{
30+
newFakeEncoder<Tuple<int>>(),
31+
newFakeEncoder<Uri>(),
32+
};
33+
34+
Assert.IsTrue(group.CanEncode(typeof(Tuple<int>)));
35+
Assert.IsTrue(group.CanEncode(typeof(Uri)));
36+
Assert.IsFalse(group.CanEncode(typeof(string)));
37+
}
38+
39+
[Test]
40+
publicvoidEncodes()
41+
{
42+
varencoder0=newFakeEncoder<Tuple<int>>();
43+
varencoder1=newFakeEncoder<Uri>();
44+
varencoder2=newFakeEncoder<Uri>();
45+
vargroup=newEncoderGroup{
46+
encoder0,
47+
encoder1,
48+
encoder2,
49+
};
50+
51+
varuri=group.TryEncode(newUri("data:"));
52+
varclrObject=(CLRObject)ManagedType.GetManagedObject(uri.Handle);
53+
Assert.AreSame(encoder1,clrObject.inst);
54+
Assert.AreNotSame(encoder2,clrObject.inst);
55+
56+
vartuple=group.TryEncode(Tuple.Create(1));
57+
clrObject=(CLRObject)ManagedType.GetManagedObject(tuple.Handle);
58+
Assert.AreSame(encoder0,clrObject.inst);
59+
}
60+
61+
[Test]
62+
publicvoidGetDecodersByTypes()
63+
{
64+
varpyint=newPyInt(10).GetPythonType();
65+
varpyfloat=newPyFloat(10).GetPythonType();
66+
varpystr=newPyString("world").GetPythonType();
67+
vardecoder1=newFakeDecoder<long>(pyint,42);
68+
vardecoder2=newFakeDecoder<string>(pyfloat,"atad:");
69+
vargroup=newDecoderGroup{
70+
decoder1,
71+
decoder2,
72+
};
73+
74+
vardecoder=group.GetDecoder(pyfloat,typeof(string));
75+
Assert.AreSame(decoder2,decoder);
76+
decoder=group.GetDecoder(pystr,typeof(string));
77+
Assert.IsNull(decoder);
78+
decoder=group.GetDecoder(pyint,typeof(long));
79+
Assert.AreSame(decoder1,decoder);
80+
}
81+
[Test]
82+
publicvoidCanDecode()
83+
{
84+
varpyint=newPyInt(10).GetPythonType();
85+
varpyfloat=newPyFloat(10).GetPythonType();
86+
varpystr=newPyString("world").GetPythonType();
87+
vardecoder1=newFakeDecoder<long>(pyint,42);
88+
vardecoder2=newFakeDecoder<string>(pyfloat,"atad:");
89+
vargroup=newDecoderGroup{
90+
decoder1,
91+
decoder2,
92+
};
93+
94+
Assert.IsTrue(group.CanDecode(pyint,typeof(long)));
95+
Assert.IsFalse(group.CanDecode(pyint,typeof(int)));
96+
Assert.IsTrue(group.CanDecode(pyfloat,typeof(string)));
97+
Assert.IsFalse(group.CanDecode(pystr,typeof(string)));
98+
}
99+
100+
[Test]
101+
publicvoidDecodes()
102+
{
103+
varpyint=newPyInt(10).GetPythonType();
104+
varpyfloat=newPyFloat(10).GetPythonType();
105+
vardecoder1=newFakeDecoder<long>(pyint,42);
106+
vardecoder2=newFakeDecoder<string>(pyfloat,"atad:");
107+
vargroup=newDecoderGroup{
108+
decoder1,
109+
decoder2,
110+
};
111+
112+
Assert.IsTrue(group.TryDecode(newPyInt(10),outlonglongResult));
113+
Assert.AreEqual(42,longResult);
114+
Assert.IsTrue(group.TryDecode(newPyFloat(10),outstringstrResult));
115+
Assert.AreSame("atad:",strResult);
116+
117+
Assert.IsFalse(group.TryDecode(newPyInt(10),outint_));
118+
}
119+
120+
[SetUp]
121+
publicvoidSetUp()
122+
{
123+
PythonEngine.Initialize();
124+
}
125+
126+
[TearDown]
127+
publicvoidDispose()
128+
{
129+
PythonEngine.Shutdown();
130+
}
131+
}
132+
}

‎src/embed_tests/Codecs.cs

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,4 +83,33 @@ static void TupleRoundtripGeneric<T, TTuple>() {
8383
}
8484
}
8585
}
86+
87+
classFakeEncoder<T>:IPyObjectEncoder
88+
{
89+
publicboolCanEncode(Typetype)=>type==typeof(T);
90+
publicPyObjectTryEncode(objectvalue)=>this.GetRawPythonProxy();
91+
}
92+
93+
classFakeDecoder<TTarget>:IPyObjectDecoder
94+
{
95+
publicPyObjectTheOnlySupportedSourceType{get;}
96+
publicTTargetDecodeResult{get;}
97+
98+
publicFakeDecoder(PyObjectobjectType,TTargetdecodeResult)
99+
{
100+
this.TheOnlySupportedSourceType=objectType;
101+
this.DecodeResult=decodeResult;
102+
}
103+
104+
publicboolCanDecode(PyObjectobjectType,TypetargetType)
105+
=>objectType.Handle==TheOnlySupportedSourceType.Handle
106+
&&targetType==typeof(TTarget);
107+
publicboolTryDecode<T>(PyObjectpyObj,outTvalue)
108+
{
109+
if(typeof(T)!=typeof(TTarget))
110+
thrownewArgumentException(nameof(T));
111+
value=(T)(object)DecodeResult;
112+
returntrue;
113+
}
114+
}
86115
}

‎src/embed_tests/Python.EmbeddingTest.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,7 @@
8383
<NoneInclude="packages.config" />
8484
</ItemGroup>
8585
<ItemGroup>
86+
<CompileInclude="CodecGroups.cs" />
8687
<CompileInclude="Codecs.cs" />
8788
<CompileInclude="dynamic.cs" />
8889
<CompileInclude="pyimport.cs" />

‎src/runtime/Codecs/DecoderGroup.cs

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
namespacePython.Runtime.Codecs
2+
{
3+
usingSystem;
4+
usingSystem.Collections;
5+
usingSystem.Collections.Generic;
6+
usingSystem.Linq;
7+
8+
/// <summary>
9+
/// Represents a group of <see cref="IPyObjectDecoder"/>s. Useful to group them by priority.
10+
/// </summary>
11+
[Obsolete(Util.UnstableApiMessage)]
12+
publicsealedclassDecoderGroup:IPyObjectDecoder,IEnumerable<IPyObjectDecoder>
13+
{
14+
readonlyList<IPyObjectDecoder>decoders=newList<IPyObjectDecoder>();
15+
16+
/// <summary>
17+
/// Add specified decoder to the group
18+
/// </summary>
19+
publicvoidAdd(IPyObjectDecoderitem)
20+
{
21+
if(itemisnull)thrownewArgumentNullException(nameof(item));
22+
23+
this.decoders.Add(item);
24+
}
25+
/// <summary>
26+
/// Remove all decoders from the group
27+
/// </summary>
28+
publicvoidClear()=>this.decoders.Clear();
29+
30+
/// <inheritdoc />
31+
publicboolCanDecode(PyObjectobjectType,TypetargetType)
32+
=>this.decoders.Any(decoder=>decoder.CanDecode(objectType,targetType));
33+
/// <inheritdoc />
34+
publicboolTryDecode<T>(PyObjectpyObj,outTvalue)
35+
{
36+
if(pyObjisnull)thrownewArgumentNullException(nameof(pyObj));
37+
38+
vardecoder=this.GetDecoder(pyObj.GetPythonType(),typeof(T));
39+
if(decoderisnull)
40+
{
41+
value=default;
42+
returnfalse;
43+
}
44+
returndecoder.TryDecode(pyObj,outvalue);
45+
}
46+
47+
/// <inheritdoc />
48+
publicIEnumerator<IPyObjectDecoder>GetEnumerator()=>this.decoders.GetEnumerator();
49+
IEnumeratorIEnumerable.GetEnumerator()=>this.decoders.GetEnumerator();
50+
}
51+
52+
[Obsolete(Util.UnstableApiMessage)]
53+
publicstaticclassDecoderGroupExtensions
54+
{
55+
/// <summary>
56+
/// Gets a concrete instance of <see cref="IPyObjectDecoder"/>
57+
/// (potentially selecting one from a collection),
58+
/// that can decode from <paramref name="objectType"/> to <paramref name="targetType"/>,
59+
/// or <c>null</c> if a matching decoder can not be found.
60+
/// </summary>
61+
[Obsolete(Util.UnstableApiMessage)]
62+
publicstaticIPyObjectDecoderGetDecoder(
63+
thisIPyObjectDecoderdecoder,
64+
PyObjectobjectType,TypetargetType)
65+
{
66+
if(decoderisnull)thrownewArgumentNullException(nameof(decoder));
67+
68+
if(decoderisIEnumerable<IPyObjectDecoder>composite)
69+
{
70+
returncomposite
71+
.Select(nestedDecoder=>nestedDecoder.GetDecoder(objectType,targetType))
72+
.FirstOrDefault(d=>d!=null);
73+
}
74+
75+
returndecoder.CanDecode(objectType,targetType)?decoder:null;
76+
}
77+
}
78+
}

‎src/runtime/Codecs/EncoderGroup.cs

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
namespacePython.Runtime.Codecs
2+
{
3+
usingSystem;
4+
usingSystem.Collections;
5+
usingSystem.Collections.Generic;
6+
usingSystem.Linq;
7+
8+
/// <summary>
9+
/// Represents a group of <see cref="IPyObjectDecoder"/>s. Useful to group them by priority.
10+
/// </summary>
11+
[Obsolete(Util.UnstableApiMessage)]
12+
publicsealedclassEncoderGroup:IPyObjectEncoder,IEnumerable<IPyObjectEncoder>
13+
{
14+
readonlyList<IPyObjectEncoder>encoders=newList<IPyObjectEncoder>();
15+
16+
/// <summary>
17+
/// Add specified encoder to the group
18+
/// </summary>
19+
publicvoidAdd(IPyObjectEncoderitem)
20+
{
21+
if(itemisnull)thrownewArgumentNullException(nameof(item));
22+
this.encoders.Add(item);
23+
}
24+
/// <summary>
25+
/// Remove all encoders from the group
26+
/// </summary>
27+
publicvoidClear()=>this.encoders.Clear();
28+
29+
/// <inheritdoc />
30+
publicboolCanEncode(Typetype)=>this.encoders.Any(encoder=>encoder.CanEncode(type));
31+
/// <inheritdoc />
32+
publicPyObjectTryEncode(objectvalue)
33+
{
34+
if(valueisnull)thrownewArgumentNullException(nameof(value));
35+
36+
foreach(varencoderinthis.GetEncoders(value.GetType()))
37+
{
38+
varresult=encoder.TryEncode(value);
39+
if(result!=null)
40+
{
41+
returnresult;
42+
}
43+
}
44+
45+
returnnull;
46+
}
47+
48+
/// <inheritdoc />
49+
publicIEnumerator<IPyObjectEncoder>GetEnumerator()=>this.encoders.GetEnumerator();
50+
IEnumeratorIEnumerable.GetEnumerator()=>this.encoders.GetEnumerator();
51+
}
52+
53+
[Obsolete(Util.UnstableApiMessage)]
54+
publicstaticclassEncoderGroupExtensions
55+
{
56+
/// <summary>
57+
/// Gets specific instances of <see cref="IPyObjectEncoder"/>
58+
/// (potentially selecting one from a collection),
59+
/// that can encode the specified <paramref name="type"/>.
60+
/// </summary>
61+
[Obsolete(Util.UnstableApiMessage)]
62+
publicstaticIEnumerable<IPyObjectEncoder>GetEncoders(thisIPyObjectEncoderdecoder,Typetype)
63+
{
64+
if(decoderisnull)thrownewArgumentNullException(nameof(decoder));
65+
66+
if(decoderisIEnumerable<IPyObjectEncoder>composite)
67+
{
68+
foreach(varnestedEncoderincomposite)
69+
foreach(varmatchinnestedEncoder.GetEncoders(type))
70+
{
71+
yieldreturnmatch;
72+
}
73+
}elseif(decoder.CanEncode(type))
74+
{
75+
yieldreturndecoder;
76+
}
77+
}
78+
}
79+
}

‎src/runtime/Python.Runtime.csproj

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,8 @@
7676
<ReferenceInclude="System" />
7777
</ItemGroup>
7878
<ItemGroup>
79+
<CompileInclude="Codecs\EncoderGroup.cs" />
80+
<CompileInclude="Codecs\DecoderGroup.cs" />
7981
<CompileInclude="Codecs\TupleCodecs.cs" />
8082
<CompileInclude="converterextensions.cs" />
8183
<CompileInclude="finalizer.cs" />

‎src/runtime/converterextensions.cs

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ namespace Python.Runtime
55
usingSystem.Collections.Generic;
66
usingSystem.Linq;
77
usingSystem.Reflection;
8+
usingPython.Runtime.Codecs;
89

910
/// <summary>
1011
/// Defines <see cref="PyObject"/> conversion to CLR types (unmarshalling)
@@ -49,8 +50,8 @@ public interface IPyObjectEncoder
4950
[Obsolete(Util.UnstableApiMessage)]
5051
publicstaticclassPyObjectConversions
5152
{
52-
staticreadonlyList<IPyObjectDecoder>decoders=newList<IPyObjectDecoder>();
53-
staticreadonlyList<IPyObjectEncoder>encoders=newList<IPyObjectEncoder>();
53+
staticreadonlyDecoderGroupdecoders=newDecoderGroup();
54+
staticreadonlyEncoderGroupencoders=newEncoderGroup();
5455

5556
/// <summary>
5657
/// Registers specified encoder (marshaller)
@@ -101,7 +102,7 @@ static IPyObjectEncoder[] GetEncoders(Type type)
101102
{
102103
lock(encoders)
103104
{
104-
returnencoders.Where(encoder=>encoder.CanEncode(type)).ToArray();
105+
returnencoders.GetEncoders(type).ToArray();
105106
}
106107
}
107108
#endregion
@@ -128,7 +129,7 @@ static Converter.TryConvertFromPythonDelegate GetDecoder(IntPtr sourceType, Type
128129
{
129130
lock(decoders)
130131
{
131-
decoder=decoders.Find(d=>d.CanDecode(pyType,targetType));
132+
decoder=decoders.GetDecoder(pyType,targetType);
132133
if(decoder==null)returnnull;
133134
}
134135
}

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp