Skip to content

Commit

Permalink
Merge pull request #27 from lillo42/master
Browse files Browse the repository at this point in the history
Merge with master
  • Loading branch information
lillo42 authored Feb 26, 2020
2 parents 1bde057 + 6e5eb3b commit ec93178
Show file tree
Hide file tree
Showing 50 changed files with 4,871 additions and 290 deletions.
40 changes: 35 additions & 5 deletions src/Mozilla.IoT.WebThing/Attributes/ThingParameterAttribute.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,29 +8,59 @@ public class ThingParameterAttribute : Attribute
public string? Title { get; set; }
public string? Description { get; set; }
public string? Unit { get; set; }
internal int? MinimumValue { get; private set; }
internal double? MinimumValue { get; private set; }

public int Minimum
/// <summary>
/// Validates only if the instance is greater than or exactly equal to "minimum"
/// </summary>
public double Minimum
{
get => MinimumValue ?? 0;
set => MinimumValue = value;
}

internal int? MaximumValue { get; private set; }
internal double? MaximumValue { get; private set; }

public int Maximum
/// <summary>
/// Validates only if the instance is less than or exactly equal to "maximum"
/// </summary>
public double Maximum
{
get => MaximumValue ?? 0;
set => MaximumValue = value;
}


internal int? MultipleOfValue { get; set; }

/// <summary>
/// Valid only if it has a value strictly less than (not equal to) "exclusiveMaximum".
/// </summary>
public int MultipleOf
{
get => MultipleOfValue ?? 0;
set => MultipleOfValue = value;
}

internal double? ExclusiveMinimumValue { get; set; }

/// <summary>
/// Valid only if it has a value strictly less than (not equal to) "exclusiveMaximum".
/// </summary>
public double ExclusiveMinimum
{
get => ExclusiveMinimumValue ?? 0;
set => ExclusiveMinimumValue = value;
}

internal double? ExclusiveMaximumValue { get; set; }

/// <summary>
/// Valid only if it has a value strictly greater than (not equal to) "exclusiveMinimum"
/// </summary>
public double ExclusiveMaximum
{
get => ExclusiveMaximumValue ?? 0;
set => ExclusiveMaximumValue = value;
}
}
}
40 changes: 29 additions & 11 deletions src/Mozilla.IoT.WebThing/Attributes/ThingPropertyAttribute.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,30 +12,48 @@ public class ThingPropertyAttribute : Attribute
public string? Unit { get; set; }
public string[]? Type { get; set; }
public bool IsReadOnly { get; set; }
public object[]? Enum { get; set; }
internal float? MinimumValue { get; set; }
internal bool? IsWriteOnlyValue { get; set; }

public float Minimum
public bool IsWriteOnly
{
get => IsWriteOnlyValue.GetValueOrDefault();
set => IsWriteOnlyValue = value;
}

public object[]? Enum { get; set; }
internal double? MinimumValue { get; set; }
public double Minimum
{
get => MinimumValue ?? 0;
set => MinimumValue = value;
}

internal float? MaximumValue { get; set; }

public float Maximum
internal double? MaximumValue { get; set; }
public double Maximum
{
get => MaximumValue ?? 0;
set => MaximumValue = value;
}


internal float? MultipleOfValue { get; set; }

public float MultipleOf

internal int? MultipleOfValue { get; set; }
public int MultipleOf
{
get => MultipleOfValue ?? 0;
set => MultipleOfValue = value;
}

internal double? ExclusiveMinimumValue { get; set; }
public double ExclusiveMinimum
{
get => ExclusiveMinimumValue ?? 0;
set => ExclusiveMinimumValue = value;
}

