Skip to content

Commit

Permalink
Merge pull request #29 from lillo42/master
Browse files Browse the repository at this point in the history
Merge with master
  • Loading branch information
lillo42 authored Feb 28, 2020
2 parents ec93178 + a55b248 commit fcc8011
Show file tree
Hide file tree
Showing 18 changed files with 1,409 additions and 284 deletions.
17 changes: 17 additions & 0 deletions src/Mozilla.IoT.WebThing/Attributes/ThingParameterAttribute.cs
Original file line number Diff line number Diff line change
Expand Up @@ -62,5 +62,22 @@ public double ExclusiveMaximum
get => ExclusiveMaximumValue ?? 0;
set => ExclusiveMaximumValue = value;
}


internal uint? MinimumLengthValue { get; set; }
public uint MinimumLength
{
get => MinimumLengthValue.GetValueOrDefault();
set => MinimumLengthValue = value;
}

internal uint? MaximumLengthValue { get; set; }
public uint MaximumLength
{
get => MaximumLengthValue.GetValueOrDefault();
set => MaximumLengthValue = value;
}

public string? Pattern { get; set; }
}
}
16 changes: 16 additions & 0 deletions src/Mozilla.IoT.WebThing/Attributes/ThingPropertyAttribute.cs
Original file line number Diff line number Diff line change
Expand Up @@ -55,5 +55,21 @@ public double ExclusiveMaximum
get => ExclusiveMaximumValue ?? 0;
set => ExclusiveMaximumValue = value;
}

internal uint? MinimumLengthValue { get; set; }
public uint MinimumLength
{
get => MinimumLengthValue.GetValueOrDefault();
set => MinimumLengthValue = value;
}

internal uint? MaximumLengthValue { get; set; }
public uint MaximumLength
{
get => MaximumLengthValue.GetValueOrDefault();
set => MaximumLengthValue = value;
}

public string? Pattern { get; set; }
}
}
126 changes: 110 additions & 16 deletions src/Mozilla.IoT.WebThing/Factories/Generator/Actions/ActionIntercept.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
using System.Linq;
using System.Reflection;
using System.Reflection.Emit;
using System.Text.RegularExpressions;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
Expand All @@ -15,6 +16,12 @@ namespace Mozilla.IoT.WebThing.Factories.Generator.Actions
{
public class ActionIntercept : IActionIntercept
{
private static readonly MethodInfo s_getLength = typeof(string).GetProperty(nameof(string.Length)).GetMethod;
private static readonly MethodInfo s_match = typeof(Regex).GetMethod(nameof(Regex.Match) , new [] { typeof(string) });
private static readonly MethodInfo s_success = typeof(Match).GetProperty(nameof(Match.Success)).GetMethod;
private static readonly ConstructorInfo s_regexConstructor = typeof(Regex).GetConstructors()[1];

private readonly ICollection<(string pattern, FieldBuilder field)> _regex = new LinkedList<(string pattern, FieldBuilder field)>();
private const MethodAttributes s_getSetAttributes =
MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.HideBySig;

Expand Down Expand Up @@ -70,14 +77,34 @@ public void Intercept(Thing thing, MethodInfo action, ThingActionAttribute? acti
&& x.ParameterType != typeof(CancellationToken))
.Select(x => x.ParameterType)
.ToArray());
var isValidIl = isValid.GetILGenerator();

CreateParameterValidation(isValidIl, parameters);
var isValidIl = isValid.GetILGenerator();
CreateParameterValidation(isValidIl, parameters, actionBuilder);
CreateInputValidation(actionBuilder, inputBuilder, isValid, input);
CreateExecuteAsync(actionBuilder, inputBuilder,input, action, thingType);

CreateStaticConstructor(actionBuilder);

Actions.Add(_option.PropertyNamingPolicy.ConvertName(name), new ActionContext(actionBuilder.CreateType()!));
}

private void CreateStaticConstructor(TypeBuilder typeBuilder)
{
if (_regex.Count > 0)
{
var constructor = typeBuilder.DefineTypeInitializer();
var il = constructor.GetILGenerator();

foreach (var (pattern, field) in _regex)
{
il.Emit(OpCodes.Ldstr, pattern);
il.Emit(OpCodes.Ldc_I4_8);
il.Emit(OpCodes.Newobj, s_regexConstructor);
il.Emit(OpCodes.Stsfld, field);
}

il.Emit(OpCodes.Ret);
}
}

