private MakeNullHandler ( [ varValue, [ getPropertyExpr, NullPolicy policy, [ nonNullExpr, [ defaultValExpr, [ exceptionMessage ) : |
||
varValue | [ | |
getPropertyExpr | [ | |
policy | NullPolicy | |
nonNullExpr | [ | |
defaultValExpr | [ | |
exceptionMessage | [ | |
return |
// Generates an expression that creates an NbtTag for given property of a directly-mappable types. // Directly-mappable types are: primitives, enums, byte[], int[], and string. // HandlePrimitiveOrEnum is actually more efficient (and preferred by NbtCompiler) for primitives and enums, // because it skips boxing and NullPolicy checks. This one is pretty much only used for byte[]/int[]/string. public override Expression HandleDirectlyMappedType(string tagName, PropertyInfo property, NullPolicy selfPolicy) { // declare a local var, which will hold the property's value ParameterExpression varValue = Expression.Parameter(property.PropertyType); // Fallback path, in case value is null and NullPolicy is InsertDefaults Expression defaultVal = Expression.Constant(SerializationUtil.GetDefaultValue(property.PropertyType)); // varRootTag.Add( new NbtTag(tagName, <defaultVal>) ); Expression defaultValExpr = Expression.Call(varRootTag, NbtCompoundAddMethod, MakeNbtTagCtor(property.PropertyType, Expression.Constant(tagName, typeof(string)), defaultVal)); // varRootTag.Add( new NbtTag(tagName, <varValue>) ); Expression makeTagExpr = Expression.Call(varRootTag, NbtCompoundAddMethod, MakeNbtTagCtor(property.PropertyType, Expression.Constant(tagName, typeof(string)), varValue)); // Getter for the property value Expression getPropertyExpr = Expression.MakeMemberAccess(argValue, property); // generate the appropriate enclosing expressions, depending on NullPolicy return(NbtCompiler.MakeNullHandler(varValue, getPropertyExpr, selfPolicy, makeTagExpr, defaultValExpr, MakePropertyNullMessage(property))); }
Expression MakeNbtTagHandler([NotNull] Type tagType, [NotNull] Type valueType, [NotNull] Expression tagNameExpr, [NotNull] Expression getPropertyExpr, NullPolicy selfPolicy, [NotNull] String nullMsg, [NotNull] Func <ParameterExpression, Expression> conversionFunc, [NotNull] Func <Expression, Expression> processTagExpr) { // declare a local var, which will hold the property's value ParameterExpression varValue = Expression.Parameter(valueType, "value"); // Primary path, adds the root tag of the NbtFile Expression makeTagExpr = processTagExpr(conversionFunc(varValue)); // Fallback path, in case value is null and NullPolicy is InsertDefaults ConstructorInfo tagCtor; if (tagType == typeof(NbtTag)) { tagCtor = NbtCompoundCtor; } else { tagCtor = tagType.GetConstructor(new[] { typeof(string) }); } Expression defaultVal = Expression.New(tagCtor, tagNameExpr); Expression defaultValExpr = processTagExpr(defaultVal); // Generate the appropriate enclosing expressions, which choose path depending on NullPolicy return(NbtCompiler.MakeNullHandler(varValue, getPropertyExpr, selfPolicy, makeTagExpr, defaultValExpr, nullMsg)); }
public override Expression HandleINbtSerializable(string tagName, PropertyInfo property, NullPolicy selfPolicy) { MethodInfo serializeMethod = property.PropertyType.GetMethod("Serialize", new[] { typeof(string) }); ParameterExpression varValue = Expression.Parameter(property.PropertyType, "value"); string nullMsg = MakePropertyNullMessage(property); // rootTag.Add( value.Serialize() ) Expression serializeExpr = Expression.Call( varRootTag, NbtCompoundAddMethod, Expression.Call(varValue, serializeMethod, Expression.Constant(tagName))); // Fallback path, in case value is null and NullPolicy is InsertDefaults Expression defaultExpr = Expression.New(NbtCompoundCtor, Expression.Constant(tagName)); // Getter for the property value Expression propValue = Expression.MakeMemberAccess(argValue, property); return(NbtCompiler.MakeNullHandler(varValue, propValue, selfPolicy, serializeExpr, defaultExpr, nullMsg)); }
Expression MakeElementHandler([NotNull] Type elementType, [NotNull] Expression tagNameExpr, [NotNull] Expression tagValueExpr, NullPolicy elementPolicy, [NotNull] string nullElementMsg, [NotNull] Func <Expression, Expression> addTagExprFunc) { if (tagValueExpr.Type != elementType) { // In case value getter's return type is different from value return type (e.g. Array.GetValue(int)) tagValueExpr = Expression.Convert(tagValueExpr, elementType); } if (elementType.IsPrimitive || elementType.IsEnum) { //=== Serializing primitives and enums === // tag.Add( new NbtTag(kvp.Key, kvp.Value) ); return(addTagExprFunc(MakeNbtTagCtor(elementType, tagNameExpr, tagValueExpr))); } else if (SerializationUtil.IsDirectlyMappedType(elementType)) { //=== Serializing directly-mapped reference types (byte[], int[], string) === // declare a local var, which will hold the property's value ParameterExpression varElementValue = Expression.Parameter(elementType, "elementValue"); // Primary path, in case element value is not null: // iDictTag.Add(new NbtTag(kvp.Key, <getValueExpr>)); Expression addElementExpr = addTagExprFunc(MakeNbtTagCtor(elementType, tagNameExpr, tagValueExpr)); // Fallback path, in case element value is null and elementPolicy is InsertDefaults: // Add a default-value tag to the list: listTag.Add(new NbtTag(null, <default>)) Expression defaultValExpr = Expression.Constant(SerializationUtil.GetDefaultValue(elementType)); Expression defaultElementExpr = addTagExprFunc(MakeNbtTagCtor(elementType, tagNameExpr, defaultValExpr)); // generate the appropriate enclosing expressions, depending on NullPolicy return(NbtCompiler.MakeNullHandler(varElementValue, tagValueExpr, elementPolicy, addElementExpr, defaultElementExpr, nullElementMsg)); } else { //=== Serializing everything else === // Check if this is an IList-of-ILists Type iListImpl = SerializationUtil.GetGenericInterfaceImpl(elementType, typeof(IList <>)); Type iDictImpl = SerializationUtil.GetStringIDictionaryImpl(elementType); // check if this type can handle its own serialization if (typeof(INbtSerializable).IsAssignableFrom(elementType)) { // element is INbtSerializable MethodInfo serializeMethod = elementType.GetMethod("Serialize", new[] { typeof(string) }); Expression newTagExpr = Expression.Call(tagValueExpr, serializeMethod, tagNameExpr); return(addTagExprFunc(newTagExpr)); } else if (typeof(NbtTag).IsAssignableFrom(elementType)) { // element is NbtTag return(MakeNbtTagHandler( elementType, elementType, tagNameExpr, tagValueExpr, elementPolicy, nullElementMsg, expr => expr, addTagExprFunc)); } else if (typeof(NbtFile).IsAssignableFrom(elementType)) { // element is NbtFile return(MakeNbtTagHandler( typeof(NbtCompound), typeof(NbtFile), tagNameExpr, tagValueExpr, elementPolicy, nullElementMsg, expr => Expression.MakeMemberAccess(expr, NbtFileRootTagProperty), addTagExprFunc)); } else if (iListImpl != null) { // element is IList<?> Type subElementType = iListImpl.GetGenericArguments()[0]; return(MakeIListHandler(tagValueExpr, subElementType, tagNameExpr, elementPolicy, elementPolicy, nullElementMsg, nullElementMsg, addTagExprFunc)); } else if (iDictImpl != null) { // element is IDictionary<string,?> return(MakeStringIDictionaryHandler(tagNameExpr, tagValueExpr, iDictImpl, elementPolicy, elementPolicy, nullElementMsg, nullElementMsg, addTagExprFunc)); } else { // Get NbtSerialize<T> method for elementType Expression makeElementTagExpr = callResolver.MakeCall(elementType, tagNameExpr, tagValueExpr); // declare a local var, which will hold the element's value ParameterExpression varElementValue = Expression.Parameter(elementType, "elementValue"); // Primary path, adds the newly-made Compound tag to our list Expression addSerializedCompoundExpr = addTagExprFunc(makeElementTagExpr); // Fallback path, in case element's value is null and NullPolicy is InsertDefaults Expression addEmptyCompoundExpr = addTagExprFunc(Expression.New(NbtCompoundCtor, tagNameExpr)); // Generate the appropriate enclosing expressions, which choose path depending on NullPolicy return(NbtCompiler.MakeNullHandler(varElementValue, tagValueExpr, elementPolicy, addSerializedCompoundExpr, addEmptyCompoundExpr, nullElementMsg)); } } }
Expression MakeStringIDictionaryHandler([NotNull] Expression tagNameExpr, [NotNull] Expression getIDictExpr, [NotNull] Type iDictImpl, NullPolicy selfPolicy, NullPolicy elementPolicy, [NotNull] string selfNullMsg, [NotNull] string elementNullMsg, [NotNull] Func <Expression, Expression> processTagExpr) { Type elementType = iDictImpl.GetGenericArguments()[1]; // find type of KeyValuePair<string,?> that the enumerator will return Type kvpType = typeof(KeyValuePair <,>).MakeGenericType(iDictImpl.GetGenericArguments()); PropertyInfo keyProp = kvpType.GetProperty("Key"); PropertyInfo valueProp = kvpType.GetProperty("Value"); // locate IDictionary.GetEnumerator() Type enumerableType = typeof(IEnumerable <>).MakeGenericType(kvpType); Type enumeratorType = typeof(IEnumerator <>).MakeGenericType(kvpType); MethodInfo getEnumeratorImpl = SerializationUtil.GetGenericInterfaceMethodImpl( iDictImpl, enumerableType, "GetEnumerator", Type.EmptyTypes); // locate IEnumerator.MoveNext() MethodInfo moveNextMethod = typeof(IEnumerator).GetMethod("MoveNext"); MethodInfo disposeMethod = typeof(IDisposable).GetMethod("Dispose"); PropertyInfo currentProp = enumeratorType.GetProperty("Current"); ParameterExpression varIDict = Expression.Parameter(iDictImpl, "iDict"); ParameterExpression varCompTag = Expression.Parameter(typeof(NbtCompound), "compTag"); ParameterExpression varEnumerator = Expression.Parameter(enumeratorType, "enumerator"); ParameterExpression varKvp = Expression.Parameter(kvpType, "element"); // generate handlers for individual elements Expression getNameExpr = Expression.MakeMemberAccess(varKvp, keyProp); Expression getValueExpr = Expression.MakeMemberAccess(varKvp, valueProp); Expression handleOneElementExpr = MakeElementHandler( elementType, getNameExpr, getValueExpr, elementPolicy, elementNullMsg, tag => Expression.Call(varCompTag, NbtCompoundAddMethod, tag)); // Make glue code to hold everything together LabelTarget loopBreak = Expression.Label(typeof(void)); Expression loopBody = Expression.Block( new[] { varKvp }, Expression.Assign(varKvp, Expression.MakeMemberAccess(varEnumerator, currentProp)), handleOneElementExpr); Expression makeIDictTagExpr = Expression.Block( new[] { varCompTag, varEnumerator }, // varCompTag = new NbtCompound(tagName) Expression.Assign(varCompTag, Expression.New(NbtCompoundCtor, tagNameExpr)), // varEnumerator = iDict.GetEnumerator() Expression.Assign(varEnumerator, Expression.Call(varIDict, getEnumeratorImpl)), // try { Expression.MakeTry( typeof(void), // while (enumerator.MoveNext()) <loopBody>; Expression.Loop( Expression.IfThenElse(Expression.Call(varEnumerator, moveNextMethod), loopBody, Expression.Break(loopBreak)), loopBreak), // } finally { enumerator.Dispose(); } Expression.Call(varEnumerator, disposeMethod), null, null), processTagExpr(varCompTag)); // default value (in case selfPolicy is InsertDefault): new NbtCompound(tagName) Expression defaultValExpr = Expression.New(NbtCompoundCtor, tagNameExpr); return(NbtCompiler.MakeNullHandler(varIDict, getIDictExpr, selfPolicy, makeIDictTagExpr, defaultValExpr, selfNullMsg)); }
Expression MakeIListHandler([NotNull] Expression getIListExpr, [NotNull] Type elementType, [NotNull] Expression tagNameExpr, NullPolicy selfPolicy, NullPolicy elementPolicy, [NotNull] string selfNullMsg, [NotNull] string elementNullMsg, [NotNull] Func <Expression, Expression> processTagExpr) { Type listType = getIListExpr.Type; // Declare locals ParameterExpression varIList = Expression.Parameter(listType, "iList"); ParameterExpression varListTag = Expression.Parameter(typeof(NbtList), "listTag"); ParameterExpression varLength = Expression.Parameter(typeof(int), "length"); ParameterExpression varIndex = Expression.Parameter(typeof(int), "i"); // Find getters for this IList MethodInfo countGetterImpl, itemGetterImpl; if (listType.IsArray) { // Although Array claims to implement IList<>, there is no way to retrieve // the interface implementation: it's handled in an unusual way by the runtime. // So we have to resort to getting Length/GetValue instead of Count/Item countGetterImpl = listType.GetProperty("Length").GetGetMethod(); itemGetterImpl = listType.GetMethod("GetValue", new[] { typeof(int) }); } else { // For non-array IList<> types, grab this.Count getter (which maps to get_Count()) countGetterImpl = SerializationUtil.GetGenericInterfaceMethodImpl( listType, typeof(ICollection <>), "get_Count", Type.EmptyTypes); // ...and the getter for indexer this[int], which maps to get_Item(int) itemGetterImpl = SerializationUtil.GetGenericInterfaceMethodImpl( listType, typeof(IList <>), "get_Item", new[] { typeof(int) }); } // Create handler for a single element Expression getElementExpr = Expression.Call(varIList, itemGetterImpl, varIndex); Expression getCountExpr = Expression.Call(varIList, countGetterImpl); Expression handleOneElementExpr = MakeElementHandler( elementType, NbtCompiler.NullStringExpr, getElementExpr, elementPolicy, elementNullMsg, tag => Expression.Call(varListTag, NbtListAddMethod, tag)); // Arrange tag construction in a loop LabelTarget loopBreak = Expression.Label(typeof(void)); Expression mainLoop = // while (true) Expression.Loop( Expression.Block( // if (i >= length) break; Expression.IfThen( Expression.GreaterThanOrEqual(varIndex, varLength), Expression.Break(loopBreak)), // <process and add one element to the list> handleOneElementExpr, // ++i; Expression.PreIncrementAssign(varIndex)), loopBreak); // new NbtList(tagName, NbtTagType.*) ConstructorInfo listTagCtor = typeof(NbtList).GetConstructor(new[] { typeof(string), typeof(NbtTagType) }); Expression makeListTagExpr = Expression.New(listTagCtor, tagNameExpr, Expression.Constant(GetNbtTagType(elementType))); // Fallback path, in case value our IList null and NullPolicy is InsertDefaults: // Add an empty list to root. Expression defaultValExpr = processTagExpr(makeListTagExpr); // Primary path, in case our IList is not null: // Package the list-building loop into a neat block, with locals Expression makeTagExpr = Expression.Block( new[] { varListTag, varIndex, varLength }, // NbtList listTag = new NbtList(tagName, NbtTagType.*); Expression.Assign(varListTag, makeListTagExpr), // int length = iList.Count; Expression.Assign(varLength, getCountExpr), // int i=0; Expression.Assign(varIndex, Expression.Constant(0)), // (fill the list tag) mainLoop, // rootTag.Add( listTag ); processTagExpr(varListTag)); // Generate the appropriate enclosing expressions, which choose path depending on NullPolicy return(NbtCompiler.MakeNullHandler(varIList, getIListExpr, selfPolicy, makeTagExpr, defaultValExpr, selfNullMsg)); }