internal double? ExclusiveMaximumValue { get; set; }
public double ExclusiveMaximum
{
get => ExclusiveMaximumValue ?? 0;
set => ExclusiveMaximumValue = value;
}
}
}
3 changes: 1 addition & 2 deletions src/Mozilla.IoT.WebThing/Converts/ThingConverter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,7 @@ public override void Write(Utf8JsonWriter writer, Thing value, JsonSerializerOpt
{
throw new ArgumentNullException(nameof(options));
}



writer.WriteStartObject();
writer.WriteString("@context", value.Context);
var builder = new UriBuilder(value.Prefix) {Path = $"/things/{options.GetPropertyName(value.Name)}"};
Expand Down
11 changes: 11 additions & 0 deletions src/Mozilla.IoT.WebThing/Extensions/TypeExtensions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
namespace System.Reflection
{
internal static class TypeExtensions
{
public static bool IsNullable(this Type type)
=> Nullable.GetUnderlyingType(type) != null;

public static Type GetUnderlyingType(this Type type)
=> Nullable.GetUnderlyingType(type) ?? type;
}
}
160 changes: 130 additions & 30 deletions src/Mozilla.IoT.WebThing/Factories/Generator/Actions/ActionIntercept.cs
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ private static void CreateActionName(TypeBuilder builder, string value)
PropertyAttributes.HasDefault | PropertyAttributes.SpecialName,
typeof(string), null);

var getProperty = builder.DefineMethod("get_ActionName",
var getProperty = builder.DefineMethod("get_ActionName",
MethodAttributes.Family | MethodAttributes.SpecialName | MethodAttributes.HideBySig | MethodAttributes.Virtual,
typeof(string), Type.EmptyTypes);

Expand All @@ -128,8 +128,7 @@ private static void CreateActionName(TypeBuilder builder, string value)
propertyBuilder.SetGetMethod(getProperty);
}

