mirror of
https://github.com/esiur/esiur-dotnet.git
synced 2026-07-30 17:30:40 +00:00
Types
This commit is contained in:
@@ -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)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -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.
|
||||
}
|
||||
}
|
||||
@@ -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,
|
||||
}
|
||||
}
|
||||
@@ -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,
|
||||
}
|
||||
}
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
@@ -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.
|
||||
}
|
||||
}
|
||||
@@ -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.
|
||||
}
|
||||
}
|
||||
@@ -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,
|
||||
}
|
||||
}
|
||||
+11
-8
@@ -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,
|
||||
//}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user