ln.types/odb/values/ODBEntity.cs

194 lines
6.6 KiB
C#

using System;
using System.Collections.Generic;
using System.IO;
using ln.types.odb.ng;
using System.Reflection;
using System.Runtime.CompilerServices;
/**
* typeCode list
*
* 0x0000 ODBNull
* 0x0001 ODBStringValue
* 0x0002 ODBList
* 0x0003 ODBGuid
* 0x0004 ODBBool
*
* 0x0010 ODBInteger
* 0x0011 ODBUInteger
* 0x0012 ODBLong
* 0x0013 ODBULong
*
* 0x0018 ODBDouble
*
* 0x0020 ODBTypedMapping
*
* 0x1000 ODBDocument
* 0x1001 Document (ln.types.odb.ng)
*
*
*
**/
namespace ln.types.odb.values
{
public delegate ODBEntity ODBValueFactory(object value);
public delegate ODBEntity ODBDeserialize(byte[] storageBytes, int offset, int length);
/// <summary>
/// ODBEntity. The base of all ODB types.
/// </summary>
/// <remarks>
///
/// </remarks>
///
public abstract class ODBEntity : IComparable<ODBEntity>
{
int storageTypeCode;
/// <summary>
/// Gets the identity of this Entity.
/// </summary>
/// <value>The identity.</value>
public virtual ODBValue Identity { get; }
/// <summary>
/// Return a .NET native value / object that semantically equals this ODBEntity instance.
/// </summary>
/// <returns>The native .NET value</returns>
/// <typeparam name="T">The type to which this ODBEntity should be casted/converted.</typeparam>
public abstract T As<T>();
/// <summary>
/// Independently clone this instance.
/// </summary>
/// <remarks>
/// For immutable values this returns the instance itself.
/// Complex ODBEntities will return a copy of themself that is completly independend of the source.
/// </remarks>
/// <returns>The clone.</returns>
public abstract ODBEntity Clone();
/// <summary>
/// Implements the internal comparison within the same subclass of ODBEntity.
/// </summary>
/// <returns>The compare.</returns>
/// <param name="other">Other.</param>
protected abstract int compare(ODBEntity other);
protected ODBEntity(int storageTypeCode)
{
this.storageTypeCode = storageTypeCode;
}
public int CompareTo(ODBEntity other)
{
if (storageTypeCode != other.storageTypeCode)
return storageTypeCode - other.storageTypeCode;
return compare(other);
}
public abstract byte[] GetStorageBytes();
public virtual void Write(BinaryWriter storage)
{
byte[] storageBytes = GetStorageBytes();
storage.Write(storageTypeCode);
storage.Write(storageBytes.Length);
storage.Write(storageBytes, 0, storageBytes.Length);
}
public override int GetHashCode() => Identity.GetHashCode();
public override bool Equals(object obj)
{
if (obj is ODBEntity)
return Identity.Equals((obj as ODBEntity).Identity);
return false;
}
public virtual object As(Type targetType)
{
MethodInfo methodInfo = GetType().GetMethod("As");
return methodInfo.MakeGenericMethod(targetType).Invoke(this, new object[0]);
}
public static bool operator <(ODBEntity a, ODBEntity b) => a.CompareTo(b) < 0;
public static bool operator >(ODBEntity a, ODBEntity b) => a.CompareTo(b) > 0;
public static bool operator <=(ODBEntity a, ODBEntity b) => a.CompareTo(b) <= 0;
public static bool operator >=(ODBEntity a, ODBEntity b) => a.CompareTo(b) >= 0;
public static bool operator ==(ODBEntity a, ODBEntity b) => (a is null) ? b is null : a.CompareTo(b) == 0;
public static bool operator !=(ODBEntity a, ODBEntity b) => (a is null) ? !(b is null) : a.CompareTo(b) != 0;
//public static implicit operator ODBEntity(ValueType v)
//{
// return Mapper.Default.MapValue(v);
//}
//public static implicit operator ODBEntity(String v)
//{
// return Mapper.Default.MapValue(v);
//}
public static ODBEntity FromNative(object v)
{
return Mapper.Default.MapValue(v);
}
static Dictionary<int, ODBDeserialize> valueDeserializers = new Dictionary<int, ODBDeserialize>();
public static void RegisterDeserializer(int storageTypeCode, ODBDeserialize deserialize)
{
valueDeserializers.Add(storageTypeCode, deserialize);
}
public static ODBEntity Deserialize(byte[] buffer, ref int offset)
{
int storageTypeCode = BitConverter.ToInt32(buffer, offset);
int storageLength = BitConverter.ToInt32(buffer, offset + 4);
if (!valueDeserializers.ContainsKey(storageTypeCode))
throw new KeyNotFoundException(String.Format("StorageTypeCode 0x{0:x8} at offset 0x{1:x8}",storageTypeCode,offset));
ODBEntity value = valueDeserializers[storageTypeCode](buffer, offset + 8, storageLength);
offset += 8 + storageLength;
return value;
}
public static ODBEntity Read(Stream stream)
{
int storageTypeCode = stream.ReadInteger();
int storageLength = stream.ReadInteger();
byte[] b = new byte[storageLength];
stream.Read(b, 0, storageLength);
if (valueDeserializers.ContainsKey(storageTypeCode))
return valueDeserializers[storageTypeCode](b, 0, storageLength);
else
throw new FormatException("wrong storage type code");
}
public override string ToString()
{
return String.Format("[{0} Identity={1}]", GetType().Name, Identity);
}
static ODBEntity()
{
RuntimeHelpers.RunClassConstructor(typeof(ODBNull).TypeHandle);
RuntimeHelpers.RunClassConstructor(typeof(Document).TypeHandle);
RuntimeHelpers.RunClassConstructor(typeof(ODBList).TypeHandle);
RuntimeHelpers.RunClassConstructor(typeof(ODBStringValue).TypeHandle);
RuntimeHelpers.RunClassConstructor(typeof(ODBInteger).TypeHandle);
RuntimeHelpers.RunClassConstructor(typeof(ODBUInteger).TypeHandle);
RuntimeHelpers.RunClassConstructor(typeof(ODBLong).TypeHandle);
RuntimeHelpers.RunClassConstructor(typeof(ODBULong).TypeHandle);
RuntimeHelpers.RunClassConstructor(typeof(ODBDouble).TypeHandle);
RuntimeHelpers.RunClassConstructor(typeof(ODBGuid).TypeHandle);
RuntimeHelpers.RunClassConstructor(typeof(ODBBool).TypeHandle);
}
}
}