private static void CreateInputValidation(TypeBuilder builder, TypeBuilder input, MethodInfo isValid,
PropertyBuilder inputProperty)
private static void CreateInputValidation(TypeBuilder builder, TypeBuilder input, MethodInfo isValid, PropertyBuilder inputProperty)
{
var isInputValidBuilder = builder.DefineMethod(nameof(ActionInfo.IsValid),
MethodAttributes.Public | MethodAttributes.ReuseSlot | MethodAttributes.Virtual | MethodAttributes.HideBySig,
Expand Down Expand Up @@ -162,40 +161,33 @@ private static void CreateParameterValidation(ILGenerator il, ParameterInfo[] pa
{
continue;
}

var parameterType = parameter.ParameterType.GetUnderlyingType();

if (IsNumber(parameter.ParameterType))
{
if (validationParameter.MinimumValue.HasValue)
{
if (next != null)
{
il.MarkLabel(next.Value);
}
next = il.DefineLabel();

il.Emit(OpCodes.Ldarg_S, i);
il.Emit(OpCodes.Ldc_I4_S, validationParameter.MinimumValue.Value);
il.Emit(OpCodes.Bge_S, next.Value);

il.Emit(OpCodes.Ldc_I4_0);
il.Emit(OpCodes.Ret);
var code = IsComplexNumber(parameterType) ? OpCodes.Bge_Un_S : OpCodes.Bge_S;
GenerateNumberValidation(il, i, parameterType, validationParameter.MinimumValue.Value, code, ref next);
}

if (validationParameter.MaximumValue.HasValue)
{
if (next != null)
{
il.MarkLabel(next.Value);
}
var code = IsComplexNumber(parameterType) ? OpCodes.Ble_Un_S : OpCodes.Ble_S;
GenerateNumberValidation(il, i, parameterType, validationParameter.MaximumValue.Value, code, ref next);
}

next = il.DefineLabel();

il.Emit(OpCodes.Ldarg_S, i);
il.Emit(OpCodes.Ldc_I4_S, validationParameter.MaximumValue.Value);
il.Emit(OpCodes.Ble_S, next.Value);
if (validationParameter.ExclusiveMinimumValue.HasValue)
{
var code = IsComplexNumber(parameterType) ? OpCodes.Bgt_Un_S : OpCodes.Bgt_S;
GenerateNumberValidation(il, i, parameterType, validationParameter.ExclusiveMinimumValue.Value, code, ref next);
}

il.Emit(OpCodes.Ldc_I4_0);
il.Emit(OpCodes.Ret);
if (validationParameter.ExclusiveMaximumValue.HasValue)
{
var code = IsComplexNumber(parameterType) ? OpCodes.Blt_Un_S : OpCodes.Blt_S;
GenerateNumberValidation(il, i, parameterType, validationParameter.ExclusiveMaximumValue.Value, code, ref next);
}

if (validationParameter.MultipleOfValue.HasValue)
Expand All @@ -204,11 +196,33 @@ private static void CreateParameterValidation(ILGenerator il, ParameterInfo[] pa
{
il.MarkLabel(next.Value);
}

next = il.DefineLabel();

il.Emit(OpCodes.Ldarg_S, i);
il.Emit(OpCodes.Ldc_I4_S, validationParameter.MultipleOfValue.Value);
il.Emit(OpCodes.Rem);
il.Emit(OpCodes.Brtrue, next.Value);
SetValue(il, validationParameter.MultipleOfValue.Value, parameter.ParameterType);

if (parameter.ParameterType == typeof(float)
|| parameter.ParameterType == typeof(double)
|| parameter.ParameterType == typeof(decimal))
{
il.Emit(OpCodes.Rem);
if (parameter.ParameterType == typeof(float))
{
il.Emit(OpCodes.Ldc_R4 , (float)0);
}
else
{
il.Emit(OpCodes.Ldc_R8, (double)0);
}

il.Emit(OpCodes.Beq_S, next.Value);
}
else
{
il.Emit(parameter.ParameterType == typeof(ulong) ? OpCodes.Rem_Un : OpCodes.Rem);
il.Emit(OpCodes.Brfalse_S, next.Value);
}

il.Emit(OpCodes.Ldc_I4_0);
il.Emit(OpCodes.Ret);
Expand All @@ -223,6 +237,92 @@ private static void CreateParameterValidation(ILGenerator il, ParameterInfo[] pa

il.Emit(OpCodes.Ldc_I4_1);
il.Emit(OpCodes.Ret);

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

next = generator.DefineLabel();

generator.Emit(OpCodes.Ldarg_S, fieldIndex);
SetValue(generator, value, fieldType);

generator.Emit(code, next.Value);

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

static void SetValue(ILGenerator generator, double value, Type fieldType)
{
if (fieldType == typeof(byte))
{
var convert = Convert.ToByte(value);
generator.Emit(OpCodes.Ldc_I4_S, convert);
}
else if (fieldType == typeof(sbyte))
{
var convert = Convert.ToSByte(value);
generator.Emit(OpCodes.Ldc_I4_S, convert);
}
else if (fieldType == typeof(short))
{
var convert = Convert.ToInt16(value);
generator.Emit(OpCodes.Ldc_I4_S, convert);
}
else if (fieldType == typeof(ushort))
{
var convert = Convert.ToUInt16(value);
generator.Emit(OpCodes.Ldc_I4_S, convert);
}
else if (fieldType == typeof(int))
{
var convert = Convert.ToInt32(value);
generator.Emit(OpCodes.Ldc_I4_S, convert);
}
else if (fieldType == typeof(uint))
{
var convert = Convert.ToUInt32(value);
generator.Emit(OpCodes.Ldc_I4_S, convert);
}
else if (fieldType == typeof(long))
{
var convert = Convert.ToInt64(value);
generator.Emit(OpCodes.Ldc_I8, convert);
}
else if (fieldType == typeof(ulong))
{
var convert = Convert.ToUInt64(value);
if (convert <= uint.MaxValue)
{
generator.Emit(OpCodes.Ldc_I4_S, (int)convert);
generator.Emit(OpCodes.Conv_I8);
}
else
{
generator.Emit(OpCodes.Ldc_I8, convert);
}
}
else if (fieldType == typeof(float))
{
var convert = Convert.ToSingle(value);
generator.Emit(OpCodes.Ldc_R4, convert);
}
else
{
var convert = Convert.ToDouble(value);
generator.Emit(OpCodes.Ldc_R8, convert);
}
}

static bool IsComplexNumber(Type parameterType)
=> parameterType == typeof(ulong)
|| parameterType == typeof(float)
|| parameterType == typeof(double)
|| parameterType == typeof(decimal);
}

private static void CreateExecuteAsync(TypeBuilder builder, TypeBuilder inputBuilder, PropertyBuilder input, MethodInfo action, Type thingType)
Expand Down Expand Up @@ -286,7 +386,7 @@ private static void CreateExecuteAsync(TypeBuilder builder, TypeBuilder inputBui

il.Emit(OpCodes.Ret);
}

private static bool IsNumber(Type type)
=> type == typeof(int)
|| type == typeof(uint)
Expand Down
Loading

0 comments on commit ec93178

Please sign in to comment.