1- #region -- License Terms --
1+ #region -- License Terms --
22//
33// MessagePack for CLI
44//
5- // Copyright (C) 2010-2016 FUJIWARA, Yusuke
5+ // Copyright (C) 2010-2017 FUJIWARA, Yusuke
66//
77// Licensed under the Apache License, Version 2.0 (the "License");
88// you may not use this file except in compliance with the License.
@@ -41,29 +41,30 @@ private void BuildTupleSerializer( TContext context, IList<PolymorphismSchema> i
4141 {
4242 var itemTypes = TupleItems . GetTupleItemTypes ( this . TargetType ) ;
4343 targetInfo = SerializationTarget . CreateForTuple ( itemTypes ) ;
44+ var isValueTuple = this . TargetType . GetIsValueType ( ) ;
4445
45- this . BuildTuplePackTo ( context , itemTypes , itemSchemaList , false ) ;
46+ this . BuildTuplePackTo ( context , itemTypes , itemSchemaList , isValueTuple , false ) ;
4647
4748#if FEATURE_TAP
4849 if ( this . WithAsync ( context ) )
4950 {
50- this . BuildTuplePackTo ( context , itemTypes , itemSchemaList , true ) ;
51+ this . BuildTuplePackTo ( context , itemTypes , itemSchemaList , isValueTuple , true ) ;
5152 }
5253#endif // FEATURE_TAP
5354
54- this . BuildTupleUnpackFrom ( context , itemTypes , itemSchemaList , false ) ;
55+ this . BuildTupleUnpackFrom ( context , itemTypes , itemSchemaList , isValueTuple , false ) ;
5556
5657#if FEATURE_TAP
5758 if ( this . WithAsync ( context ) )
5859 {
59- this . BuildTupleUnpackFrom ( context , itemTypes , itemSchemaList , true ) ;
60+ this . BuildTupleUnpackFrom ( context , itemTypes , itemSchemaList , isValueTuple , true ) ;
6061 }
6162#endif // FEATURE_TAP
6263 }
6364
6465 #region -- PackTo --
6566
66- private void BuildTuplePackTo ( TContext context , IList < Type > itemTypes , IList < PolymorphismSchema > itemSchemaList , bool isAsync )
67+ private void BuildTuplePackTo ( TContext context , IList < Type > itemTypes , IList < PolymorphismSchema > itemSchemaList , bool isValueTuple , bool isAsync )
6768 {
6869 /*
6970 packer.PackArrayHeader( cardinarity );
@@ -84,46 +85,54 @@ private void BuildTuplePackTo( TContext context, IList<Type> itemTypes, IList<Po
8485 this . EmitSequentialStatements (
8586 context ,
8687 TypeDefinition . VoidType ,
87- this . BuildTuplePackToCore ( context , itemTypes , itemSchemaList , isAsync )
88+ this . BuildTuplePackToCore ( context , itemTypes , itemSchemaList , isValueTuple , isAsync )
8889 )
8990 ) ;
9091 }
9192
92- private IEnumerable < TConstruct > BuildTuplePackToCore ( TContext context , IList < Type > itemTypes , IList < PolymorphismSchema > itemSchemaList , bool isAsync )
93+ private IEnumerable < TConstruct > BuildTuplePackToCore ( TContext context , IList < Type > itemTypes , IList < PolymorphismSchema > itemSchemaList , bool isValueTuple , bool isAsync )
94+ {
95+ return
96+ isValueTuple
97+ ? BuildTuplePackToCore ( context , itemTypes , itemSchemaList , ( t , n ) => t . GetField ( n ) , ( c , s , m ) => this . EmitGetFieldExpression ( c , s , m ) , isAsync )
98+ : BuildTuplePackToCore ( context , itemTypes , itemSchemaList , ( t , n ) => t . GetProperty ( n ) , ( c , s , m ) => this . EmitGetPropertyExpression ( c , s , m ) , isAsync ) ;
99+ }
100+
101+ private IEnumerable < TConstruct > BuildTuplePackToCore < TInfo > ( TContext context , IList < Type > itemTypes , IList < PolymorphismSchema > itemSchemaList , Func < Type , string , TInfo > memberFactory , Func < TContext , TConstruct , TInfo , TConstruct > chainConstructFactory , bool isAsync )
93102 {
94103 // Note: cardinality is put as array length by PackHelper.
95104 var depth = - 1 ;
96- var tupleTypeList = TupleItems . CreateTupleTypeList ( itemTypes ) ;
97- var propertyInvocationChain = new List < PropertyInfo > ( itemTypes . Count % 7 + 1 ) ;
105+ var tupleTypeList = TupleItems . CreateTupleTypeList ( this . TargetType ) ;
106+ var memberInvocationChain = new List < TInfo > ( itemTypes . Count % 7 + 1 ) ;
98107 var packValueArguments =
99108 new [ ] { context . Packer , context . PackToTarget }
100109#if FEATURE_TAP
101110 . Concat ( isAsync ? new [ ] { this . ReferCancellationToken ( context , 3 ) } : NoConstructs ) . ToArray ( )
102111#endif // FEATURE_TAP
103112 ;
104113
105- for ( int i = 0 ; i < itemTypes . Count ; i ++ )
114+ for ( var i = 0 ; i < itemTypes . Count ; i ++ )
106115 {
107116 if ( i % 7 == 0 )
108117 {
109118 depth ++ ;
110119 }
111120
112- for ( int j = 0 ; j < depth ; j ++ )
121+ for ( var j = 0 ; j < depth ; j ++ )
113122 {
114123 // .TRest.TRest ...
115- var restProperty = tupleTypeList [ j ] . GetProperty ( "Rest" ) ;
124+ var restMember = memberFactory ( tupleTypeList [ j ] , "Rest" ) ;
116125#if DEBUG
117- Contract . Assert ( restProperty != null ) ;
126+ Contract . Assert ( restMember != null , tupleTypeList [ j ] . GetFullName ( ) + ".Rest is not defined" ) ;
118127#endif
119- propertyInvocationChain . Add ( restProperty ) ;
128+ memberInvocationChain . Add ( restMember ) ;
120129 }
121130
122- var itemNProperty = tupleTypeList [ depth ] . GetProperty ( "Item" + ( ( i % 7 ) + 1 ) ) ;
123- propertyInvocationChain . Add ( itemNProperty ) ;
131+ var itemNMember = memberFactory ( tupleTypeList [ depth ] , "Item" + ( ( i % 7 ) + 1 ) ) ;
132+ memberInvocationChain . Add ( itemNMember ) ;
124133#if DEBUG
125134 Contract . Assert (
126- itemNProperty != null ,
135+ itemNMember != null ,
127136 tupleTypeList [ depth ] . GetFullName ( ) + "::Item" + ( ( i % 7 ) + 1 ) + " [ " + depth + " ] @ " + i
128137 ) ;
129138#endif
@@ -144,15 +153,16 @@ tupleTypeList[ depth ].GetFullName() + "::Item" + ( ( i % 7 ) + 1 ) + " [ " + de
144153 itemTypes [ count ] ,
145154 context . Packer ,
146155 context . PackToTarget ,
147- propertyInvocationChain ,
156+ memberInvocationChain ,
148157 itemSchemaList . Count == 0 ? null : itemSchemaList [ count ] ,
158+ chainConstructFactory ,
149159 isAsync
150160 )
151161 ) ,
152162 packValueArguments
153163 ) ;
154164
155- propertyInvocationChain . Clear ( ) ;
165+ memberInvocationChain . Clear ( ) ;
156166 }
157167
158168 var packHelperArguments =
@@ -215,13 +225,14 @@ tupleTypeList[ depth ].GetFullName() + "::Item" + ( ( i % 7 ) + 1 ) + " [ " + de
215225 yield return methodInvocation ;
216226 }
217227
218- private IEnumerable < TConstruct > EmitPackTupleItemStatements (
228+ private IEnumerable < TConstruct > EmitPackTupleItemStatements < TInfo > (
219229 TContext context ,
220230 Type itemType ,
221231 TConstruct currentPacker ,
222232 TConstruct tuple ,
223- IEnumerable < PropertyInfo > propertyInvocationChain ,
233+ IEnumerable < TInfo > memberInvocationChain ,
224234 PolymorphismSchema itemsSchema ,
235+ Func < TContext , TConstruct , TInfo , TConstruct > chainConstructFactory ,
225236 bool isAsync
226237 )
227238 {
@@ -232,8 +243,8 @@ bool isAsync
232243 itemType ,
233244 NilImplication . Null ,
234245 null ,
235- propertyInvocationChain . Aggregate (
236- tuple , ( propertySource , property ) => this . EmitGetPropertyExpression ( context , propertySource , property )
246+ memberInvocationChain . Aggregate (
247+ tuple , ( memberSource , member ) => chainConstructFactory ( context , memberSource , member )
237248 ) ,
238249 null ,
239250 itemsSchema ,
@@ -245,7 +256,7 @@ bool isAsync
245256
246257 #region -- UnpackFrom --
247258
248- private void BuildTupleUnpackFrom ( TContext context , IList < Type > itemTypes , IList < PolymorphismSchema > itemSchemaList , bool isAsync )
259+ private void BuildTupleUnpackFrom ( TContext context , IList < Type > itemTypes , IList < PolymorphismSchema > itemSchemaList , bool isValueTuple , bool isAsync )
249260 {
250261 /*
251262 * checked
@@ -283,14 +294,22 @@ private void BuildTupleUnpackFrom( TContext context, IList<Type> itemTypes, ILis
283294 this . EmitSequentialStatements (
284295 context ,
285296 this . TargetType ,
286- this . BuildTupleUnpackFromCore ( context , itemTypes , itemSchemaList , isAsync )
297+ this . BuildTupleUnpackFromCore ( context , itemTypes , itemSchemaList , isValueTuple , isAsync )
287298 )
288299 ) ;
289300 }
290301
291- private IEnumerable < TConstruct > BuildTupleUnpackFromCore ( TContext context , IList < Type > itemTypes , IList < PolymorphismSchema > itemSchemaList , bool isAsync )
302+ private IEnumerable < TConstruct > BuildTupleUnpackFromCore ( TContext context , IList < Type > itemTypes , IList < PolymorphismSchema > itemSchemaList , bool isValueTuple , bool isAsync )
303+ {
304+ return
305+ isValueTuple
306+ ? BuildTupleUnpackFromCore ( context , itemTypes , itemSchemaList , ( t , n ) => t . GetField ( n ) , isAsync )
307+ : BuildTupleUnpackFromCore ( context , itemTypes , itemSchemaList , ( t , n ) => t . GetProperty ( n ) , isAsync ) ;
308+ }
309+
310+ private IEnumerable < TConstruct > BuildTupleUnpackFromCore < TInfo > ( TContext context , IList < Type > itemTypes , IList < PolymorphismSchema > itemSchemaList , Func < Type , string , TInfo > memberFactory , bool isAsync )
292311 {
293- var tupleTypeList = TupleItems . CreateTupleTypeList ( itemTypes ) ;
312+ var tupleTypeList = TupleItems . CreateTupleTypeList ( this . TargetType ) ;
294313 yield return
295314 this . EmitCheckIsArrayHeaderExpression ( context , context . Unpacker ) ;
296315
@@ -316,14 +335,14 @@ private IEnumerable<TConstruct> BuildTupleUnpackFromCore( TContext context, ILis
316335 ;
317336 for ( var i = 0 ; i < itemTypes . Count ; i ++ )
318337 {
319- var propertyName = SerializationTarget . GetTupleItemNameFromIndex ( i ) ;
338+ var memberName = SerializationTarget . GetTupleItemNameFromIndex ( i ) ;
320339 var unpackedItem = context . DefineUnpackedItemParameterInSetValueMethods ( itemTypes [ i ] ) ;
321- var setUnpackValueOfMethodName = MethodNamePrefix . SetUnpackedValueOf + propertyName ;
340+ var setUnpackValueOfMethodName = MethodNamePrefix . SetUnpackedValueOf + memberName ;
322341
323342 var index = i ;
324343 this . ExtractPrivateMethod (
325344 context ,
326- AdjustName ( MethodNamePrefix . UnpackValue + propertyName , isAsync ) ,
345+ AdjustName ( MethodNamePrefix . UnpackValue + memberName , isAsync ) ,
327346 false , // isStatic
328347#if FEATURE_TAP
329348 isAsync ? TypeDefinition . TaskType :
@@ -332,7 +351,7 @@ private IEnumerable<TConstruct> BuildTupleUnpackFromCore( TContext context, ILis
332351 ( ) => this . EmitUnpackItemValueStatement (
333352 context ,
334353 itemTypes [ index ] ,
335- this . MakeStringLiteral ( context , propertyName ) ,
354+ this . MakeStringLiteral ( context , memberName ) ,
336355 context . TupleItemNilImplication ,
337356 null , // memberInfo
338357 itemSchemaList . Count == 0 ? null : itemSchemaList [ index ] ,
@@ -355,7 +374,7 @@ private IEnumerable<TConstruct> BuildTupleUnpackFromCore( TContext context, ILis
355374 context ,
356375 context . UnpackingContextInSetValueMethods ,
357376 unpackingContext . VariableType ,
358- propertyName ,
377+ memberName ,
359378 unpackedItem
360379 ) ,
361380 context . UnpackingContextInSetValueMethods ,
@@ -368,15 +387,15 @@ private IEnumerable<TConstruct> BuildTupleUnpackFromCore( TContext context, ILis
368387 }
369388
370389 TConstruct currentTuple = null ;
371- for ( int nest = tupleTypeList . Count - 1 ; nest >= 0 ; nest -- )
390+ for ( var nest = tupleTypeList . Count - 1 ; nest >= 0 ; nest -- )
372391 {
373392 var gets =
374393 Enumerable . Range ( nest * 7 , Math . Min ( itemTypes . Count - nest * 7 , 7 ) )
375394 . Select ( i =>
376395 this . EmitGetFieldExpression (
377396 context ,
378397 context . UnpackingContextInCreateObjectFromContext ,
379- new FieldDefinition (
398+ new FieldDefinition (
380399 unpackingContext . VariableType ,
381400 SerializationTarget . GetTupleItemNameFromIndex ( i ) ,
382401 itemTypes [ i ]
@@ -388,13 +407,33 @@ itemTypes[ i ]
388407 gets = gets . Concat ( new [ ] { currentTuple } ) ;
389408 }
390409
391- currentTuple =
392- this . EmitCreateNewObjectExpression (
393- context ,
394- null , // Tuple is reference contextType.
395- tupleTypeList [ nest ] . GetConstructors ( ) . Single ( ) ,
396- gets . ToArray ( )
397- ) ;
410+ var constructor = tupleTypeList [ nest ] . GetConstructors ( ) . SingleOrDefault ( ) ;
411+ if ( constructor == null )
412+ {
413+ // arity 0 value tuple
414+ #if DEBUG
415+ Contract . Assert ( tupleTypeList [ nest ] . GetFullName ( ) == "System.ValueTuple" , tupleTypeList [ nest ] . GetFullName ( ) + " == System.ValueTuple" ) ;
416+ #endif
417+ currentTuple = this . MakeDefaultLiteral ( context , tupleTypeList [ nest ] ) ;
418+ }
419+ else
420+ {
421+ var tempVariable = default ( TConstruct ) ;
422+
423+ if ( tupleTypeList [ nest ] . GetIsValueType ( ) )
424+ {
425+ // Temp var is required for value type (that is, ValueTuple)
426+ tempVariable = this . DeclareLocal ( context , tupleTypeList [ nest ] , context . GetUniqueVariableName ( "tuple" ) ) ;
427+ }
428+
429+ currentTuple =
430+ this . EmitCreateNewObjectExpression (
431+ context ,
432+ tempVariable , // Tuple is reference contextType.
433+ constructor ,
434+ gets . ToArray ( )
435+ ) ;
436+ }
398437 }
399438
400439#if DEBUG
0 commit comments