2018-04-25 15:25:47 +02:00
using System ;
using System.IO ;
using CSharpTest.Net.Serialization ;
namespace Umbraco.Web.PublishedCache.NuCache.DataSource
{
internal abstract class SerializerBase
{
2020-07-03 12:11:05 +10:00
private const char PrefixNull = 'N' ;
private const char PrefixString = 'S' ;
private const char PrefixInt32 = 'I' ;
private const char PrefixUInt16 = 'H' ;
2020-07-03 16:56:08 +12:00
private const char PrefixUInt32 = 'J' ;
2020-07-03 12:11:05 +10:00
private const char PrefixLong = 'L' ;
private const char PrefixFloat = 'F' ;
private const char PrefixDouble = 'B' ;
private const char PrefixDateTime = 'D' ;
private const char PrefixByte = 'O' ;
2020-08-13 23:32:05 +10:00
// TODO: It might make sense to have another prefix for an LZ4 compressed byte array.
// Would be an improvement for the SQLDatabase compression option because then you could mix compressed and decompressed properties with the same alias.
// For example, don't compress recent content, but compress older content.
2020-07-09 00:17:31 +12:00
private const char PrefixByteArray = 'A' ;
2020-07-03 12:11:05 +10:00
2018-04-25 15:25:47 +02:00
protected string ReadString ( Stream stream ) = > PrimitiveSerializer . String . ReadFrom ( stream ) ;
protected int ReadInt ( Stream stream ) = > PrimitiveSerializer . Int32 . ReadFrom ( stream ) ;
protected long ReadLong ( Stream stream ) = > PrimitiveSerializer . Int64 . ReadFrom ( stream ) ;
protected float ReadFloat ( Stream stream ) = > PrimitiveSerializer . Float . ReadFrom ( stream ) ;
protected double ReadDouble ( Stream stream ) = > PrimitiveSerializer . Double . ReadFrom ( stream ) ;
protected DateTime ReadDateTime ( Stream stream ) = > PrimitiveSerializer . DateTime . ReadFrom ( stream ) ;
2020-07-09 00:17:31 +12:00
protected byte [ ] ReadByteArray ( Stream stream ) = > PrimitiveSerializer . Bytes . ReadFrom ( stream ) ;
2018-04-25 15:25:47 +02:00
private T ? ReadObject < T > ( Stream stream , char t , Func < Stream , T > read )
where T : struct
{
var type = PrimitiveSerializer . Char . ReadFrom ( stream ) ;
2020-07-03 12:11:05 +10:00
if ( type = = PrefixNull ) return null ;
2018-04-25 15:25:47 +02:00
if ( type ! = t )
throw new NotSupportedException ( $"Cannot deserialize type '{type}', expected '{t}'." ) ;
return read ( stream ) ;
}
2020-07-03 00:26:55 +10:00
protected string ReadStringObject ( Stream stream , bool intern = false ) // required 'cos string is not a struct
2018-04-25 15:25:47 +02:00
{
var type = PrimitiveSerializer . Char . ReadFrom ( stream ) ;
2020-07-03 12:11:05 +10:00
if ( type = = PrefixNull ) return null ;
if ( type ! = PrefixString )
2020-07-09 00:17:31 +12:00
throw new NotSupportedException ( $"Cannot deserialize type '{type}', expected '{PrefixString}'." ) ;
2020-07-03 00:26:55 +10:00
return intern
? string . Intern ( PrimitiveSerializer . String . ReadFrom ( stream ) )
: PrimitiveSerializer . String . ReadFrom ( stream ) ;
2018-04-25 15:25:47 +02:00
}
2020-07-03 12:11:05 +10:00
protected int? ReadIntObject ( Stream stream ) = > ReadObject ( stream , PrefixInt32 , ReadInt ) ;
protected long? ReadLongObject ( Stream stream ) = > ReadObject ( stream , PrefixLong , ReadLong ) ;
protected float? ReadFloatObject ( Stream stream ) = > ReadObject ( stream , PrefixFloat , ReadFloat ) ;
protected double? ReadDoubleObject ( Stream stream ) = > ReadObject ( stream , PrefixDouble , ReadDouble ) ;
protected DateTime ? ReadDateTimeObject ( Stream stream ) = > ReadObject ( stream , PrefixDateTime , ReadDateTime ) ;
2018-04-25 15:25:47 +02:00
2020-07-09 00:17:31 +12:00
protected byte [ ] ReadByteArrayObject ( Stream stream ) // required 'cos byte[] is not a struct
{
var type = PrimitiveSerializer . Char . ReadFrom ( stream ) ;
if ( type = = PrefixNull ) return null ;
if ( type ! = PrefixByteArray )
throw new NotSupportedException ( $"Cannot deserialize type '{type}', expected '{PrefixByteArray}'." ) ;
return PrimitiveSerializer . Bytes . ReadFrom ( stream ) ;
}
2018-04-25 15:25:47 +02:00
protected object ReadObject ( Stream stream )
= > ReadObject ( PrimitiveSerializer . Char . ReadFrom ( stream ) , stream ) ;
protected object ReadObject ( char type , Stream stream )
{
2020-07-03 12:11:05 +10:00
// NOTE: There is going to be a ton of boxing going on here, but i'm not sure we can avoid that because innevitably with our
// current model structure the value will need to end up being 'object' at some point anyways.
2018-04-25 15:25:47 +02:00
switch ( type )
{
2020-07-03 12:11:05 +10:00
case PrefixNull :
2018-04-25 15:25:47 +02:00
return null ;
2020-07-03 12:11:05 +10:00
case PrefixString :
2018-04-25 15:25:47 +02:00
return PrimitiveSerializer . String . ReadFrom ( stream ) ;
2020-07-03 12:11:05 +10:00
case PrefixInt32 :
2018-04-25 15:25:47 +02:00
return PrimitiveSerializer . Int32 . ReadFrom ( stream ) ;
2020-07-03 12:11:05 +10:00
case PrefixUInt16 :
return PrimitiveSerializer . UInt16 . ReadFrom ( stream ) ;
2020-07-03 16:56:08 +12:00
case PrefixUInt32 :
return PrimitiveSerializer . UInt32 . ReadFrom ( stream ) ;
2020-07-03 12:11:05 +10:00
case PrefixByte :
return PrimitiveSerializer . Byte . ReadFrom ( stream ) ;
case PrefixLong :
2018-04-25 15:25:47 +02:00
return PrimitiveSerializer . Int64 . ReadFrom ( stream ) ;
2020-07-03 12:11:05 +10:00
case PrefixFloat :
2018-04-25 15:25:47 +02:00
return PrimitiveSerializer . Float . ReadFrom ( stream ) ;
2020-07-03 12:11:05 +10:00
case PrefixDouble :
2018-04-25 15:25:47 +02:00
return PrimitiveSerializer . Double . ReadFrom ( stream ) ;
2020-07-03 12:11:05 +10:00
case PrefixDateTime :
2018-04-25 15:25:47 +02:00
return PrimitiveSerializer . DateTime . ReadFrom ( stream ) ;
2020-07-09 00:17:31 +12:00
case PrefixByteArray :
return PrimitiveSerializer . Bytes . ReadFrom ( stream ) ;
2018-04-25 15:25:47 +02:00
default :
2019-01-26 10:52:19 -05:00
throw new NotSupportedException ( $"Cannot deserialize unknown type '{type}'." ) ;
2018-04-25 15:25:47 +02:00
}
}
protected void WriteObject ( object value , Stream stream )
{
if ( value = = null )
{
2020-07-03 12:11:05 +10:00
PrimitiveSerializer . Char . WriteTo ( PrefixNull , stream ) ;
2018-04-25 15:25:47 +02:00
}
else if ( value is string stringValue )
{
2020-07-03 12:11:05 +10:00
PrimitiveSerializer . Char . WriteTo ( PrefixString , stream ) ;
2018-04-25 15:25:47 +02:00
PrimitiveSerializer . String . WriteTo ( stringValue , stream ) ;
}
else if ( value is int intValue )
{
2020-07-03 12:11:05 +10:00
PrimitiveSerializer . Char . WriteTo ( PrefixInt32 , stream ) ;
2018-04-25 15:25:47 +02:00
PrimitiveSerializer . Int32 . WriteTo ( intValue , stream ) ;
}
2020-07-03 12:11:05 +10:00
else if ( value is byte byteValue )
{
PrimitiveSerializer . Char . WriteTo ( PrefixByte , stream ) ;
PrimitiveSerializer . Byte . WriteTo ( byteValue , stream ) ;
}
else if ( value is ushort ushortValue )
{
PrimitiveSerializer . Char . WriteTo ( PrefixUInt16 , stream ) ;
PrimitiveSerializer . UInt16 . WriteTo ( ushortValue , stream ) ;
}
2018-04-25 15:25:47 +02:00
else if ( value is long longValue )
{
2020-07-03 12:11:05 +10:00
PrimitiveSerializer . Char . WriteTo ( PrefixLong , stream ) ;
2018-04-25 15:25:47 +02:00
PrimitiveSerializer . Int64 . WriteTo ( longValue , stream ) ;
}
else if ( value is float floatValue )
{
2020-07-03 12:11:05 +10:00
PrimitiveSerializer . Char . WriteTo ( PrefixFloat , stream ) ;
2018-04-25 15:25:47 +02:00
PrimitiveSerializer . Float . WriteTo ( floatValue , stream ) ;
}
else if ( value is double doubleValue )
{
2020-07-03 12:11:05 +10:00
PrimitiveSerializer . Char . WriteTo ( PrefixDouble , stream ) ;
2018-04-25 15:25:47 +02:00
PrimitiveSerializer . Double . WriteTo ( doubleValue , stream ) ;
}
else if ( value is DateTime dateValue )
{
2020-07-03 12:11:05 +10:00
PrimitiveSerializer . Char . WriteTo ( PrefixDateTime , stream ) ;
2018-04-25 15:25:47 +02:00
PrimitiveSerializer . DateTime . WriteTo ( dateValue , stream ) ;
}
2020-07-03 16:56:08 +12:00
else if ( value is uint uInt32Value )
{
PrimitiveSerializer . Char . WriteTo ( PrefixUInt32 , stream ) ;
PrimitiveSerializer . UInt32 . WriteTo ( uInt32Value , stream ) ;
}
2020-07-09 00:17:31 +12:00
else if ( value is byte [ ] byteArrayValue )
{
PrimitiveSerializer . Char . WriteTo ( PrefixByteArray , stream ) ;
PrimitiveSerializer . Bytes . WriteTo ( byteArrayValue , stream ) ;
}
2018-04-25 15:25:47 +02:00
else
throw new NotSupportedException ( "Value type " + value . GetType ( ) . FullName + " cannot be serialized." ) ;
}
}
}