private static PropertyBuilder CreateProperty(TypeBuilder builder, string fieldName, Type type)
{
Expand Down Expand Up @@ -147,7 +174,7 @@ private static void CreateInputValidation(TypeBuilder builder, TypeBuilder input
isInputValid.Emit(OpCodes.Ret);
}

private static void CreateParameterValidation(ILGenerator il, ParameterInfo[] parameters)
private void CreateParameterValidation(ILGenerator il, ParameterInfo[] parameters, TypeBuilder typeBuilder)
{
Label? next = null;
for (var i = 0; i < parameters.Length; i++)
Expand Down Expand Up @@ -228,6 +255,44 @@ private static void CreateParameterValidation(ILGenerator il, ParameterInfo[] pa
il.Emit(OpCodes.Ret);
}
}
else if (IsString(parameter.ParameterType))
{
if (validationParameter.MinimumLengthValue.HasValue)
{
GenerateStringLengthValidation(il, i, validationParameter.MinimumLengthValue.Value, OpCodes.Bge_S, ref next);
}

if (validationParameter.MaximumLengthValue.HasValue)
{
GenerateStringLengthValidation(il, i, validationParameter.MaximumLengthValue.Value, OpCodes.Ble_S, ref next);
}

if (validationParameter.Pattern != null)
{
var regex = typeBuilder.DefineField($"_regex{parameter.Name}", typeof(Regex),
FieldAttributes.Private | FieldAttributes.Static | FieldAttributes.InitOnly);
_regex.Add((validationParameter.Pattern ,regex));
if (next != null)
{
il.MarkLabel(next.Value);
}

next = il.DefineLabel();
var isNull = il.DefineLabel();
il.Emit(OpCodes.Ldarg_S, i);
il.Emit(OpCodes.Brfalse_S, isNull);

il.Emit(OpCodes.Ldsfld, regex);
il.Emit(OpCodes.Ldarg_S, i);
il.EmitCall(OpCodes.Callvirt, s_match, null);
il.EmitCall(OpCodes.Callvirt, s_success, null);
il.Emit(OpCodes.Brtrue_S, next.Value);

il.MarkLabel(isNull);
il.Emit(OpCodes.Ldc_I4_0);
il.Emit(OpCodes.Ret);
}
}
}

if (next.HasValue)
Expand Down Expand Up @@ -255,6 +320,30 @@ static void GenerateNumberValidation(ILGenerator generator, int fieldIndex, Type
generator.Emit(OpCodes.Ldc_I4_0);
generator.Emit(OpCodes.Ret);
}

static void GenerateStringLengthValidation(ILGenerator generator, int fieldIndex, uint value, OpCode code, ref Label? next)
{
if (next != null)
{
generator.MarkLabel(next.Value);
}

next = generator.DefineLabel();

var nextCheckNull = generator.DefineLabel();

generator.Emit(OpCodes.Ldarg_S, fieldIndex);
generator.Emit(OpCodes.Brfalse_S, nextCheckNull);

generator.Emit(OpCodes.Ldarg_S, fieldIndex);
generator.EmitCall(OpCodes.Callvirt, s_getLength, null);
generator.Emit(OpCodes.Ldc_I4, value);
generator.Emit(code, next.Value);

generator.MarkLabel(nextCheckNull);
generator.Emit(OpCodes.Ldc_I4_0);
generator.Emit(OpCodes.Ret);
}

static void SetValue(ILGenerator generator, double value, Type fieldType)
{
Expand Down Expand Up @@ -323,6 +412,22 @@ static bool IsComplexNumber(Type parameterType)
|| parameterType == typeof(float)
|| parameterType == typeof(double)
|| parameterType == typeof(decimal);

static bool IsString(Type type)
=> type == typeof(string);

static bool IsNumber(Type type)
=> type == typeof(int)
|| type == typeof(uint)
|| type == typeof(long)
|| type == typeof(ulong)
|| type == typeof(short)
|| type == typeof(ushort)
|| type == typeof(double)
|| type == typeof(float)
|| type == typeof(decimal)
|| type == typeof(byte)
|| type == typeof(sbyte);
}

