2019-06-12 21:56:55 +02:00
using System ;
using System.Runtime.InteropServices ;
namespace Capnp
{
/// <summary>
/// Provides extensions to the <see cref="IStructDeserializer"/> and <see cref="IStructSerializer"/> interfaces for type-safe reading and writing.
/// </summary>
public static class SerializerExtensions
{
/// <summary>
/// Reads a boolean field.
/// </summary>
/// <typeparam name="T">Type implementing <see cref="IStructDeserializer"/></typeparam>
/// <param name="d">"this" instance</param>
/// <param name="bitOffset">Start bit</param>
/// <param name="defaultValue">Field default value (will be XORed with the result)</param>
/// <returns>The read value</returns>
public static bool ReadDataBool < T > ( this T d , ulong bitOffset , bool defaultValue = false )
where T : IStructDeserializer
{
return ( d . StructReadData ( bitOffset , 1 ) ! = 0 ) ! = defaultValue ;
}
/// <summary>
/// Writes a boolean field.
/// </summary>
/// <typeparam name="T">Type implementing <see cref="IStructSerializer"/></typeparam>
/// <param name="d">"this" instance</param>
/// <param name="bitOffset">Start bit</param>
/// <param name="value">Value to write</param>
/// <param name="defaultValue">Field default value (will be XORed with the value to write)</param>
public static void WriteData < T > ( this T d , ulong bitOffset , bool value , bool defaultValue = false )
where T : IStructSerializer
{
d . StructWriteData ( bitOffset , 1 , value ! = defaultValue ? 1 ul : 0 ) ;
}
/// <summary>
/// Reads a byte field.
/// </summary>
/// <typeparam name="T">Type implementing <see cref="IStructDeserializer"/></typeparam>
/// <param name="d">"this" instance</param>
/// <param name="bitOffset">Start bit</param>
/// <param name="defaultValue">Field default value (will be XORed with the result)</param>
/// <returns>The read value</returns>
public static byte ReadDataByte < T > ( this T d , ulong bitOffset , byte defaultValue = 0 )
where T : IStructDeserializer
{
return ( byte ) ( d . StructReadData ( bitOffset , 8 ) ^ defaultValue ) ;
}
/// <summary>
/// Writes a byte field.
/// </summary>
/// <typeparam name="T">Type implementing <see cref="IStructSerializer"/></typeparam>
/// <param name="d">"this" instance</param>
/// <param name="bitOffset">Start bit</param>
/// <param name="value">Value to write</param>
/// <param name="defaultValue">Field default value (will be XORed with the value to write)</param>
public static void WriteData < T > ( this T d , ulong bitOffset , byte value , byte defaultValue = 0 )
where T : IStructSerializer
{
d . StructWriteData ( bitOffset , 8 , ( byte ) ( value ^ defaultValue ) ) ;
}
/// <summary>
/// Reads a signed byte field.
/// </summary>
/// <typeparam name="T">Type implementing <see cref="IStructDeserializer"/></typeparam>
/// <param name="d">"this" instance</param>
/// <param name="bitOffset">Start bit</param>
/// <param name="defaultValue">Field default value (will be XORed with the result)</param>
/// <returns>The read value</returns>
public static sbyte ReadDataSByte < T > ( this T d , ulong bitOffset , sbyte defaultValue = 0 )
where T : IStructDeserializer
{
return ( sbyte ) ( ( sbyte ) d . StructReadData ( bitOffset , 8 ) ^ defaultValue ) ;
}
/// <summary>
/// Writes a signed byte field.
/// </summary>
/// <typeparam name="T">Type implementing <see cref="IStructSerializer"/></typeparam>
/// <param name="d">"this" instance</param>
/// <param name="bitOffset">Start bit</param>
/// <param name="value">Value to write</param>
/// <param name="defaultValue">Field default value (will be XORed with the value to write)</param>
public static void WriteData < T > ( this T d , ulong bitOffset , sbyte value , sbyte defaultValue = 0 )
where T : IStructSerializer
{
d . StructWriteData ( bitOffset , 8 , unchecked ( ( ulong ) ( value ^ defaultValue ) ) ) ;
}
/// <summary>
/// Reads a ushort field.
/// </summary>
/// <typeparam name="T">Type implementing <see cref="IStructDeserializer"/></typeparam>
/// <param name="d">"this" instance</param>
/// <param name="bitOffset">Start bit</param>
/// <param name="defaultValue">Field default value (will be XORed with the result)</param>
/// <returns>The read value</returns>
public static ushort ReadDataUShort < T > ( this T d , ulong bitOffset , ushort defaultValue = 0 )
where T : IStructDeserializer
{
return ( ushort ) ( d . StructReadData ( bitOffset , 16 ) ^ defaultValue ) ;
}
/// <summary>
/// Writes a ushort field.
/// </summary>
/// <typeparam name="T">Type implementing <see cref="IStructSerializer"/></typeparam>
/// <param name="d">"this" instance</param>
/// <param name="bitOffset">Start bit</param>
/// <param name="value">Value to write</param>
/// <param name="defaultValue">Field default value (will be XORed with the value to write)</param>
public static void WriteData < T > ( this T d , ulong bitOffset , ushort value , ushort defaultValue = 0 )
where T : IStructSerializer
{
d . StructWriteData ( bitOffset , 16 , ( ushort ) ( value ^ defaultValue ) ) ;
}
/// <summary>
/// Reads a short field.
/// </summary>
/// <typeparam name="T">Type implementing <see cref="IStructDeserializer"/></typeparam>
/// <param name="d">"this" instance</param>
/// <param name="bitOffset">Start bit</param>
/// <param name="defaultValue">Field default value (will be XORed with the result)</param>
/// <returns>The read value</returns>
public static short ReadDataShort < T > ( this T d , ulong bitOffset , short defaultValue = 0 )
where T : IStructDeserializer
{
return ( short ) ( ( short ) d . StructReadData ( bitOffset , 16 ) ^ defaultValue ) ;
}
/// <summary>
/// Writes a short field.
/// </summary>
/// <typeparam name="T">Type implementing <see cref="IStructSerializer"/></typeparam>
/// <param name="d">"this" instance</param>
/// <param name="bitOffset">Start bit</param>
/// <param name="value">Value to write</param>
/// <param name="defaultValue">Field default value (will be XORed with the value to write)</param>
public static void WriteData < T > ( this T d , ulong bitOffset , short value , short defaultValue = 0 )
where T : IStructSerializer
{
d . StructWriteData ( bitOffset , 16 , unchecked ( ( ulong ) ( value ^ defaultValue ) ) ) ;
}
/// <summary>
/// Reads a uint field.
/// </summary>
/// <typeparam name="T">Type implementing <see cref="IStructDeserializer"/></typeparam>
/// <param name="d">"this" instance</param>
/// <param name="bitOffset">Start bit</param>
/// <param name="defaultValue">Field default value (will be XORed with the result)</param>
/// <returns>The read value</returns>
public static uint ReadDataUInt < T > ( this T d , ulong bitOffset , uint defaultValue = 0 )
where T : IStructDeserializer
{
return ( uint ) ( d . StructReadData ( bitOffset , 32 ) ^ defaultValue ) ;
}
/// <summary>
/// Writes a uint field.
/// </summary>
/// <typeparam name="T">Type implementing <see cref="IStructSerializer"/></typeparam>
/// <param name="d">"this" instance</param>
/// <param name="bitOffset">Start bit</param>
/// <param name="value">Value to write</param>
/// <param name="defaultValue">Field default value (will be XORed with the value to write)</param>
public static void WriteData < T > ( this T d , ulong bitOffset , uint value , uint defaultValue = 0 )
where T : IStructSerializer
{
d . StructWriteData ( bitOffset , 32 , value ^ defaultValue ) ;
}
/// <summary>
/// Performs a "reinterpret cast" of the struct's data section and returns a reference to a single element of the cast result.
/// </summary>
/// <typeparam name="U">The cast target type. Must be a primitive type which qualifies for <code><![CDATA[MemoryMarshal.Cast<ulong, U>()]]></code></typeparam>
/// <param name="d">"this" instance</param>
/// <param name="woffset">Index within the cast result, conceptually into <code>U[]</code></param>
/// <returns>A reference to the data element</returns>
public static ref U RefData < U > ( this IStructSerializer d , int woffset )
where U : struct
{
var data = MemoryMarshal . Cast < ulong , U > ( d . StructDataSection ) ;
return ref MemoryMarshal . GetReference ( data . Slice ( woffset , 1 ) ) ;
}
/// <summary>
/// Reads an int field.
/// </summary>
/// <typeparam name="T">Type implementing <see cref="IStructDeserializer"/></typeparam>
/// <param name="d">"this" instance</param>
/// <param name="bitOffset">Start bit</param>
/// <param name="defaultValue">Field default value (will be XORed with the result)</param>
/// <returns>The read value</returns>
public static int ReadDataInt < T > ( this T d , ulong bitOffset , int defaultValue = 0 )
where T : IStructDeserializer
{
return ( int ) d . StructReadData ( bitOffset , 32 ) ^ defaultValue ;
}
/// <summary>
/// Writes an int field.
/// </summary>
/// <typeparam name="T">Type implementing <see cref="IStructSerializer"/></typeparam>
/// <param name="d">"this" instance</param>
/// <param name="bitOffset">Start bit</param>
/// <param name="value">Value to write</param>
/// <param name="defaultValue">Field default value (will be XORed with the value to write)</param>
public static void WriteData < T > ( this T d , ulong bitOffset , int value , int defaultValue = 0 )
where T : IStructSerializer
{
d . StructWriteData ( bitOffset , 32 , unchecked ( ( ulong ) ( value ^ defaultValue ) ) ) ;
}
/// <summary>
/// Reads a ulong field.
/// </summary>
/// <typeparam name="T">Type implementing <see cref="IStructDeserializer"/></typeparam>
/// <param name="d">"this" instance</param>
/// <param name="bitOffset">Start bit</param>
/// <param name="defaultValue">Field default value (will be XORed with the result)</param>
/// <returns>The read value</returns>
public static ulong ReadDataULong < T > ( this T d , ulong bitOffset , ulong defaultValue = 0 )
where T : IStructDeserializer
{
return d . StructReadData ( bitOffset , 64 ) ^ defaultValue ;
}
/// <summary>
/// Writes a ulong field.
/// </summary>
/// <typeparam name="T">Type implementing <see cref="IStructSerializer"/></typeparam>
/// <param name="d">"this" instance</param>
/// <param name="bitOffset">Start bit</param>
/// <param name="value">Value to write</param>
/// <param name="defaultValue">Field default value (will be XORed with the value to write)</param>
public static void WriteData < T > ( this T d , ulong bitOffset , ulong value , ulong defaultValue = 0 )
where T : IStructSerializer
{
d . StructWriteData ( bitOffset , 64 , value ^ defaultValue ) ;
}
/// <summary>
/// Reads a long field.
/// </summary>
/// <typeparam name="T">Type implementing <see cref="IStructDeserializer"/></typeparam>
/// <param name="d">"this" instance</param>
/// <param name="bitOffset">Start bit</param>
/// <param name="defaultValue">Field default value (will be XORed with the result)</param>
/// <returns>The read value</returns>
public static long ReadDataLong < T > ( this T d , ulong bitOffset , long defaultValue = 0 )
where T : IStructDeserializer
{
return ( long ) d . StructReadData ( bitOffset , 64 ) ^ defaultValue ;
}
/// <summary>
/// Writes a long field.
/// </summary>
/// <typeparam name="T">Type implementing <see cref="IStructSerializer"/></typeparam>
/// <param name="d">"this" instance</param>
/// <param name="bitOffset">Start bit</param>
/// <param name="value">Value to write</param>
/// <param name="defaultValue">Field default value (will be XORed with the value to write)</param>
public static void WriteData < T > ( this T d , ulong bitOffset , long value , long defaultValue = 0 )
where T : IStructSerializer
{
d . StructWriteData ( bitOffset , 64 , unchecked ( ( ulong ) ( value ^ defaultValue ) ) ) ;
}
/// <summary>
/// Reads a float field.
/// </summary>
/// <typeparam name="T">Type implementing <see cref="IStructDeserializer"/></typeparam>
/// <param name="d">"this" instance</param>
/// <param name="bitOffset">Start bit</param>
/// <param name="defaultValue">Field default value (raw bits will be XORed with the result)</param>
/// <returns>The read value</returns>
public static float ReadDataFloat < T > ( this T d , ulong bitOffset , float defaultValue = 0 )
where T : IStructDeserializer
{
2019-07-04 22:05:37 +02:00
int defaultBits = defaultValue . ReplacementSingleToInt32Bits ( ) ;
2019-06-12 21:56:55 +02:00
int bits = ( int ) d . StructReadData ( bitOffset , 32 ) ^ defaultBits ;
2019-07-04 22:05:37 +02:00
return bits . ReplacementInt32ToSingleBits ( ) ;
2019-06-12 21:56:55 +02:00
}
/// <summary>
/// Writes a float field.
/// </summary>
/// <typeparam name="T">Type implementing <see cref="IStructSerializer"/></typeparam>
/// <param name="d">"this" instance</param>
/// <param name="bitOffset">Start bit</param>
/// <param name="value">Value to write</param>
/// <param name="defaultValue">Field default value (raw bits will be XORed with the value to write)</param>
public static void WriteData < T > ( this T d , ulong bitOffset , float value , float defaultValue = 0.0f )
where T : IStructSerializer
{
2019-07-04 22:05:37 +02:00
int bits = value . ReplacementSingleToInt32Bits ( ) ;
int defaultBits = defaultValue . ReplacementSingleToInt32Bits ( ) ;
2019-06-12 21:56:55 +02:00
WriteData ( d , bitOffset , bits , defaultBits ) ;
}
/// <summary>
/// Reads a double field.
/// </summary>
/// <typeparam name="T">Type implementing <see cref="IStructDeserializer"/></typeparam>
/// <param name="d">"this" instance</param>
/// <param name="bitOffset">Start bit</param>
/// <param name="defaultValue">Field default value (raw bits will be XORed with the result)</param>
/// <returns>The read value</returns>
public static double ReadDataDouble < T > ( this T d , ulong bitOffset , double defaultValue = 0 )
where T : IStructDeserializer
{
long defaultBits = BitConverter . DoubleToInt64Bits ( defaultValue ) ;
long bits = ( long ) d . StructReadData ( bitOffset , 64 ) ^ defaultBits ;
return BitConverter . Int64BitsToDouble ( bits ) ;
}
/// <summary>
/// Writes a double field.
/// </summary>
/// <typeparam name="T">Type implementing <see cref="IStructSerializer"/></typeparam>
/// <param name="d">"this" instance</param>
/// <param name="bitOffset">Start bit</param>
/// <param name="value">Value to write</param>
/// <param name="defaultValue">Field default value (raw bits will be XORed with the value to write)</param>
public static void WriteData < T > ( this T d , ulong bitOffset , double value , double defaultValue = 0.0 )
where T : IStructSerializer
{
long bits = BitConverter . DoubleToInt64Bits ( value ) ;
long defaultBits = BitConverter . DoubleToInt64Bits ( defaultValue ) ;
WriteData ( d , bitOffset , bits , defaultBits ) ;
}
}
2020-01-11 17:56:12 +01:00
}