Skip to content

Commit

Permalink
Merge remote-tracking branch 'upstream/develop' into driver/ina2xx
Browse files Browse the repository at this point in the history
  • Loading branch information
engunneer committed Mar 16, 2024
2 parents 0cd4f10 + 304fd50 commit 4a87570
Show file tree
Hide file tree
Showing 52 changed files with 1,637 additions and 536 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,28 @@ public Point Center
set => SetInvalidatingProperty(ref center, value);
}

/// <inheritdoc/>
public override int Left
{
get => center.X - radius;
set
{
center.X = value + radius;
Invalidate();
}
}

/// <inheritdoc/>
public override int Top
{
get => center.Y - radius;
set
{
center.Y = value + radius;
Invalidate();
}
}

/// <summary>
/// Gets or sets the foreground color of the Circle.
/// </summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ public class Picture : ThemedControl
private Color _backColor = Color.Transparent;
private VerticalAlignment _verticalAlignment = VerticalAlignment.Center;
private HorizontalAlignment _horizontalAlignment = HorizontalAlignment.Center;
private MF.Image _image = default!;
private MF.Image? _image = default!;

/// <summary>
/// Initializes a new instance of the <see cref="MicroLayout.Picture"/> class with the specified dimensions and image.
Expand All @@ -21,7 +21,7 @@ public class Picture : ThemedControl
/// <param name="width">The width of the image display control.</param>
/// <param name="height">The height of the image display control.</param>
/// <param name="image">The image to be displayed.</param>
public Picture(int left, int top, int width, int height, MF.Image image)
public Picture(int left, int top, int width, int height, MF.Image? image = null)
: base(left, top, width, height)
{
Image = image;
Expand All @@ -42,7 +42,7 @@ public override void ApplyTheme(DisplayTheme theme)
/// <summary>
/// Gets or sets the image to be displayed on the image display control.
/// </summary>
public MF.Image Image
public MF.Image? Image
{
get => _image;
set => SetInvalidatingProperty(ref _image, value);
Expand Down Expand Up @@ -81,6 +81,8 @@ public Color BackColor
/// <param name="graphics">The <see cref="MicroGraphics"/> surface to draw the image display control on.</param>
protected override void OnDraw(MicroGraphics graphics)
{
if (Image == null) { return; }

if (BackColor != Color.Transparent)
{
graphics.DrawRectangle(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,15 @@
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Meadow.Foundation.Serialization;

[AttributeUsage(AttributeTargets.Property, Inherited = true)]
public class JsonIgnoreAttribute : Attribute

Check warning on line 10 in Source/Meadow.Foundation.Libraries_and_Frameworks/Serialization.MicroJson/Driver/MicroJson.TypeSafe.cs

View workflow job for this annotation

GitHub Actions / build

Missing XML comment for publicly visible type or member 'JsonIgnoreAttribute'
{
}

public static partial class MicroJson
{
/// <summary>
Expand All @@ -26,7 +32,7 @@ public static List<T> DeserializeList<T>(ArrayList array)
/// </summary>
/// <typeparam name="T">The type of objects in the list.</typeparam>
/// <param name="array">The JSON array to deserialize.</param>
/// <param name="type">The type of objects in the list as a <see cref="System.Type"/>.</param>
/// <param name="type">The type of objects in the list as a <see cref="Type"/>.</param>
/// <param name="instance"></param>
/// <returns>A list of objects of type T.</returns>
private static void DeserializeList<T>(ArrayList array, Type type, ref List<T> instance)
Expand Down Expand Up @@ -73,55 +79,14 @@ public static T[] DeserializeArray<T>(ArrayList array)
}

/// <summary>
/// Deserializes a JSON array into an array of objects of the specified type.
/// </summary>
/// <param name="array">The JSON array to deserialize.</param>
/// <param name="type">The type of objects in the array as a <see cref="System.Type"/>.</param>
/// <param name="instance">The array instance to populate.</param>
private static void DeserializeArray(ArrayList array, Type type, ref Array instance)
{
var index = 0;

foreach (Hashtable item in array)
{
if (type == typeof(string))
{
var e = item.GetEnumerator();
e.MoveNext();
instance.SetValue(((DictionaryEntry)e.Current).Value, index);
index++;
}
else
{
var arrayItem = Activator.CreateInstance(type);
Deserialize(item, type, ref arrayItem);
instance.SetValue(arrayItem, index++);
}
}
}

/// <summary>
/// Deserializes an object of type T from a JSON string or Hashtable.
/// Deserializes an object of type T from a JSON string.
/// </summary>
/// <typeparam name="T">The type of object to deserialize.</typeparam>
/// <param name="data">The JSON string or Hashtable to deserialize.</param>
/// <param name="encodedData">A UTF8-encoded JSON string to deserialize.</param>
/// <returns>An object of type T.</returns>
public static T Deserialize<T>(object data)
public static T Deserialize<T>(byte[] encodedData)
{
if (data is string json)
{
return Deserialize<T>(json);
}
else if (data is Hashtable hashtable)
{
object? instance = Activator.CreateInstance<T>();
Deserialize(hashtable, typeof(T), ref instance!);
return (T)instance;
}
else
{
throw new ArgumentException("Unsupported data type for deserialization.");
}
return Deserialize<T>(Encoding.UTF8.GetString(encodedData));
}

/// <summary>
Expand All @@ -134,6 +99,17 @@ public static T Deserialize<T>(string json)
{
var type = typeof(T);

return (T)Deserialize(json, type);
}

/// <summary>
/// Deserializes an object of type T from a JSON string.
/// </summary>
/// <param name="type">The type of object to deserialize.</param>
/// <param name="json">The JSON string to deserialize.</param>
/// <returns>An object of the specified type</returns>
public static object Deserialize(string json, Type type)
{
if (type.IsArray)
{
var elementType = type.GetElementType();
Expand All @@ -152,7 +128,7 @@ public static T Deserialize<T>(string json)
}
}

return (T)(object)targetArray;
return targetArray;
}
else if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(List<>))
{
Expand All @@ -172,14 +148,14 @@ public static T Deserialize<T>(string json)
}
}

return (T)targetList;
return targetList;
}
else
{
object instance = Activator.CreateInstance(type);
Deserialize(json, typeof(T), ref instance);
Deserialize(json, type, ref instance);

return (T)instance;
return instance;
}
}

