using ln.type; using System; using System.Collections.Generic; using System.IO; using System.Reflection; using System.Runtime.CompilerServices; using System.Text; /** * typeCode list * * 0x0000 ODBNull * 0x0001 ODBStringValue * 0x0002 ODBList * 0x0003 ODBGuid * 0x0004 ODBBool * 0x0005 ODBObject * * 0x0010 ODBInteger * 0x0011 ODBUInteger * 0x0012 ODBLong * 0x0013 ODBULong * * 0x0018 ODBDouble * * 0x0020 ODBTypedMapping * * 0x0800 ODBByteBuffer * * 0x1000 ODBDocument * 0x1001 Document (ln.types.odb.ng) * * * **/ namespace ln.objects.catalog { public delegate ODBEntity ODBValueFactory(object value); public delegate ODBEntity ODBDeserialize(byte[] storageBytes, int offset, int length); /// /// ODBEntity. The base of all ODB types. /// /// The data model used by ODB can be described as follows: /// /// Each piece of information to be used with ODB may be called an entity. /// ODB provides support for several types of entities (e.g. numbers, strings, documents, lists,...) /// An entity has an identity and a state. /// Two entities of same type having the same identity are considered to be "equal". /// Two entities of same type having the same identity may represent different states of the same entity. (different "Versions", e.g. an old and up to date /// /// ODBEntity instances /// - define identity through Identity /// - may be seen as a "container" holding a certain state /// /// ODBValue instances /// extend ODBEntity /// - implement Identity to return itself /// - implement CompareTo as simple "substraction" /// /// other ODBEntity subtypes /// - implement a read-only Identity to return a ODBvalue instance /// - implement CompareTo type specific without defined semantic meaning /// /// /// /// public abstract class ODBEntity : IComparable { int storageTypeCode; /// /// Gets the identity of this Entity. /// /// The identity. public virtual ODBValue Identity { get; } /// /// Independently clone this instance. /// /// /// For immutable values this returns the instance itself. /// Complex ODBEntities will return a copy of themself that is completly independend of the source. /// /// The clone. public abstract ODBEntity Clone(); /// /// Implements the internal comparison within the same subclass of ODBEntity. /// /// The compare. /// Other. 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[] Serialize(); public virtual void Serialize(BinaryWriter storage) { byte[] storageBytes = Serialize(); 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 (Equals(GetType(), obj.GetType()) && obj is ODBEntity) return Equals(Identity, (obj as ODBEntity).Identity); return false; } 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 valueDeserializers = new Dictionary(); 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 Deserialize(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); } public string TreeString => ToTreeString(0); public abstract string ToTreeString(int indent); static ODBEntity() { RuntimeHelpers.RunClassConstructor(typeof(ODBNull).TypeHandle); RuntimeHelpers.RunClassConstructor(typeof(ODBObject).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); RuntimeHelpers.RunClassConstructor(typeof(ODBByteBuffer).TypeHandle); } } }