2021-07-28 12:40:35 -04:00
// Copyright Epic Games, Inc. All Rights Reserved.
using EpicGames.Core ;
using System ;
namespace EpicGames.Serialization
{
2022-03-28 10:11:10 -04:00
/// <summary>
/// Marks a class as supporting serialization to compact-binary, even if it does not have exposed fields. This suppresses errors
/// when base class objects are empty.
/// </summary>
[AttributeUsage(AttributeTargets.Class)]
2022-10-03 17:36:19 -04:00
public sealed class CbObjectAttribute : Attribute
2022-03-28 10:11:10 -04:00
{
}
2021-07-28 12:40:35 -04:00
/// <summary>
/// Attribute used to mark a property that should be serialized to compact binary
/// </summary>
2021-09-04 10:26:56 -04:00
[AttributeUsage(AttributeTargets.Property)]
2022-10-03 17:36:19 -04:00
public sealed class CbFieldAttribute : Attribute
2021-07-28 12:40:35 -04:00
{
/// <summary>
/// Name of the serialized field
/// </summary>
2022-10-03 17:36:19 -04:00
public string? Name { get ; }
2021-07-28 12:40:35 -04:00
/// <summary>
/// Default constructor
/// </summary>
public CbFieldAttribute ( )
{
}
/// <summary>
/// Constructor
/// </summary>
2022-03-24 15:56:16 -04:00
/// <param name="name"></param>
public CbFieldAttribute ( string name )
2021-07-28 12:40:35 -04:00
{
2022-03-25 15:35:47 -04:00
Name = name ;
2021-07-28 12:40:35 -04:00
}
}
2022-01-17 18:52:44 -05:00
/// <summary>
/// Attribute used to indicate that this object is the base for a class hierarchy. Each derived class must have a [CbDiscriminator] attribute.
/// </summary>
2022-10-03 17:36:19 -04:00
[AttributeUsage(AttributeTargets.Class)]
public sealed class CbPolymorphicAttribute : Attribute
2022-01-17 18:52:44 -05:00
{
}
/// <summary>
/// Sets the name used for discriminating between derived classes during serialization
/// </summary>
2022-10-03 17:36:19 -04:00
[AttributeUsage(AttributeTargets.Class)]
public sealed class CbDiscriminatorAttribute : Attribute
2022-01-17 18:52:44 -05:00
{
/// <summary>
/// Name used to identify this class
/// </summary>
public string Name { get ; }
/// <summary>
/// Constructor
/// </summary>
2022-03-24 15:56:16 -04:00
/// <param name="name">Name used to identify this class</param>
2022-03-25 15:35:47 -04:00
public CbDiscriminatorAttribute ( string name ) = > Name = name ;
2022-01-17 18:52:44 -05:00
}
2021-07-28 12:40:35 -04:00
/// <summary>
/// Exception thrown when serializing cb objects
/// </summary>
public class CbException : Exception
{
2022-03-25 15:35:47 -04:00
/// <inheritdoc cref="Exception(String?)"/>
2022-03-24 15:56:16 -04:00
public CbException ( string message ) : base ( message )
2021-07-28 12:40:35 -04:00
{
}
2022-03-25 15:35:47 -04:00
/// <inheritdoc cref="Exception(String?, Exception)"/>
2022-03-24 15:56:16 -04:00
public CbException ( string message , Exception inner ) : base ( message , inner )
2021-07-28 12:40:35 -04:00
{
}
}
2022-03-28 10:11:10 -04:00
/// <summary>
/// Exception indicating that a class does not have any fields to serialize
/// </summary>
public sealed class CbEmptyClassException : CbException
{
/// <summary>
/// Type with missing field annotations
/// </summary>
2022-10-03 17:36:19 -04:00
public Type ClassType { get ; }
2022-03-28 10:11:10 -04:00
/// <summary>
/// Constructor
/// </summary>
2022-10-03 17:36:19 -04:00
public CbEmptyClassException ( Type classType )
: base ( $"{classType.Name} does not have any fields marked with a [CbField] attribute. If this is intended, explicitly mark the class with a [CbObject] attribute." )
2022-03-28 10:11:10 -04:00
{
2022-10-03 17:36:19 -04:00
ClassType = classType ;
2022-03-28 10:11:10 -04:00
}
}
2021-07-28 12:40:35 -04:00
/// <summary>
/// Attribute-driven compact binary serializer
/// </summary>
public static class CbSerializer
{
2021-08-20 14:28:49 -04:00
/// <summary>
/// Serialize an object
/// </summary>
2022-03-24 15:56:16 -04:00
/// <param name="type">Type of the object to serialize</param>
/// <param name="value"></param>
2021-08-20 14:28:49 -04:00
/// <returns></returns>
2022-03-24 15:56:16 -04:00
public static CbObject Serialize ( Type type , object value )
2021-08-20 14:28:49 -04:00
{
2022-03-24 15:56:16 -04:00
CbWriter writer = new CbWriter ( ) ;
CbConverter . GetConverter ( type ) . WriteObject ( writer , value ) ;
return writer . ToObject ( ) ;
2021-08-20 14:28:49 -04:00
}
2021-07-28 12:40:35 -04:00
/// <summary>
/// Serialize an object
/// </summary>
/// <typeparam name="T"></typeparam>
2022-03-24 15:56:16 -04:00
/// <param name="value"></param>
2021-07-28 12:40:35 -04:00
/// <returns></returns>
2022-03-24 15:56:16 -04:00
public static CbObject Serialize < T > ( T value )
2021-07-28 12:40:35 -04:00
{
2022-03-24 15:56:16 -04:00
CbWriter writer = new CbWriter ( ) ;
CbConverter . GetConverter < T > ( ) . Write ( writer , value ) ;
return writer . ToObject ( ) ;
2021-07-29 15:36:21 -04:00
}
2022-04-05 20:17:50 -04:00
/// <summary>
/// Serialize an object
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="value"></param>
/// <returns></returns>
public static byte [ ] SerializeToByteArray < T > ( T value )
{
CbWriter writer = new CbWriter ( ) ;
CbConverter . GetConverter < T > ( ) . Write ( writer , value ) ;
return writer . ToByteArray ( ) ;
}
2021-07-29 15:36:21 -04:00
/// <summary>
2021-07-30 15:15:43 -04:00
/// Serialize a property to a given writer
2021-07-29 15:36:21 -04:00
/// </summary>
/// <typeparam name="T"></typeparam>
2022-03-24 15:56:16 -04:00
/// <param name="writer"></param>
/// <param name="value"></param>
public static void Serialize < T > ( CbWriter writer , T value )
2021-07-29 15:36:21 -04:00
{
2022-03-24 15:56:16 -04:00
CbConverter . GetConverter < T > ( ) . Write ( writer , value ) ;
2021-07-30 15:15:43 -04:00
}
2021-07-29 09:20:21 -04:00
2021-07-30 15:15:43 -04:00
/// <summary>
/// Serialize a named property to the given writer
/// </summary>
/// <typeparam name="T"></typeparam>
2022-03-24 15:56:16 -04:00
/// <param name="writer"></param>
/// <param name="name"></param>
/// <param name="value"></param>
public static void Serialize < T > ( CbWriter writer , Utf8String name , T value )
2021-07-30 15:15:43 -04:00
{
2022-03-24 15:56:16 -04:00
CbConverter . GetConverter < T > ( ) . WriteNamed ( writer , name , value ) ;
2021-07-28 12:40:35 -04:00
}
2021-08-20 14:28:49 -04:00
/// <summary>
/// Deserialize an object from a <see cref="CbObject"/>
/// </summary>
2022-03-24 15:56:16 -04:00
/// <param name="field"></param>
/// <param name="type">Type of the object to read</param>
2021-08-20 14:28:49 -04:00
/// <returns></returns>
2022-03-24 15:56:16 -04:00
public static object? Deserialize ( CbField field , Type type )
2021-08-20 14:28:49 -04:00
{
2022-03-24 15:56:16 -04:00
return CbConverter . GetConverter ( type ) . ReadObject ( field ) ;
2021-08-20 14:28:49 -04:00
}
2021-07-28 12:40:35 -04:00
/// <summary>
2021-10-05 11:16:41 -04:00
/// Deserialize an object from a <see cref="CbField"/>
2021-07-28 12:40:35 -04:00
/// </summary>
/// <typeparam name="T"></typeparam>
2022-03-24 15:56:16 -04:00
/// <param name="field"></param>
2021-07-28 12:40:35 -04:00
/// <returns></returns>
2022-03-24 15:56:16 -04:00
public static T Deserialize < T > ( CbField field )
2021-07-28 12:40:35 -04:00
{
2022-03-24 15:56:16 -04:00
return CbConverter . GetConverter < T > ( ) . Read ( field ) ;
2021-07-29 09:20:21 -04:00
}
2021-10-05 11:16:41 -04:00
/// <summary>
/// Deserialize an object from a <see cref="CbObject"/>
/// </summary>
/// <typeparam name="T"></typeparam>
2022-03-24 15:56:16 -04:00
/// <param name="obj"></param>
2021-10-05 11:16:41 -04:00
/// <returns></returns>
2022-03-24 15:56:16 -04:00
public static T Deserialize < T > ( CbObject obj ) = > Deserialize < T > ( obj . AsField ( ) ) ;
2021-10-05 11:16:41 -04:00
/// <summary>
/// Deserialize an object from a block of memory
/// </summary>
/// <typeparam name="T"></typeparam>
2022-03-24 15:56:16 -04:00
/// <param name="data"></param>
2021-10-05 11:16:41 -04:00
/// <returns></returns>
2022-03-24 15:56:16 -04:00
public static T Deserialize < T > ( ReadOnlyMemory < byte > data ) = > Deserialize < T > ( new CbField ( data ) ) ;
2021-07-28 12:40:35 -04:00
}
}