Expand All @@ -206,87 +182,107 @@ private static void Deserialize(Hashtable? root, Type type, ref object instance)
{
var values = root ?? throw new ArgumentException();

var props = type.GetProperties(System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.NonPublic).ToList();
var props = type.GetProperties(
System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.NonPublic)
.Where(p => p.GetCustomAttributes(typeof(JsonIgnoreAttribute), true).Length == 0)
.ToList();

foreach (string v in values.Keys)
{
var prop = props.FirstOrDefault(p => string.Compare(p.Name, v, true) == 0);
var prop = props.FirstOrDefault(p => string.Compare(p.Name, v, StringComparison.OrdinalIgnoreCase) == 0);

if (prop != null && prop.CanWrite)
{
switch (true)
Type propType = prop.PropertyType;

if (propType.IsEnum)
{
prop.SetValue(instance, Enum.Parse(propType, values[v].ToString()));
}
else if (propType.IsArray)
{
var al = values[v] as ArrayList;
var elementType = propType.GetElementType();
var targetArray = Array.CreateInstance(elementType, al!.Count);
for (int i = 0; i < al.Count; i++)
{
object arrayItem = Activator.CreateInstance(elementType);
Deserialize(al[i] as Hashtable, elementType, ref arrayItem);
targetArray.SetValue(arrayItem, i);
}
prop.SetValue(instance, targetArray);
}
else if (propType.IsGenericType && propType.GetGenericTypeDefinition() == typeof(List<>))
{
var listType = propType.GetGenericArguments()[0];
var list = Activator.CreateInstance(propType);
var addMethod = propType.GetMethod("Add");

foreach (var item in (ArrayList)values[v])
{
object listItem = Activator.CreateInstance(listType);
Deserialize(item as Hashtable, listType, ref listItem);
addMethod.Invoke(list, new[] { listItem });
}

prop.SetValue(instance, list);
}
else if (propType.GetInterfaces().Any(i => i.IsGenericType && i.GetGenericTypeDefinition() == typeof(IDictionary<,>)))
{
var dictionaryType = propType.GetGenericTypeDefinition();
var keyType = propType.GetGenericArguments()[0];
var valueType = propType.GetGenericArguments()[1];

var dictionary = (IDictionary)Activator.CreateInstance(propType);

foreach (DictionaryEntry entry in (Hashtable)values[v])
{
object key = Convert.ChangeType(entry.Key, keyType);
object value = Activator.CreateInstance(valueType);
Deserialize((Hashtable)entry.Value, valueType, ref value);
dictionary.Add(key, value);
}

prop.SetValue(instance, dictionary);
}
else if (IsComplexType(propType))
{
case bool _ when prop.PropertyType.IsEnum:
var enumValue = Enum.Parse(prop.PropertyType, values[v].ToString());
prop.SetValue(instance, enumValue);
break;
case bool _ when prop.PropertyType == typeof(ulong):
prop.SetValue(instance, Convert.ToUInt64(values[v]));
break;
case bool _ when prop.PropertyType == typeof(long):
prop.SetValue(instance, Convert.ToInt64(values[v]));
break;
case bool _ when prop.PropertyType == typeof(uint):
prop.SetValue(instance, Convert.ToUInt32(values[v]));
break;
case bool _ when prop.PropertyType == typeof(int):
prop.SetValue(instance, Convert.ToInt32(values[v]));
break;
case bool _ when prop.PropertyType == typeof(ushort):
prop.SetValue(instance, Convert.ToUInt16(values[v]));
break;
case bool _ when prop.PropertyType == typeof(short):
prop.SetValue(instance, Convert.ToInt16(values[v]));
break;
case bool _ when prop.PropertyType == typeof(byte):
prop.SetValue(instance, Convert.ToByte(values[v]));
break;
case bool _ when prop.PropertyType == typeof(sbyte):
prop.SetValue(instance, Convert.ToBoolean(values[v]));
break;
case bool _ when prop.PropertyType == typeof(double):
prop.SetValue(instance, Convert.ToDouble(values[v]));
break;
case bool _ when prop.PropertyType == typeof(float):
prop.SetValue(instance, Convert.ToSingle(values[v]));
break;
case bool _ when prop.PropertyType == typeof(bool):
prop.SetValue(instance, Convert.ToBoolean(values[v]));
break;
case bool _ when prop.PropertyType == typeof(string):
prop.SetValue(instance, values[v].ToString());
break;
default:
if (prop.PropertyType.IsArray)
{
var al = values[v] as ArrayList;
var elementType = prop.PropertyType.GetElementType();
var targetArray = Array.CreateInstance(elementType, al!.Count);
DeserializeArray(al, elementType, ref targetArray);
prop.SetValue(instance, targetArray);
}
else if (prop.PropertyType.IsGenericType && prop.PropertyType.GetGenericTypeDefinition() == typeof(List<>))
{
var listType = prop.PropertyType.GetGenericArguments()[0];
var list = Activator.CreateInstance(prop.PropertyType);
var addMethod = prop.PropertyType.GetMethod("Add");

foreach (var item in (ArrayList)values[v])
{
var listItem = Activator.CreateInstance(listType);
Deserialize(item as Hashtable, listType, ref listItem);
addMethod.Invoke(list, new[] { listItem });
}

prop.SetValue(instance, list);
}
else
{
throw new NotSupportedException($"Type '{prop.PropertyType}' not supported");
}
break;
if (values[v] is Hashtable hashtableValue)
{
object complexInstance = Activator.CreateInstance(propType);
Deserialize(hashtableValue, propType, ref complexInstance);
prop.SetValue(instance, complexInstance);
}
}
else
{
if (values[v] != null && values[v] != DBNull.Value)
{
prop.SetValue(instance, Convert.ChangeType(values[v], propType));
}
}
}
}
}

private static bool IsComplexType(Type type)
{
if (type.IsPrimitive ||
type.IsEnum ||
type == typeof(string) ||
type == typeof(decimal) ||
type == typeof(DateTime) ||
type == typeof(Guid)
)
{
return false;
}

if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>))
{
return IsComplexType(Nullable.GetUnderlyingType(type));
}

return true;
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using System;
using System.Collections;
using System.Linq;
using System.Reflection;
using System.Text;

Expand Down Expand Up @@ -113,7 +114,10 @@ public static partial class MicroJson
var hashtable = new Hashtable();

// Use PropertyInfo instead of MethodInfo for better performance
PropertyInfo[] properties = type.GetProperties(BindingFlags.Public | BindingFlags.Instance);
var properties = type
.GetProperties(BindingFlags.Public | BindingFlags.Instance)
.Where(p => p.GetCustomAttributes(typeof(JsonIgnoreAttribute), true).Length == 0);

foreach (PropertyInfo property in properties)
{
object returnObject = property.GetValue(o);
Expand Down
Loading

0 comments on commit 4a87570

Please sign in to comment.