private static void CreateExecuteAsync(TypeBuilder builder, TypeBuilder inputBuilder, PropertyBuilder input, MethodInfo action, Type thingType)
Expand Down Expand Up @@ -387,17 +492,6 @@ private static void CreateExecuteAsync(TypeBuilder builder, TypeBuilder inputBui
il.Emit(OpCodes.Ret);
}

private static bool IsNumber(Type type)
=> type == typeof(int)
|| type == typeof(uint)
|| type == typeof(long)
|| type == typeof(ulong)
|| type == typeof(short)
|| type == typeof(ushort)
|| type == typeof(double)
|| type == typeof(float)
|| type == typeof(decimal)
|| type == typeof(byte)
|| type == typeof(sbyte);

}
}
Original file line number Diff line number Diff line change
Expand Up @@ -99,9 +99,22 @@ public void Intercept(Thing thing, MethodInfo action, ThingActionAttribute? acti
parameterActionInfo.MinimumValue);
_jsonWriter.PropertyNumber(nameof(ThingPropertyAttribute.Maximum), parameterType,
parameterActionInfo.MaximumValue);
_jsonWriter.PropertyNumber(nameof(ThingPropertyAttribute.ExclusiveMinimum), parameterType,
parameterActionInfo.ExclusiveMinimumValue);
_jsonWriter.PropertyNumber(nameof(ThingPropertyAttribute.ExclusiveMaximum), parameterType,
parameterActionInfo.ExclusiveMaximumValue);
_jsonWriter.PropertyWithNullableValue(nameof(ThingPropertyAttribute.MultipleOf),
parameterActionInfo.MultipleOfValue);
}
else if (jsonType == "string")
{
_jsonWriter.PropertyNumber(nameof(ThingPropertyAttribute.MinimumLength), parameterType,
parameterActionInfo.MinimumLengthValue);
_jsonWriter.PropertyNumber(nameof(ThingPropertyAttribute.MaximumLength), parameterType,
parameterActionInfo.MaximumLengthValue);
_jsonWriter.PropertyString(nameof(ThingPropertyAttribute.Pattern), parameterType,
parameterActionInfo.Pattern);
}
}

_jsonWriter.EndObject();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -85,9 +85,22 @@ public void Intercept(Thing thing, PropertyInfo propertyInfo, ThingPropertyAttri
thingPropertyAttribute.MinimumValue);
_jsonWriter.PropertyNumber(nameof(ThingPropertyAttribute.Maximum), propertyType,
thingPropertyAttribute.MaximumValue);
_jsonWriter.PropertyNumber(nameof(ThingPropertyAttribute.ExclusiveMinimum), propertyType,
thingPropertyAttribute.ExclusiveMinimumValue);
_jsonWriter.PropertyNumber(nameof(ThingPropertyAttribute.ExclusiveMaximum), propertyType,
thingPropertyAttribute.ExclusiveMaximumValue);
_jsonWriter.PropertyNumber(nameof(ThingPropertyAttribute.MultipleOf), propertyType,
thingPropertyAttribute.MultipleOfValue);
}
else if (jsonType == "string")
{
_jsonWriter.PropertyNumber(nameof(ThingPropertyAttribute.MinimumLength), propertyType,
thingPropertyAttribute.MinimumLengthValue);
_jsonWriter.PropertyNumber(nameof(ThingPropertyAttribute.MaximumLength), propertyType,
thingPropertyAttribute.MaximumLengthValue);
_jsonWriter.PropertyString(nameof(ThingPropertyAttribute.Pattern), propertyType,
thingPropertyAttribute.Pattern);
}
}
else
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -647,5 +647,16 @@ public void PropertyEnum(string propertyName, Type propertyType, object[]? @enum

EndArray();
}

public void PropertyString(string propertyName, Type propertyType, string? value)
{
if (value == null)
{
PropertyWithNullValue(propertyName);
return;
}

PropertyWithValue(propertyName, value);
}
}
}
Loading

0 comments on commit fcc8011

Please sign in to comment.