// Copyright Epic Games, Inc. All Rights Reserved.
using System;
using System.Collections.Generic;
using System.Linq;
namespace EpicGames.Serialization.Converters
{
///
/// Converter for dictionary types
///
class CbDictionaryConverter : CbConverter> where TKey : notnull
{
///
public override Dictionary Read(CbField field)
{
if (field.IsNull())
{
return null!;
}
Dictionary dictionary = [];
foreach (CbField element in field)
{
IEnumerator enumerator = element.AsArray().GetEnumerator();
if (!enumerator.MoveNext())
{
throw new CbException("Missing key for dictionary entry");
}
TKey key = CbSerializer.Deserialize(enumerator.Current);
if (!enumerator.MoveNext())
{
throw new CbException("Missing value for dictionary entry");
}
TValue value = CbSerializer.Deserialize(enumerator.Current);
dictionary.Add(key, value);
}
return dictionary;
}
///
public override void Write(CbWriter writer, Dictionary value)
{
if (value == null)
{
writer.WriteNullValue();
}
else
{
writer.BeginUniformArray(CbFieldType.Array);
foreach (KeyValuePair pair in value)
{
writer.BeginArray();
CbSerializer.Serialize(writer, pair.Key);
CbSerializer.Serialize(writer, pair.Value);
writer.EndArray();
}
writer.EndUniformArray();
}
}
///
public override void WriteNamed(CbWriter writer, CbFieldName name, Dictionary value)
{
if (value == null)
{
writer.WriteNull(name);
}
else if (value.Count > 0)
{
writer.BeginUniformArray(name, CbFieldType.Array);
foreach (KeyValuePair pair in value)
{
writer.BeginArray();
CbSerializer.Serialize(writer, pair.Key);
CbSerializer.Serialize(writer, pair.Value);
writer.EndArray();
}
writer.EndUniformArray();
}
}
}
///
/// Factory for CbDictionaryConverter
///
class CbDictionaryConverterFactory : CbConverterFactory
{
///
public override CbConverter? CreateConverter(Type type)
{
if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Dictionary<,>))
{
Type? keyType = type.GetGenericArguments().FirstOrDefault();
if (keyType == typeof(string))
{
// if the key type is a string serialize as a CbObject to more closely follow typical conventions
Type converterType = typeof(CbStringDictionaryConverter<>).MakeGenericType(type.GenericTypeArguments[1..]);
return (CbConverter)Activator.CreateInstance(converterType)!;
}
else
{
Type converterType = typeof(CbDictionaryConverter<,>).MakeGenericType(type.GenericTypeArguments);
return (CbConverter)Activator.CreateInstance(converterType)!;
}
}
return null;
}
}
///
/// Converter for dictionary types with string keys, serialized as objects
///
class CbStringDictionaryConverter : CbConverter>
{
///
public override Dictionary Read(CbField field)
{
if (field.IsNull())
{
return null!;
}
Dictionary dictionary = [];
foreach (CbField element in field)
{
string key = element.Name.ToString();
TValue value = CbSerializer.Deserialize(element);
dictionary.Add(key, value);
}
return dictionary;
}
///
public override void Write(CbWriter writer, Dictionary value)
{
if (value == null)
{
writer.WriteNullValue();
}
else
{
writer.BeginObject();
foreach (KeyValuePair pair in value)
{
CbSerializer.Serialize(writer, pair.Key, pair.Value);
}
writer.EndObject();
}
}
///
public override void WriteNamed(CbWriter writer, CbFieldName name, Dictionary value)
{
if (value == null)
{
writer.WriteNull(name);
}
else if (value.Count > 0)
{
writer.BeginObject(name);
foreach (KeyValuePair pair in value)
{
CbSerializer.Serialize(writer, pair.Key, pair.Value);
}
writer.EndObject();
}
}
}
}