This commit is contained in:
2026-07-12 15:22:42 +03:00
parent 91d9c5d959
commit 2f81cd1d30
44 changed files with 785 additions and 242 deletions
+2 -3
View File
@@ -1,6 +1,7 @@
using Esiur.Core;
using Esiur.Data.Gvwie;
using Esiur.Data.Types;
using Esiur.Net.Packets;
using Esiur.Protocol;
using Esiur.Resource;
using Microsoft.CodeAnalysis;
@@ -9,6 +10,7 @@ using System.Buffers.Binary;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Reflection.Metadata;
using System.Text;
namespace Esiur.Data;
@@ -980,10 +982,7 @@ public static class DataSerializer
}
public static Tdu TypeDefComposer(object value, Warehouse warehouse, EpConnection connection)
{
}
}
+19
View File
@@ -0,0 +1,19 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace Esiur.Data
{
public enum OrderingControl : byte
{
Strict = 0,
// Can be reordered with unrelated notifications,
// but updates are still delivered.
Relaxed = 1,
// Runtime may keep only the newest pending value
// for this property.
LatestOnly = 2,
}
}
@@ -23,6 +23,11 @@ public class ArgumentDef
public Map<string, string> Annotations { get; set; }
//public ArgumentDefFlags Flags { get; set; }
public object DefaultValue { get; set; }
public static async AsyncReply<ParseResult<ArgumentDef>> ParseAsync(byte[] data, uint offset, int index, EpConnection connection, ulong[] requestSequence)
{
var optional = (data[offset] & 0x1) == 0x1;
@@ -0,0 +1,12 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace Esiur.Data.Types
{
public enum ArgumentDefField : byte
{
ValueType = 0x03, // TypeRepresentation
DefaultValue = 0x04, // object
}
}
@@ -0,0 +1,14 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace Esiur.Data.Types
{
[Flags]
public enum ArgumentDefFlags : byte
{
None = 0,
Optional = 0x01, // Caller may omit the argument.
Variadic = 0x02, // Last argument accepts multiple values.
}
}
+1 -1
View File
@@ -17,7 +17,7 @@ public class AttributeDef : MemberDef
set;
}
public static AttributeDef MakeAttributeDef(Type type, PropertyInfo pi, byte index, string name, TypeDef typeDef)
{
return new AttributeDef()
@@ -0,0 +1,12 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace Esiur.Data.Types
{
public enum ConstantDefField : byte
{
ValueType = 0x03, // TypeRepresentation
Value = 0x04, // object
}
}
@@ -0,0 +1,14 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace Esiur.Data.Types
{
[Flags]
public enum ConstantDefFlags : byte
{
None = 0x00,
Inherited = (byte)MemberDefFlags.Inherited,
Deprecated = (byte)MemberDefFlags.Deprecated,
}
}
+62 -59
View File
@@ -26,83 +26,86 @@ public class EventDef : MemberDef
return $"{Name}: {ArgumentType}";
}
public bool Subscribable { get; set; }
public bool AutoDelivered { get; set; }
public bool Deprecated { get; set; }
public EventInfo EventInfo { get; set; }
public Tru ArgumentType { get; set; }
public static async AsyncReply<ParseResult<EventDef>> ParseAsync(byte[] data, uint offset, byte index, bool inherited, EpConnection connection, ulong[] requestSequence)
{
var oOffset = offset;
//public static async AsyncReply<ParseResult<EventDef>> ParseAsync(byte[] data, uint offset, byte index, bool inherited, EpConnection connection, ulong[] requestSequence)
//{
// var oOffset = offset;
var hasAnnotation = ((data[offset] & 0x10) == 0x10);
var subscribable = ((data[offset++] & 0x8) == 0x8);
// var hasAnnotation = ((data[offset] & 0x10) == 0x10);
// var subscribable = ((data[offset++] & 0x8) == 0x8);
var name = data.GetString(offset + 1, data[offset]);
offset += (uint)data[offset] + 1;
// var name = data.GetString(offset + 1, data[offset]);
// offset += (uint)data[offset] + 1;
var argType = await Tru.ParseAsync(data, offset, connection, requestSequence);
// var argType = await Tru.ParseAsync(data, offset, connection, requestSequence);
offset += argType.Size;
// offset += argType.Size;
// Annotation ?
Map<string, string> annotations = null;
// // Annotation ?
// Map<string, string> annotations = null;
if (hasAnnotation)
{
var (len, anns) = Codec.ParseSync(data, offset, null);
// if (hasAnnotation)
// {
// var (len, anns) = Codec.ParseSync(data, offset, null);
if (anns is Map<string, string> map)
annotations = map;
// if (anns is Map<string, string> map)
// annotations = map;
offset += len;
}
// offset += len;
// }
return new ParseResult<EventDef>(new EventDef()
{
Index = index,
Name = name,
Inherited = inherited,
ArgumentType = argType.Value,
Subscribable = subscribable,
Annotations = annotations
}, offset - oOffset);
}
// return new ParseResult<EventDef>(new EventDef()
// {
// Index = index,
// Name = name,
// Inherited = inherited,
// ArgumentType = argType.Value,
// AutoDelivered = !subscribable,
// Annotations = annotations
// }, offset - oOffset);
//}
public byte[] Compose(EpConnection connection)
{
var name = Name.ToBytes();
//public byte[] Compose(EpConnection connection)
//{
// var name = Name.ToBytes();
var hdr = Inherited ? (byte)0x80 : (byte)0;
// var hdr = Inherited ? (byte)0x80 : (byte)0;
if (Subscribable)
hdr |= 0x8;
// if (Subscribable)
// hdr |= 0x8;
if (Annotations != null)
{
var exp = Codec.Compose(Annotations, connection.Instance.Warehouse, connection); //( DC.ToBytes(Annotation);
hdr |= 0x50;
return new BinaryList()
.AddUInt8(hdr)
.AddUInt8((byte)name.Length)
.AddUInt8Array(name)
.AddUInt8Array(ArgumentType.Compose(connection))
.AddInt32(exp.Length)
.AddUInt8Array(exp)
.ToArray();
}
else
hdr |= 0x40;
// if (Annotations != null)
// {
// var exp = Codec.Compose(Annotations, connection.Instance.Warehouse, connection); //( DC.ToBytes(Annotation);
// hdr |= 0x50;
// return new BinaryList()
// .AddUInt8(hdr)
// .AddUInt8((byte)name.Length)
// .AddUInt8Array(name)
// .AddUInt8Array(ArgumentType.Compose(connection))
// .AddInt32(exp.Length)
// .AddUInt8Array(exp)
// .ToArray();
// }
// else
// hdr |= 0x40;
return new BinaryList()
.AddUInt8(hdr)
.AddUInt8((byte)name.Length)
.AddUInt8Array(name)
.AddUInt8Array(ArgumentType.Compose(connection))
.ToArray();
}
// return new BinaryList()
// .AddUInt8(hdr)
// .AddUInt8((byte)name.Length)
// .AddUInt8Array(name)
// .AddUInt8Array(ArgumentType.Compose(connection))
// .ToArray();
//}
public static EventDef MakeEventDef(Warehouse warehouse, Type type, EventInfo ei, byte index, string name, TypeDef schema)
@@ -124,7 +127,7 @@ public class EventDef : MemberDef
throw new Exception($"Unsupported type `{argType}` in event `{type.Name}.{ei.Name}`");
var annotationAttrs = ei.GetCustomAttributes<AnnotationAttribute>(true);
var subscribableAttr = ei.GetCustomAttribute<SubscribableAttribute>(true);
var autoDeliveredAttr = ei.GetCustomAttribute<AutoDeliveredAttribute>(true);
//evtType.Nullable = new NullabilityInfoContext().Create(ei).ReadState is NullabilityState.Nullable;
@@ -175,7 +178,7 @@ public class EventDef : MemberDef
Inherited = ei.DeclaringType != type,
Annotations = annotations,
EventInfo = ei,
Subscribable = subscribableAttr != null
AutoDelivered = autoDeliveredAttr != null
};
}
@@ -0,0 +1,14 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace Esiur.Data.Types
{
public enum EventDefField : byte
{
ArgumentType = 0x03, // TypeRepresentation
ArgumentName = 0x04, // string
OrderingControl = 0x05, // OrderingControl
HistoryControl = 0x06, // HistoryControl
}
}
@@ -0,0 +1,17 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace Esiur.Data.Types
{
[Flags]
public enum EventDefFlags : byte
{
None = 0x00,
Inherited = (byte)MemberDefFlags.Inherited,
Deprecated = (byte)MemberDefFlags.Deprecated,
AutoDelivered = 0x04, // Delivered to attached clients without explicit subscription.
Historical = 0x08,
}
}
@@ -0,0 +1,14 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace Esiur.Data.Types
{
public enum ExampleField : byte
{
Title = 0x00, // string
Description = 0x01, // string
Arguments = 0x02, // Map<byte, object>
Result = 0x03, // object
}
}
@@ -30,6 +30,13 @@ public class FunctionDef : MemberDef
public Tru ReturnType { get; set; }
public bool IsStatic { get; set; }
public bool ReadOnly { get; set; }
public bool Idempotent { get; set; }
public bool Cancellable { get; set; }
public bool Deprecated { get; set; }
//public FunctionDefFlags Flags { get; set; }
public StreamMode StreamMode { get; set; }
public ArgumentDef[] Arguments { get; set; }
@@ -0,0 +1,13 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace Esiur.Data.Types
{
public enum FunctionDefField : byte
{
Arguments = 0x03, // List<Map<byte, object>>
ReturnType = 0x04, // TRU
StreamMode = 0x05, // StreamMode
}
}
@@ -0,0 +1,19 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace Esiur.Data.Types
{
[Flags]
public enum FunctionDefFlags : byte
{
None = 0x00,
Inherited = (byte)MemberDefFlags.Inherited,
Deprecated = (byte)MemberDefFlags.Deprecated,
Static = 0x04,
ReadOnly = 0x08,
Idempotent = 0x10,
Cancellable = 0x20,
}
}
+37 -35
View File
@@ -361,56 +361,58 @@ public class LocalTypeDef:TypeDef
}
public override byte[] Compose(EpConnection connection)
{
// bake it binarily
var b = new BinaryList();
//public override byte[] Compose(EpConnection connection)
//{
// // bake it binarily
// var b = new BinaryList();
// find the first parent type that implements IResource
// // find the first parent type that implements IResource
var hasParent = ParentTypeDef != null;
var hasClassAnnotation = Annotations != null && Annotations.Count() > 0;
// var hasParent = ParentTypeDef != null;
// var hasClassAnnotation = Annotations != null && Annotations.Count() > 0;
var typeNameBytes = DC.ToBytes(_typeName);
// var typeNameBytes = DC.ToBytes(_typeName);
b.AddUInt8((byte)((hasParent ? 0x80 : 0) | (hasClassAnnotation ? 0x40 : 0x0) | (byte)_typeDefKind))
.AddUInt64(_typeId)
.AddUInt8((byte)typeNameBytes.Length)
.AddUInt8Array(typeNameBytes);
// b.AddUInt8((byte)((hasParent ? 0x80 : 0) | (hasClassAnnotation ? 0x40 : 0x0) | (byte)_typeDefKind))
// .AddUInt64(_typeId)
// .AddUInt8((byte)typeNameBytes.Length)
// .AddUInt8Array(typeNameBytes);
if (hasParent)
{
b.AddUInt64(ParentTypeDef.Id);
}
// if (hasParent)
// {
// b.AddUInt64(ParentTypeDef.Id);
// }
if (hasClassAnnotation)
{
// if (hasClassAnnotation)
// {
//foreach (var ann in Annotations)
// Annotations.Add(ann.Key, ann.Value);
// //foreach (var ann in Annotations)
// // Annotations.Add(ann.Key, ann.Value);
var classAnnotationBytes = Codec.Compose(Annotations, connection.Instance.Warehouse, connection);
// var classAnnotationBytes = Codec.Compose(Annotations, connection.Instance.Warehouse, connection);
b.AddUInt8Array(classAnnotationBytes);
// b.AddUInt8Array(classAnnotationBytes);
}
// }
b.AddInt32(_version)
.AddUInt16((ushort)(_functions.Count + _properties.Count + _events.Count + _constants.Count));
// b.AddInt32(_version)
// .AddUInt16((ushort)(_functions.Count + _properties.Count + _events.Count + _constants.Count));
foreach (var ft in _functions)
b.AddUInt8Array(ft.Compose(connection ));
foreach (var pt in _properties)
b.AddUInt8Array(pt.Compose(connection));
foreach (var et in _events)
b.AddUInt8Array(et.Compose(connection));
foreach (var ct in _constants)
b.AddUInt8Array(ct.Compose(connection));
// foreach (var ft in _functions)
// b.AddUInt8Array(ft.Compose(connection ));
// foreach (var pt in _properties)
// b.AddUInt8Array(pt.Compose(connection));
// foreach (var et in _events)
// b.AddUInt8Array(et.Compose(connection));
// foreach (var ct in _constants)
// b.AddUInt8Array(ct.Compose(connection));
// return b.ToArray();
//}
return b.ToArray();
}
public static bool HasParent(Type type)
{
+47 -5
View File
@@ -9,13 +9,55 @@ namespace Esiur.Data.Types;
public class MemberDef
{
// Core fields
public byte Index { get; set; }
public string Name { get; set; }
public bool Inherited { get; set; }
public TypeDef Definition { get; set; }
public string Fullname => Definition.Name + "." + Name;
public string Name { get; set; } = string.Empty;
public bool Inherited { get; set; }
public TypeDef Definition { get; set; } = null!;
// Human-readable metadata
public string? Description { get; set; }
public string? Usage { get; set; }
public List<object>? Examples { get; set; }
public List<string>? Tags { get; set; }
// Value constraints and representation
public string? Unit { get; set; }
public object? Minimum { get; set; }
public object? Maximum { get; set; }
public List<object>? AllowedValues { get; set; }
public string? Pattern { get; set; }
public string? Format { get; set; }
// Operational semantics
public List<string>? Preconditions { get; set; }
public List<string>? Postconditions { get; set; }
public OperationEffects Effects { get; set; }
public List<string>? Warnings { get; set; }
public List<byte>? RelatedMembers { get; set; }
// Compatibility guidance
public string? DeprecationMessage { get; set; }
public string Fullname =>
Definition is null || string.IsNullOrEmpty(Definition.Name)
? Name
: $"{Definition.Name}.{Name}";
}
@@ -0,0 +1,38 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace Esiur.Data.Types
{
public enum MemberDefField : byte
{
// Core member fields
Index = 0x00, // byte
Name = 0x01, // string
Flags = 0x02, // byte: member-specific flags enum
// Human-readable metadata
Description = 0x20, // string
Usage = 0x21, // string
Examples = 0x22, // List<object>
Tags = 0x23, // List<string>
// Value constraints and representation
Unit = 0x24, // string
Minimum = 0x25, // object: same type as the value
Maximum = 0x26, // object: same type as the value
AllowedValues = 0x27, // List<object>
Pattern = 0x28, // string
Format = 0x29, // string
// Operational semantics
Preconditions = 0x2A, // List<string>
Postconditions = 0x2B, // List<string>
Effects = 0x2C, // OperationEffects
Warnings = 0x2D, // List<string>
RelatedMembers = 0x2E, // List<byte>: member indexes
// Compatibility guidance
DeprecationMessage = 0x2F, // string
}
}
@@ -0,0 +1,14 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace Esiur.Data.Types
{
[Flags]
public enum MemberDefFlags : byte
{
None = 0x00,
Inherited = 0x01, // Member is inherited from a parent TypeDef.
Deprecated = 0x02, // Member is retained for compatibility but should be avoided.
}
}
@@ -0,0 +1,30 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace Esiur.Data.Types
{
[Flags]
public enum OperationEffects : byte
{
None = 0x00,
// Changes one or more properties of the target resource.
ModifiesState = 0x01,
// Creates a resource or another persistent object.
CreatesResource = 0x02,
// Deletes or disposes a resource.
DeletesResource = 0x04,
// Produces externally visible output or communication.
External = 0x08,
// Emits events or notifications.
EmitsEvents = 0x10,
// Effects are not fully known or described.
Unknown = 0x80
}
}
+109 -111
View File
@@ -36,19 +36,18 @@ public class PropertyDef : MemberDef
*/
//bool ReadOnly;
//EPTypes::DataType ReturnType;
public PropertyPermission Permission
{
get;
set;
}
//public PropertyPermission Permission
//{
// get;
// set;
//}
public bool ReadOnly { get; set; }
public bool Constant { get; set; }
//public bool IsNullable { get; set; }
public bool HasHistory
{
get;
set;
}
public bool Historical { get; set; }
/*
public PropertyType Mode
@@ -81,124 +80,124 @@ public class PropertyDef : MemberDef
return $"{Name}: {ValueType}";
}
public static async AsyncReply<ParseResult<PropertyDef>> ParseAsync(byte[] data, uint offset, byte index, bool inherited, EpConnection connection, ulong[] requestSequence)
{
var oOffset = offset;
//public static async AsyncReply<ParseResult<PropertyDef>> ParseAsync(byte[] data, uint offset, byte index, bool inherited, EpConnection connection, ulong[] requestSequence)
//{
// var oOffset = offset;
var hasAnnotation = ((data[offset] & 0x8) == 0x8);
var hasHistory = ((data[offset] & 1) == 1);
var permission = (PropertyPermission)((data[offset++] >> 1) & 0x3);
var name = data.GetString(offset + 1, data[offset]);
// var hasAnnotation = ((data[offset] & 0x8) == 0x8);
// var hasHistory = ((data[offset] & 1) == 1);
// var permission = (PropertyPermission)((data[offset++] >> 1) & 0x3);
// var name = data.GetString(offset + 1, data[offset]);
//Console.WriteLine("Parsing propdef " + name);
// //Console.WriteLine("Parsing propdef " + name);
offset += (uint)data[offset] + 1;
// offset += (uint)data[offset] + 1;
var valueType = await Tru.ParseAsync(data, offset, connection, requestSequence);
// var valueType = await Tru.ParseAsync(data, offset, connection, requestSequence);
offset += valueType.Size;
// offset += valueType.Size;
Map<string, string> annotations = null;
// Map<string, string> annotations = null;
// arguments
if (hasAnnotation) // Annotation ?
{
var (len, anns) = Codec.ParseSync(data, offset, null);
// // arguments
// if (hasAnnotation) // Annotation ?
// {
// var (len, anns) = Codec.ParseSync(data, offset, null);
if (anns is Map<string, string> map)
annotations = map;
// if (anns is Map<string, string> map)
// annotations = map;
offset += len;
}
// offset += len;
// }
return new ParseResult<PropertyDef>(new PropertyDef()
{
Index = index,
Name = name,
Inherited = inherited,
Permission = permission,
HasHistory = hasHistory,
ValueType = valueType.Value,
Annotations = annotations
}, offset - oOffset);
// return new ParseResult<PropertyDef>(new PropertyDef()
// {
// Index = index,
// Name = name,
// Inherited = inherited,
// Permission = permission,
// HasHistory = hasHistory,
// ValueType = valueType.Value,
// Annotations = annotations
// }, offset - oOffset);
}
//}
public byte[] Compose(EpConnection connection)
{
var name = DC.ToBytes(Name);
//public byte[] Compose(EpConnection connection)
//{
// var name = DC.ToBytes(Name);
var pv = ((byte)(Permission) << 1) | (HasHistory ? 1 : 0);
// var pv = ((byte)(Permission) << 1) | (HasHistory ? 1 : 0);
if (Inherited)
pv |= 0x80;
// if (Inherited)
// pv |= 0x80;
//if (WriteAnnotation != null && ReadAnnotation != null)
//{
// var rexp = DC.ToBytes(ReadAnnotation);
// var wexp = DC.ToBytes(WriteAnnotation);
// return new BinaryList()
// .AddUInt8((byte)(0x38 | pv))
// .AddUInt8((byte)name.Length)
// .AddUInt8Array(name)
// .AddUInt8Array(ValueType.Compose())
// .AddInt32(wexp.Length)
// .AddUInt8Array(wexp)
// .AddInt32(rexp.Length)
// .AddUInt8Array(rexp)
// .ToArray();
//}
//else if (WriteAnnotation != null)
//{
// var wexp = DC.ToBytes(WriteAnnotation);
// return new BinaryList()
// .AddUInt8((byte)(0x30 | pv))
// .AddUInt8((byte)name.Length)
// .AddUInt8Array(name)
// .AddUInt8Array(ValueType.Compose())
// .AddInt32(wexp.Length)
// .AddUInt8Array(wexp)
// .ToArray();
//}
//else if (ReadAnnotation != null)
//{
// var rexp = DC.ToBytes(ReadAnnotation);
// return new BinaryList()
// .AddUInt8((byte)(0x28 | pv))
// .AddUInt8((byte)name.Length)
// .AddUInt8Array(name)
// .AddUInt8Array(ValueType.Compose())
// .AddInt32(rexp.Length)
// .AddUInt8Array(rexp)
// .ToArray();
//}
if (Annotations != null)
{
var rexp = Codec.Compose(Annotations, connection.Instance.Warehouse, connection);
return new BinaryList()
.AddUInt8((byte)(0x28 | pv))
.AddUInt8((byte)name.Length)
.AddUInt8Array(name)
.AddUInt8Array(ValueType.Compose(connection))
.AddUInt8Array(rexp)
.ToArray();
}
else
{
return new BinaryList()
.AddUInt8((byte)(0x20 | pv))
.AddUInt8((byte)name.Length)
.AddUInt8Array(name)
.AddUInt8Array(ValueType.Compose(connection))
.ToArray();
}
}
// //if (WriteAnnotation != null && ReadAnnotation != null)
// //{
// // var rexp = DC.ToBytes(ReadAnnotation);
// // var wexp = DC.ToBytes(WriteAnnotation);
// // return new BinaryList()
// // .AddUInt8((byte)(0x38 | pv))
// // .AddUInt8((byte)name.Length)
// // .AddUInt8Array(name)
// // .AddUInt8Array(ValueType.Compose())
// // .AddInt32(wexp.Length)
// // .AddUInt8Array(wexp)
// // .AddInt32(rexp.Length)
// // .AddUInt8Array(rexp)
// // .ToArray();
// //}
// //else if (WriteAnnotation != null)
// //{
// // var wexp = DC.ToBytes(WriteAnnotation);
// // return new BinaryList()
// // .AddUInt8((byte)(0x30 | pv))
// // .AddUInt8((byte)name.Length)
// // .AddUInt8Array(name)
// // .AddUInt8Array(ValueType.Compose())
// // .AddInt32(wexp.Length)
// // .AddUInt8Array(wexp)
// // .ToArray();
// //}
// //else if (ReadAnnotation != null)
// //{
// // var rexp = DC.ToBytes(ReadAnnotation);
// // return new BinaryList()
// // .AddUInt8((byte)(0x28 | pv))
// // .AddUInt8((byte)name.Length)
// // .AddUInt8Array(name)
// // .AddUInt8Array(ValueType.Compose())
// // .AddInt32(rexp.Length)
// // .AddUInt8Array(rexp)
// // .ToArray();
// //}
// if (Annotations != null)
// {
// var rexp = Codec.Compose(Annotations, connection.Instance.Warehouse, connection);
// return new BinaryList()
// .AddUInt8((byte)(0x28 | pv))
// .AddUInt8((byte)name.Length)
// .AddUInt8Array(name)
// .AddUInt8Array(ValueType.Compose(connection))
// .AddUInt8Array(rexp)
// .ToArray();
// }
// else
// {
// return new BinaryList()
// .AddUInt8((byte)(0x20 | pv))
// .AddUInt8((byte)name.Length)
// .AddUInt8Array(name)
// .AddUInt8Array(ValueType.Compose(connection))
// .ToArray();
// }
//}
public static PropertyDef MakePropertyDef(Warehouse warehouse, Type type, PropertyInfo pi, string name, byte index, PropertyPermission permission, TypeDef schema)
public static PropertyDef MakePropertyDef(Warehouse warehouse, Type type, PropertyInfo pi, string name, byte index, TypeDef typeDef)
{
var genericPropType = pi.PropertyType.IsGenericType ? pi.PropertyType.GetGenericTypeDefinition() : null;
// @TODO: need to check if the type is remote
@@ -211,7 +210,7 @@ public class PropertyDef : MemberDef
throw new Exception($"Unsupported type `{pi.PropertyType}` in property `{type.Name}.{pi.Name}`");
var annotationAttrs = pi.GetCustomAttributes<AnnotationAttribute>(true);
var storageAttr = pi.GetCustomAttribute<StorageAttribute>(true);
var historicalAttr = pi.GetCustomAttribute<HistoricalAttribute>(true);
//var nullabilityContext = new NullabilityInfoContext();
//propType.Nullable = nullabilityContext.Create(pi).ReadState is NullabilityState.Nullable;
@@ -267,8 +266,7 @@ public class PropertyDef : MemberDef
Inherited = pi.DeclaringType != type,
ValueType = propType,
PropertyInfo = pi,
HasHistory = storageAttr == null ? false : storageAttr.Mode == StorageMode.History,
Permission = permission,
Historical = historicalAttr == null,
Annotations = annotations,
};
@@ -0,0 +1,14 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace Esiur.Data.Types
{
public enum PropertyDefField : byte
{
ValueType = 0x03, // TypeRepresentation
OrderingControl = 0x04, // OrderingControl
HistoryControl = 0x05, // HistoryControl
DefaultValue = 0x06, // object
}
}
@@ -0,0 +1,19 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace Esiur.Data.Types
{
[Flags]
public enum PropertyDefFlags : byte
{
None = 0x00,
Inherited = (byte)MemberDefFlags.Inherited,
Deprecated = (byte)MemberDefFlags.Deprecated,
ReadOnly = 0x04, // Property cannot be changed by remote Set.
Constant = 0x08, // Property has a constant valu
Volatile = 0x10, // Value may change but is not necessarily synchronized.
Historical = 0x20, // Previous values are retained and may be fetched.
}
}
+14
View File
@@ -0,0 +1,14 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace Esiur.Data.Types
{
[Flags]
public enum StreamMode:byte
{
None = 0,
Push = 0x1, // Stream is in push mode, where data is sent from the source to the destination.
Pull = 0x2, // Stream is in pull mode, where data is requested from the source by the destination.
}
}
-14
View File
@@ -32,16 +32,7 @@ public class TypeDef
protected int _version;
protected TypeDefKind _typeDefKind;
//Type _definedType { get; set; }
//Type _proxyType { get; set; }
//Type _parentDefinedType { get; set; }
//bool _isLocal;
//public Type DefinedType => _definedType;
//public Type ParentDefinedType => _parentDefinedType;
//public Type ProxyType => _proxyType;
public override string ToString()
{
@@ -53,13 +44,8 @@ public class TypeDef
public ulong? ParentTypeId => _parentTypeId;
//public byte[] Content => _content;
public TypeDefKind Kind => _typeDefKind;
public EventDef GetEventDefByName(string eventName)
{
foreach (var i in _events)
@@ -0,0 +1,27 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace Esiur.Data.Types
{
public enum TypeDefField : byte
{
Version = 0x00,
Id = 0x01,
Name = 0x02,
Namespace = 0x03,
Kind = 0x04,
Parent = 0x05,
Properties = 0x06,
Functions = 0x07,
Events = 0x08,
Constants = 0x09,
Usage = 0x20,
Description = 0x21,
Example = 0x22,
Category = 0x23,
Since = 0x24,
Annotations = 0x25,
}
}
@@ -29,12 +29,15 @@ using System.Threading.Tasks;
namespace Esiur.Resource;
[AttributeUsage(AttributeTargets.Event)]
public class SubscribableAttribute : System.Attribute
/// <summary>
/// Indicates that an event is delivered to attached clients without
/// requiring an explicit subscription.
/// </summary>
[AttributeUsage(
AttributeTargets.Event |
AttributeTargets.Field,
AllowMultiple = false,
Inherited = true)]
public sealed class AutoDeliveredAttribute : Attribute
{
public SubscribableAttribute()
{
}
}
}
@@ -0,0 +1,17 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace Esiur.Resource
{
/// <summary>
/// Indicates that a running remote invocation may be cancelled.
/// </summary>
[AttributeUsage(
AttributeTargets.Method,
AllowMultiple = false,
Inherited = true)]
public sealed class CancellableAttribute : Attribute
{
}
}
@@ -0,0 +1,20 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace Esiur.Resource
{
/// <summary>
/// Indicates that previous values of an exported property are retained
/// and may be fetched remotely.
/// </summary>
[AttributeUsage(
AttributeTargets.Property |
AttributeTargets.Field,
AllowMultiple = false,
Inherited = true)]
public sealed class HistoricalAttribute : Attribute
{
}
}
@@ -0,0 +1,19 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace Esiur.Resource
{
/// <summary>
/// Indicates that repeating the same invocation should have the same
/// externally observable effect as invoking it once.
/// </summary>
[AttributeUsage(
AttributeTargets.Method,
AllowMultiple = false,
Inherited = true)]
public sealed class IdempotentAttribute : Attribute
{
}
}
@@ -0,0 +1,28 @@
using Esiur.Data;
using System;
using System.Collections.Generic;
using System.Text;
namespace Esiur.Resource
{
/// <summary>
/// Specifies non-default notification ordering for a property or event.
/// Absence of this attribute means strict ordering.
/// </summary>
[AttributeUsage(
AttributeTargets.Property |
AttributeTargets.Field |
AttributeTargets.Event,
AllowMultiple = false,
Inherited = true)]
public sealed class OrderingAttribute : Attribute
{
public OrderingControl Control { get; }
public OrderingAttribute(OrderingControl control)
{
Control = control;
}
}
}
@@ -0,0 +1,21 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace Esiur.Resource
{
/// <summary>
/// Indicates that an exported function does not change resource state,
/// or that an exported property cannot be changed remotely.
/// </summary>
[AttributeUsage(
AttributeTargets.Method |
AttributeTargets.Property |
AttributeTargets.Field,
AllowMultiple = false,
Inherited = true)]
public sealed class ReadOnlyAttribute : Attribute
{
}
}
@@ -0,0 +1,34 @@
using Esiur.Data.Types;
using System;
using System.Collections.Generic;
using System.Text;
namespace Esiur.Resource
{
/// <summary>
/// Marks an exported function as streaming and specifies its delivery mode.
/// </summary>
[AttributeUsage(
AttributeTargets.Method,
AllowMultiple = false,
Inherited = true)]
public sealed class StreamAttribute : Attribute
{
/// <summary>
/// Gets the stream delivery mode.
/// </summary>
public StreamMode Mode { get; }
/// <summary>
/// Indicates whether a push stream may be paused and resumed remotely.
/// This should only be true when Mode is Push.
/// </summary>
public bool Pausable { get; set; }
public StreamAttribute(StreamMode mode = StreamMode.Push)
{
Mode = mode;
}
}
}
@@ -0,0 +1,35 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace Esiur.Resource.Attributes
{
[AttributeUsage(
AttributeTargets.Class |
AttributeTargets.Struct |
AttributeTargets.Interface |
AttributeTargets.Enum |
AttributeTargets.Delegate |
AttributeTargets.Method |
AttributeTargets.Property |
AttributeTargets.Field |
AttributeTargets.Event |
AttributeTargets.Parameter |
AttributeTargets.ReturnValue,
AllowMultiple = false,
Inherited = true)]
public sealed class UsageAttribute : Attribute
{
public string Value { get; }
public UsageAttribute(string value)
{
if (string.IsNullOrWhiteSpace(value))
throw new ArgumentException(
"Usage text cannot be null or empty.",
nameof(value));
Value = value;
}
}
}
@@ -0,0 +1,20 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace Esiur.Resource.Attributes
{
/// <summary>
/// Indicates that an exported property has volatile synchronization
/// semantics. This is unrelated to the C# volatile memory modifier.
/// </summary>
[AttributeUsage(
AttributeTargets.Property |
AttributeTargets.Field,
AllowMultiple = false,
Inherited = true)]
public sealed class VolatileAttribute : Attribute
{
}
}
@@ -4,10 +4,10 @@ using System.Text;
namespace Esiur.Resource
{
public enum PropertyPermission : byte
{
Read = 1,
Write,
ReadWrite,
}
//public enum PropertyPermission : byte
//{
// ReadOnly = 0,
// Write,
// ReadWrite,
//}
}