public string GetWrite(string sourceName, string sourceCode, ITypeSymbol sourceType, IValueSerializationGeneratorContext context)
        {
            if (_serializer.IsResolvable(sourceType))
            {
                var value = VariableHelper.GetName(sourceType);

                string result;
                if (sourceName.IsNullOrWhiteSpace())
                {
                    // We are writing an item of a collection or something like that.
                    // We cannot ignore null values, instead we must write the "null" keyword.

                    result =
                        $@"var {value} = {sourceCode};
if ({value} == null)
{{
	{context.Write.Writer}.WriteNullValue();
}}
else
{{
	{_serializer.GetResolve(sourceType)}.Serialize({context.Write.Writer}, {value});
}}";
                }
                else
                {
                    result =
                        $@"var {value} = {sourceCode};
if ({value} != null)
{{
	{context.Write.Object}.WritePropertyName(""{sourceName}"");
	{_serializer.GetResolve(sourceType)}.Serialize({context.Write.Writer}, {value});
}}";
                }

                return(result);
            }

            return(null);
        }
        public string ReadCollection(string target, ITypeSymbol collectionType, ITypeSymbol itemType, IValueSerializationGeneratorContext context)
        {
            var itemTypeName = itemType.GetDeclarationGenericFullName();

            var implementation = _collectionResolver.FindImplementation(collectionType);

            var collection     = VariableHelper.GetName(implementation.Implementation);
            var item           = VariableHelper.GetName(itemType);
            var collectionKind = VariableHelper.GetName("collectionType");

            return($@"
					var {collectionKind} = {context.Read.Reader}.OpenCollection({context.Read.FirstChar}, out {context.Read.OverChar});
					if({collectionKind} == JsonReaderExtension.CollectionType.SingleValue)
					{{
						{implementation.CreateInstance(collection)}
						var {item} = default({itemTypeName});

						{context.UsingOverAsFirstChar(overHasValue: true).GetRead(item, itemType)}
						{implementation.AddItemToInstance(collection, item)}
						
						{implementation.InstanceToContract(collection, target)}
					}}
					else if({collectionKind} == JsonReaderExtension.CollectionType.Collection)
					{{
						// If collection type is Collection, then the overChar returned by OpenCollection is null.

						{implementation.CreateInstance(collection)}
						var {item} = default({itemTypeName});

						while ({context.Read.Reader}.MoveToNextCollectionItem(ref {context.Read.OverChar}))
						{{
							{context.UsingOverAsFirstChar().GetRead(item, itemType)}
							{implementation.AddItemToInstance(collection, item)}
						}}

						{implementation.InstanceToContract(collection, target)}
					}}"                    );
        }
        public string ReadDictionary(string target, ITypeSymbol dictionaryType, ITypeSymbol itemType, IValueSerializationGeneratorContext context)
        {
            var implementation = _collectionResolver.FindImplementation(dictionaryType);

            var dictionary = VariableHelper.GetName(implementation.Implementation);
            var key        = VariableHelper.GetName <string>();

            // Note: the {context.Read.OverChar} is always null after the MoveToNextProperty so we don't need to propagate it as FirstChar
            //		 This means that we don't need to specify the .UsingOverAsFirstChar() on the context for context.GetRead($"{dictionary}[{key}]", itemType).

            return($@"
					if ({context.Read.Reader}.OpenObject({context.Read.FirstChar}, out {context.Read.OverChar}))
					{{
						{implementation.CreateInstance(dictionary)}
						var {key} = default(string);

						while ({context.Read.Reader}.MoveToNextProperty(ref {context.Read.OverChar}, ref {key}, toUpper: false))
						{{
							{context.IgnoringCurrentFirstChar().GetRead($"{dictionary}[{key}]", itemType)}
						}}

						{implementation.InstanceToContract(dictionary, target)}
					}}"                    );
        }
        public string GetWrite(string sourceName, string sourceCode, ITypeSymbol sourceType, IValueSerializationGeneratorContext context)
        {
            string mappedType;

            if (sourceName.HasValueTrimmed())
            {
                // We are writing a property value, if the source is null, we can just ignore the whole property.

                if (_stringType.Equals(sourceType.GetDeclarationGenericFullName(), StringComparison.OrdinalIgnoreCase))
                {
                    var value = VariableHelper.GetName(sourceType);
                    return($@"
						var {value} = {sourceCode};
						if ({value} != null)
						{{
							{context.Write.Object}.WritePropertyName(""{sourceName}"");
							{context.Write.Writer}.WriteStringValue({value});
						}}"                        );
                }
                else if (_supportedTypes.TryGetValue(sourceType.GetDeclarationGenericFullName(), out mappedType))
                {
                    return($@"
						{context.Write.Object}.WritePropertyName(""{sourceName}"");
						{context.Write.Writer}.Write(({mappedType}){sourceCode});"                        );
                }
                else if (sourceType.IsNullable(out sourceType) && _supportedTypes.TryGetValue(sourceType.GetDeclarationGenericFullName(), out mappedType))
                {
                    var value = VariableHelper.GetName(sourceType);
                    return($@"
						var {value} = {sourceCode};
						if ({value}.HasValue)
						{{
							{context.Write.Object}.WritePropertyName(""{sourceName}"");
							{context.Write.Writer}.Write(({mappedType}){value}.Value);
						}}"                        );
                }
            }
            else
            {
                // We are writing an item of a collection or something like that.
                // We cannot ignore null values, instead we must write the "null" keyword.

                if (_stringType.Equals(sourceType.GetDeclarationGenericFullName(), StringComparison.OrdinalIgnoreCase))
                {
                    // WriteStringValue handles the "null" itself.
                    return($@"{context.Write.Writer}.WriteStringValue({sourceCode});");
                }
                else if (_supportedTypes.TryGetValue(sourceType.GetDeclarationGenericFullName(), out mappedType))
                {
                    return($@"{context.Write.Writer}.Write(({mappedType}){sourceCode});");
                }
                else if (sourceType.IsNullable(out sourceType) && _supportedTypes.TryGetValue(sourceType.GetDeclarationGenericFullName(), out mappedType))
                {
                    var value = VariableHelper.GetName(sourceType);
                    return($@"
						var {value} = {sourceCode};
						if ({value}.HasValue)
						{{
							{context.Write.Writer}.Write(({mappedType}){value}.Value);
						}}
						else
						{{
							{context.Write.Writer}.WriteNullValue();
						}}"                        );
                }
            }

            return(null);
        }