diff --git a/Esiur/Proxy/TemplateGenerator.cs b/Esiur/Proxy/TemplateGenerator.cs index 82dac01..3985ae8 100644 --- a/Esiur/Proxy/TemplateGenerator.cs +++ b/Esiur/Proxy/TemplateGenerator.cs @@ -11,6 +11,7 @@ using Esiur.Net.IIP; using System.Diagnostics; namespace Esiur.Proxy; + public static class TemplateGenerator { internal static Regex urlRegex = new Regex(@"^(?:([\S]*)://([^/]*)/?)"); @@ -300,8 +301,13 @@ public static class TemplateGenerator var positionalArgs = f.Arguments.Where((x) => !x.Optional).ToArray(); var optionalArgs = f.Arguments.Where((x) => x.Optional).ToArray(); - if (f.Annotation != null) - rt.AppendLine($"[Annotation({ToLiteral(f.Annotation)})]"); + if (f.Annotations != null) + { + foreach (var kv in f.Annotations) + { + rt.AppendLine($"[Annotation({ToLiteral(kv.Key)}, {ToLiteral(kv.Value)})]"); + } + } if (f.IsStatic) { diff --git a/Esiur/Resource/AnnotationAttribute.cs b/Esiur/Resource/AnnotationAttribute.cs index 2372e8c..8a21b08 100644 --- a/Esiur/Resource/AnnotationAttribute.cs +++ b/Esiur/Resource/AnnotationAttribute.cs @@ -4,17 +4,26 @@ using System.Text; namespace Esiur.Resource; -[AttributeUsage(AttributeTargets.Interface | AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Method | AttributeTargets.Event)] +[AttributeUsage(AttributeTargets.Interface | AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Method | AttributeTargets.Event, AllowMultiple = true)] public class AnnotationAttribute : Attribute { - public string Annotation { get; set; } + public readonly string? Key; + public readonly string Value; + public AnnotationAttribute(string annotation) { - this.Annotation = annotation; + Key = null; + Value = annotation; } - public AnnotationAttribute(params string[] annotations) + public AnnotationAttribute(string key, string value) { - this.Annotation = String.Join("\n", annotations); + Key = key; + Value = value; } + + //public AnnotationAttribute(params string[] annotations) + //{ + // this.Annotation = String.Join("\n", annotations); + //} } diff --git a/Esiur/Resource/Template/ArgumentTemplate.cs b/Esiur/Resource/Template/ArgumentTemplate.cs index e0367a0..62d3b27 100644 --- a/Esiur/Resource/Template/ArgumentTemplate.cs +++ b/Esiur/Resource/Template/ArgumentTemplate.cs @@ -5,6 +5,7 @@ using System.Text; using System.Reflection; namespace Esiur.Resource.Template; + public class ArgumentTemplate { public string Name { get; set; } @@ -17,16 +18,32 @@ public class ArgumentTemplate public int Index { get; set; } + public Map Annotations { get; set; } + public static (uint, ArgumentTemplate) Parse(byte[] data, uint offset, int index) { - var optional = (data[offset++] & 0x1) == 0x1; + var optional = (data[offset] & 0x1) == 0x1; + var hasAnnotations = (data[offset++] & 0x2) == 0x2; var cs = (uint)data[offset++]; var name = data.GetString(offset, cs); offset += cs; var (size, type) = TRU.Parse(data, offset); - return (cs + 2 + size, new ArgumentTemplate(name, index, type, optional)); + + Map annotations = null; + + if (hasAnnotations) + { + var acs = data.GetUInt32(offset, Endian.Little); + offset += 2; + var (l, a) = Codec.ParseSync(data, offset, null); + // for saftey, Map might change in the future + if (a is Map ann) + annotations = ann; + } + + return (cs + 2 + size, new ArgumentTemplate(name, index, type, optional, annotations)); } public ArgumentTemplate() @@ -34,23 +51,49 @@ public class ArgumentTemplate } - public ArgumentTemplate(string name, int index, TRU type, bool optional) + public ArgumentTemplate(string name, int index, TRU type, bool optional, Map annotations) { Name = name; Index = index; Type = type; Optional = optional; + Annotations = annotations; + } + + public override string ToString() + { + if (Optional) + return $"[{Name}: {Type}]"; + else + return $"{Name}: {Type} "; } public byte[] Compose() { var name = DC.ToBytes(Name); - return new BinaryList() - .AddUInt8(Optional ? (byte)1 : (byte)0) - .AddUInt8((byte)name.Length) - .AddUInt8Array(name) - .AddUInt8Array(Type.Compose()) - .ToArray(); + if (Annotations == null) + { + return new BinaryList() + .AddUInt8(Optional ? (byte)1 : (byte)0) + .AddUInt8((byte)name.Length) + .AddUInt8Array(name) + .AddUInt8Array(Type.Compose()) + .ToArray(); + } + else + { + var exp = Codec.Compose(Annotations, null, null); + + return new BinaryList() + .AddUInt8((byte)(0x2 | (Optional ? 1 : 0))) + .AddUInt8((byte)name.Length) + .AddUInt8Array(name) + .AddUInt8Array(Type.Compose()) + .AddUInt32((ushort)exp.Length) + .AddUInt8Array(exp) + .ToArray(); + + } } } diff --git a/Esiur/Resource/Template/AttributeTemplate.cs b/Esiur/Resource/Template/AttributeTemplate.cs index 8bdc473..214d96a 100644 --- a/Esiur/Resource/Template/AttributeTemplate.cs +++ b/Esiur/Resource/Template/AttributeTemplate.cs @@ -7,6 +7,7 @@ using System.Text; using System.Threading.Tasks; namespace Esiur.Resource.Template; + public class AttributeTemplate : MemberTemplate { public PropertyInfo PropertyInfo diff --git a/Esiur/Resource/Template/ConstantTemplate.cs b/Esiur/Resource/Template/ConstantTemplate.cs index 6e876d3..f5eea7d 100644 --- a/Esiur/Resource/Template/ConstantTemplate.cs +++ b/Esiur/Resource/Template/ConstantTemplate.cs @@ -10,16 +10,16 @@ namespace Esiur.Resource.Template; public class ConstantTemplate : MemberTemplate { public readonly object Value; - //public readonly byte[] ValueData; - public readonly string Annotation; + + public Map Annotations; public readonly TRU ValueType; public FieldInfo FieldInfo { get; set; } - public ConstantTemplate(TypeTemplate template, byte index, string name, bool inherited, TRU valueType, object value, string annotation) + public ConstantTemplate(TypeTemplate template, byte index, string name, bool inherited, TRU valueType, object value, Map annotations) : base(template, index, name, inherited) { - Annotation = annotation; + Annotations = annotations; ValueType = valueType; Value = value; //try @@ -40,9 +40,9 @@ public class ConstantTemplate : MemberTemplate var hdr = Inherited ? (byte)0x80 : (byte)0; - if (Annotation != null) + if (Annotations != null) { - var exp = DC.ToBytes(Annotation); + var exp = Codec.Compose(Annotations, null, null);// DC.ToBytes(Annotation); hdr |= 0x70; return new BinaryList() .AddUInt8(hdr) @@ -71,7 +71,7 @@ public class ConstantTemplate : MemberTemplate public static ConstantTemplate MakeConstantTemplate(Type type, FieldInfo ci, byte index = 0, string customName = null, TypeTemplate typeTemplate = null) { - var annotationAttr = ci.GetCustomAttribute(true); + var annotationAttrs = ci.GetCustomAttributes(true); var valueType = TRU.FromType(ci.FieldType); @@ -83,7 +83,17 @@ public class ConstantTemplate : MemberTemplate if (typeTemplate?.Type == TemplateType.Enum) value = Convert.ChangeType(value, ci.FieldType.GetEnumUnderlyingType()); - var ct = new ConstantTemplate(typeTemplate, index, customName ?? ci.Name, ci.DeclaringType != type, valueType, value, annotationAttr?.Annotation); + Map annotations = null; + + if (annotationAttrs != null && annotationAttrs.Count() > 0) + { + annotations = new Map(); + foreach (var attr in annotationAttrs) + annotations.Add(attr.Key, attr.Value); + } + + + var ct = new ConstantTemplate(typeTemplate, index, customName ?? ci.Name, ci.DeclaringType != type, valueType, value, annotations); ct.FieldInfo = ci; return ct; diff --git a/Esiur/Resource/Template/EventTemplate.cs b/Esiur/Resource/Template/EventTemplate.cs index b782997..3713ab2 100644 --- a/Esiur/Resource/Template/EventTemplate.cs +++ b/Esiur/Resource/Template/EventTemplate.cs @@ -9,14 +9,20 @@ using System.Text; using System.Threading.Tasks; namespace Esiur.Resource.Template; + public class EventTemplate : MemberTemplate { - public string Annotation + public Map Annotations { get; set; } + public override string ToString() + { + return $"{Name}: {ArgumentType}"; + } + public bool Subscribable { get; set; } public EventInfo EventInfo { get; set; } @@ -32,9 +38,9 @@ public class EventTemplate : MemberTemplate if (Subscribable) hdr |= 0x8; - if (Annotation != null) + if (Annotations != null) { - var exp = DC.ToBytes(Annotation); + var exp = Codec.Compose(Annotations, null, null); //( DC.ToBytes(Annotation); hdr |= 0x50; return new BinaryList() .AddUInt8(hdr) @@ -47,6 +53,7 @@ public class EventTemplate : MemberTemplate } else hdr |= 0x40; + return new BinaryList() .AddUInt8(hdr) .AddUInt8((byte)name.Length) @@ -55,10 +62,10 @@ public class EventTemplate : MemberTemplate .ToArray(); } - public EventTemplate(TypeTemplate template, byte index, string name, bool inherited, TRU argumentType, string annotation = null, bool subscribable = false) + public EventTemplate(TypeTemplate template, byte index, string name, bool inherited, TRU argumentType, Map annotations = null, bool subscribable = false) : base(template, index, name, inherited) { - this.Annotation = annotation; + this.Annotations = annotations; this.Subscribable = subscribable; this.ArgumentType = argumentType; } @@ -80,7 +87,7 @@ public class EventTemplate : MemberTemplate if (evtType == null) throw new Exception($"Unsupported type `{argType}` in event `{type.Name}.{ei.Name}`"); - var annotationAttr = ei.GetCustomAttribute(true); + var annotationAttrs = ei.GetCustomAttributes(true); var subscribableAttr = ei.GetCustomAttribute(true); //evtType.Nullable = new NullabilityInfoContext().Create(ei).ReadState is NullabilityState.Nullable; @@ -117,8 +124,13 @@ public class EventTemplate : MemberTemplate var et = new EventTemplate(typeTemplate, index, customName ?? ei.Name, ei.DeclaringType != type, evtType); et.EventInfo = ei; - if (annotationAttr != null) - et.Annotation = annotationAttr.Annotation; + + if (annotationAttrs != null && annotationAttrs.Count() > 0) + { + et.Annotations = new Map(); + foreach (var attr in annotationAttrs) + et.Annotations.Add(attr.Key, attr.Value); + } if (subscribableAttr != null) et.Subscribable = true; diff --git a/Esiur/Resource/Template/FunctionTemplate.cs b/Esiur/Resource/Template/FunctionTemplate.cs index a0e45ef..b5635e5 100644 --- a/Esiur/Resource/Template/FunctionTemplate.cs +++ b/Esiur/Resource/Template/FunctionTemplate.cs @@ -13,7 +13,7 @@ namespace Esiur.Resource.Template; public class FunctionTemplate : MemberTemplate { - public string Annotation + public Map Annotations { get; set; @@ -53,9 +53,9 @@ public class FunctionTemplate : MemberTemplate bl.AddUInt8Array(Arguments[i].Compose()); - if (Annotation != null) + if (Annotations != null) { - var exp = DC.ToBytes(Annotation); + var exp = Codec.Compose(Annotations, null, null);// DC.ToBytes(Annotation); bl.AddInt32(exp.Length) .AddUInt8Array(exp); bl.InsertUInt8(0, (byte)((Inherited ? (byte)0x90 : (byte)0x10) | (IsStatic ? 0x4 : 0))); @@ -66,12 +66,12 @@ public class FunctionTemplate : MemberTemplate return bl.ToArray(); } - public FunctionTemplate(TypeTemplate template, byte index, string name, bool inherited, bool isStatic, ArgumentTemplate[] arguments, TRU returnType, string annotation = null) + public FunctionTemplate(TypeTemplate template, byte index, string name, bool inherited, bool isStatic, ArgumentTemplate[] arguments, TRU returnType, Map annotations = null) : base(template, index, name, inherited) { this.Arguments = arguments; this.ReturnType = returnType; - this.Annotation = annotation; + this.Annotations = annotations; this.IsStatic = isStatic; } @@ -105,7 +105,7 @@ public class FunctionTemplate : MemberTemplate if (rtType == null) throw new Exception($"Unsupported type `{mi.ReturnType}` in method `{type.Name}.{mi.Name}` return"); - var annotationAttr = mi.GetCustomAttribute(true); + var annotationAttrs = mi.GetCustomAttributes(true); //var nullabilityInfoContext = new NullabilityInfoContext(); //rtType.Nullable = nullabilityInfoContext.Create(mi.ReturnParameter).WriteState is NullabilityState.Nullable; @@ -174,17 +174,13 @@ public class FunctionTemplate : MemberTemplate if (argType == null) throw new Exception($"Unsupported type `{x.ParameterType}` in method `{type.Name}.{mi.Name}` parameter `{x.Name}`"); - //argType.Nullable = nullabilityInfoContext.Create(x).WriteState is NullabilityState.Nullable; - //var argNullableAttr = x.GetCustomAttribute(true); - //var argNullableContextAttr = x.GetCustomAttribute(true) ?? nullableContextAttr; + var argAnnotationAttrs = x.GetCustomAttributes(true); + var argNullableAttr = x.GetCustomAttributes(true).FirstOrDefault(x => x.GetType().FullName == "System.Runtime.CompilerServices.NullableAttribute"); var argNullableContextAttr = x.GetCustomAttributes(true).FirstOrDefault(x => x.GetType().FullName == "System.Runtime.CompilerServices.NullableContextAttr"); - //var argFlags = argNullableAttr?.Flags?.ToList() ?? new List(); - //var argFlags = ((byte[])argNullableAttr?.NullableFlags ?? new byte[0]).ToList(); - var argNullableAttrFlags = (argNullableAttr?.GetType().GetField("NullableFlags")?.GetValue(argNullableAttr) as byte[] ?? new byte[0]).ToList(); var argNullableContextAttrFlag = (byte)(argNullableAttr?.GetType().GetField("Flag")?.GetValue(argNullableAttr) ?? (byte)0); @@ -203,12 +199,22 @@ public class FunctionTemplate : MemberTemplate argType.SetNull(argNullableAttrFlags); } + Map argAnn = null; + + if (argAnnotationAttrs != null && argAnnotationAttrs.Count() > 0) + { + argAnn = new Map(); + foreach (var attr in argAnnotationAttrs) + argAnn.Add(attr.Key, attr.Value); + } + return new ArgumentTemplate() { Name = x.Name, Type = argType, ParameterInfo = x, - Optional = x.IsOptional + Optional = x.IsOptional, + Annotations = argAnn }; }) .ToArray(); @@ -219,10 +225,21 @@ public class FunctionTemplate : MemberTemplate mi.IsStatic, arguments, rtType); - if (annotationAttr != null) - ft.Annotation = annotationAttr.Annotation; + + if (annotationAttrs != null && annotationAttrs.Count() > 0) + { + ft.Annotations = new Map(); + foreach (var attr in annotationAttrs) + ft.Annotations.Add(attr.Key, attr.Value); + } else - ft.Annotation = "(" + String.Join(",", mi.GetParameters().Where(x => x.ParameterType != typeof(DistributedConnection)).Select(x => "[" + x.ParameterType.Name + "] " + x.Name)) + ") -> " + mi.ReturnType.Name; + { + ft.Annotations = new Map(); + ft.Annotations.Add(null, "(" + String.Join(",", + mi.GetParameters().Where(x => x.ParameterType != typeof(DistributedConnection)) + .Select(x => "[" + x.ParameterType.Name + "] " + x.Name)) + ") -> " + mi.ReturnType.Name); + + } ft.MethodInfo = mi; // functions.Add(ft); @@ -230,4 +247,11 @@ public class FunctionTemplate : MemberTemplate return ft; } + public override string ToString() + { + //return = "(" + String.Join(",", mi.GetParameters().Where(x => x.ParameterType != typeof(DistributedConnection)).Select(x => "[" + x.ParameterType.Name + "] " + x.Name)) + ") -> " + mi.ReturnType.Name; + + return $"{ReturnType} {Name}({string.Join(", ", Arguments.Select(a => a.ToString()))})"; + } + } diff --git a/Esiur/Resource/Template/PropertyTemplate.cs b/Esiur/Resource/Template/PropertyTemplate.cs index c7a4855..ddcfae9 100644 --- a/Esiur/Resource/Template/PropertyTemplate.cs +++ b/Esiur/Resource/Template/PropertyTemplate.cs @@ -76,6 +76,10 @@ public class PropertyTemplate : MemberTemplate set; }*/ + public override string ToString() + { + return $"{Name}: {ValueType}"; + } public override byte[] Compose() {