Round Units to 3 significant digits by default (ToString). Add JsonConverters to generator

This commit is contained in:
ig 2023-03-02 17:15:10 +01:00
parent 19188fa430
commit 8ae9119858
22 changed files with 256 additions and 103 deletions

View File

@ -6,6 +6,6 @@ public static class Utils
{ {
public static Decimal Round3(this Decimal d) public static Decimal Round3(this Decimal d)
{ {
return DecimalUtils.RoundToSignificantFigures(d, 3); return DecimalUtils.RoundToSignificantDigits(d, 3);
} }
} }

View File

@ -2,6 +2,9 @@
#define Sum #define Sum
using static System.Math; using static System.Math;
using System.Text.Json;
using System.Text.Json.Serialization;
using InnovEnergy.Lib.Utils;
namespace InnovEnergy.Lib.Units; namespace InnovEnergy.Lib.Units;
@ -10,7 +13,7 @@ using T = Angle;
public readonly partial struct Angle public readonly partial struct Angle
{ {
public Decimal Value { get; } public Decimal Value { get; }
public override String ToString() => Value + Unit; public override String ToString() => Value.RoundToSignificantDigits(Units.DisplaySignificantDigits) + Unit;
// scalar multiplication // scalar multiplication
@ -75,3 +78,19 @@ public readonly partial struct Angle
public override Int32 GetHashCode() => Value.GetHashCode(); public override Int32 GetHashCode() => Value.GetHashCode();
} }
internal class AngleConverter : JsonConverter<Angle>
{
public override Angle Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
return new Angle(reader.GetDecimal());
}
public override void Write(Utf8JsonWriter writer, Angle value, JsonSerializerOptions options)
{
var rounded = value.Value.RoundToSignificantDigits(Units.JsonSignificantDigits);
writer.WriteNumberValue(rounded);
}
}

View File

@ -2,6 +2,9 @@
#define Sum #define Sum
using static System.Math; using static System.Math;
using System.Text.Json;
using System.Text.Json.Serialization;
using InnovEnergy.Lib.Utils;
namespace InnovEnergy.Lib.Units; namespace InnovEnergy.Lib.Units;
@ -10,7 +13,7 @@ using T = ApparentPower;
public readonly partial struct ApparentPower public readonly partial struct ApparentPower
{ {
public Decimal Value { get; } public Decimal Value { get; }
public override String ToString() => Value + Unit; public override String ToString() => Value.RoundToSignificantDigits(Units.DisplaySignificantDigits) + Unit;
// scalar multiplication // scalar multiplication
@ -75,3 +78,19 @@ public readonly partial struct ApparentPower
public override Int32 GetHashCode() => Value.GetHashCode(); public override Int32 GetHashCode() => Value.GetHashCode();
} }
internal class ApparentPowerConverter : JsonConverter<ApparentPower>
{
public override ApparentPower Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
return new ApparentPower(reader.GetDecimal());
}
public override void Write(Utf8JsonWriter writer, ApparentPower value, JsonSerializerOptions options)
{
var rounded = value.Value.RoundToSignificantDigits(Units.JsonSignificantDigits);
writer.WriteNumberValue(rounded);
}
}

View File

@ -2,6 +2,9 @@
#define Sum #define Sum
using static System.Math; using static System.Math;
using System.Text.Json;
using System.Text.Json.Serialization;
using InnovEnergy.Lib.Utils;
namespace InnovEnergy.Lib.Units; namespace InnovEnergy.Lib.Units;
@ -10,7 +13,7 @@ using T = Current;
public readonly partial struct Current public readonly partial struct Current
{ {
public Decimal Value { get; } public Decimal Value { get; }
public override String ToString() => Value + Unit; public override String ToString() => Value.RoundToSignificantDigits(Units.DisplaySignificantDigits) + Unit;
// scalar multiplication // scalar multiplication
@ -75,3 +78,19 @@ public readonly partial struct Current
public override Int32 GetHashCode() => Value.GetHashCode(); public override Int32 GetHashCode() => Value.GetHashCode();
} }
internal class CurrentConverter : JsonConverter<Current>
{
public override Current Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
return new Current(reader.GetDecimal());
}
public override void Write(Utf8JsonWriter writer, Current value, JsonSerializerOptions options)
{
var rounded = value.Value.RoundToSignificantDigits(Units.JsonSignificantDigits);
writer.WriteNumberValue(rounded);
}
}

View File

@ -2,6 +2,9 @@
#define Equal #define Equal
using static System.Math; using static System.Math;
using System.Text.Json;
using System.Text.Json.Serialization;
using InnovEnergy.Lib.Utils;
namespace InnovEnergy.Lib.Units; namespace InnovEnergy.Lib.Units;
@ -10,7 +13,7 @@ using T = Frequency;
public readonly partial struct Frequency public readonly partial struct Frequency
{ {
public Decimal Value { get; } public Decimal Value { get; }
public override String ToString() => Value + Unit; public override String ToString() => Value.RoundToSignificantDigits(Units.DisplaySignificantDigits) + Unit;
// scalar multiplication // scalar multiplication
@ -75,3 +78,19 @@ public readonly partial struct Frequency
public override Int32 GetHashCode() => Value.GetHashCode(); public override Int32 GetHashCode() => Value.GetHashCode();
} }
internal class FrequencyConverter : JsonConverter<Frequency>
{
public override Frequency Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
return new Frequency(reader.GetDecimal());
}
public override void Write(Utf8JsonWriter writer, Frequency value, JsonSerializerOptions options)
{
var rounded = value.Value.RoundToSignificantDigits(Units.JsonSignificantDigits);
writer.WriteNumberValue(rounded);
}
}

View File

@ -1,7 +1,10 @@
#nullable enable // Auto-generated code requires an explicit '#nullable' directive in source. #nullable enable // Auto-generated code requires an explicit '#nullable' directive in source.
#define Type #define AggregationType
using static System.Math; using static System.Math;
using System.Text.Json;
using System.Text.Json.Serialization;
using InnovEnergy.Lib.Utils;
namespace InnovEnergy.Lib.Units; namespace InnovEnergy.Lib.Units;
@ -10,7 +13,7 @@ using T = Template;
public readonly partial struct Template public readonly partial struct Template
{ {
public Decimal Value { get; } public Decimal Value { get; }
public override String ToString() => Value + Unit; public override String ToString() => Value.RoundToSignificantDigits(Units.DisplaySignificantDigits) + Unit;
// scalar multiplication // scalar multiplication
@ -75,3 +78,19 @@ public readonly partial struct Template
public override Int32 GetHashCode() => Value.GetHashCode(); public override Int32 GetHashCode() => Value.GetHashCode();
} }
internal class TemplateConverter : JsonConverter<Template>
{
public override Template Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
return new Template(reader.GetDecimal());
}
public override void Write(Utf8JsonWriter writer, Template value, JsonSerializerOptions options)
{
var rounded = value.Value.RoundToSignificantDigits(Units.JsonSignificantDigits);
writer.WriteNumberValue(rounded);
}
}

View File

@ -11,5 +11,5 @@ do
file=$(basename -- "$path") file=$(basename -- "$path")
class="${file%.*}" class="${file%.*}"
echo "generating $file" echo "generating $file"
sed "s/Template/$class/g; s/Type/$type/" "./Generator/Template.txt" > "./$class.generated.cs" sed "s/Template/$class/g; s/AggregationType/$type/g" "./Generator/Template.txt" > "./$class.generated.cs"
done done

View File

@ -1,17 +0,0 @@
using System.Text.Json;
using System.Text.Json.Serialization;
namespace InnovEnergy.Lib.Units.Json;
public class CurrentConverter : JsonConverter<Current>
{
public override Current Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
return new Current(reader.GetDecimal());
}
public override void Write(Utf8JsonWriter writer, Current value, JsonSerializerOptions options)
{
writer.WriteNumberValue(value.Value);
}
}

View File

@ -1,17 +0,0 @@
using System.Text.Json;
using System.Text.Json.Serialization;
namespace InnovEnergy.Lib.Units.Json;
public class PowerConverter : JsonConverter<Power>
{
public override Power Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
return new Power(reader.GetDecimal());
}
public override void Write(Utf8JsonWriter writer, Power value, JsonSerializerOptions options)
{
writer.WriteNumberValue(value.Value);
}
}

View File

@ -1,17 +0,0 @@
using System.Text.Json;
using System.Text.Json.Serialization;
namespace InnovEnergy.Lib.Units.Json;
public class ResistanceConverter : JsonConverter<Current>
{
public override Current Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
return new Current(reader.GetDecimal());
}
public override void Write(Utf8JsonWriter writer, Current value, JsonSerializerOptions options)
{
writer.WriteNumberValue(value.Value);
}
}

View File

@ -1,17 +0,0 @@
using System.Text.Json;
using System.Text.Json.Serialization;
namespace InnovEnergy.Lib.Units.Json;
public class VoltageConverter : JsonConverter<Voltage>
{
public override Voltage Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
return new Voltage(reader.GetDecimal());
}
public override void Write(Utf8JsonWriter writer, Voltage value, JsonSerializerOptions options)
{
writer.WriteNumberValue(value.Value);
}
}

View File

@ -2,6 +2,9 @@
#define Sum #define Sum
using static System.Math; using static System.Math;
using System.Text.Json;
using System.Text.Json.Serialization;
using InnovEnergy.Lib.Utils;
namespace InnovEnergy.Lib.Units; namespace InnovEnergy.Lib.Units;
@ -10,7 +13,7 @@ using T = Number;
public readonly partial struct Number public readonly partial struct Number
{ {
public Decimal Value { get; } public Decimal Value { get; }
public override String ToString() => Value + Unit; public override String ToString() => Value.RoundToSignificantDigits(Units.DisplaySignificantDigits) + Unit;
// scalar multiplication // scalar multiplication
@ -75,3 +78,19 @@ public readonly partial struct Number
public override Int32 GetHashCode() => Value.GetHashCode(); public override Int32 GetHashCode() => Value.GetHashCode();
} }
internal class NumberConverter : JsonConverter<Number>
{
public override Number Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
return new Number(reader.GetDecimal());
}
public override void Write(Utf8JsonWriter writer, Number value, JsonSerializerOptions options)
{
var rounded = value.Value.RoundToSignificantDigits(Units.JsonSignificantDigits);
writer.WriteNumberValue(rounded);
}
}

View File

@ -11,7 +11,6 @@ public readonly partial struct Power
public Power(Decimal value) => Value = value; public Power(Decimal value) => Value = value;
// P=UI // P=UI
public static Voltage operator /(Power power, Current current) => new Voltage(power.Value / current.Value); public static Voltage operator /(Power power, Current current) => new Voltage(power.Value / current.Value);
public static Current operator /(Power power, Voltage voltage) => new Current(power.Value / voltage.Value); public static Current operator /(Power power, Voltage voltage) => new Current(power.Value / voltage.Value);

View File

@ -2,6 +2,9 @@
#define Sum #define Sum
using static System.Math; using static System.Math;
using System.Text.Json;
using System.Text.Json.Serialization;
using InnovEnergy.Lib.Utils;
namespace InnovEnergy.Lib.Units; namespace InnovEnergy.Lib.Units;
@ -10,7 +13,7 @@ using T = Power;
public readonly partial struct Power public readonly partial struct Power
{ {
public Decimal Value { get; } public Decimal Value { get; }
public override String ToString() => Value + Unit; public override String ToString() => Value.RoundToSignificantDigits(Units.DisplaySignificantDigits) + Unit;
// scalar multiplication // scalar multiplication
@ -75,3 +78,19 @@ public readonly partial struct Power
public override Int32 GetHashCode() => Value.GetHashCode(); public override Int32 GetHashCode() => Value.GetHashCode();
} }
internal class PowerConverter : JsonConverter<Power>
{
public override Power Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
return new Power(reader.GetDecimal());
}
public override void Write(Utf8JsonWriter writer, Power value, JsonSerializerOptions options)
{
var rounded = value.Value.RoundToSignificantDigits(Units.JsonSignificantDigits);
writer.WriteNumberValue(rounded);
}
}

View File

@ -2,6 +2,9 @@
#define Sum #define Sum
using static System.Math; using static System.Math;
using System.Text.Json;
using System.Text.Json.Serialization;
using InnovEnergy.Lib.Utils;
namespace InnovEnergy.Lib.Units; namespace InnovEnergy.Lib.Units;
@ -10,7 +13,7 @@ using T = ReactivePower;
public readonly partial struct ReactivePower public readonly partial struct ReactivePower
{ {
public Decimal Value { get; } public Decimal Value { get; }
public override String ToString() => Value + Unit; public override String ToString() => Value.RoundToSignificantDigits(Units.DisplaySignificantDigits) + Unit;
// scalar multiplication // scalar multiplication
@ -75,3 +78,19 @@ public readonly partial struct ReactivePower
public override Int32 GetHashCode() => Value.GetHashCode(); public override Int32 GetHashCode() => Value.GetHashCode();
} }
internal class ReactivePowerConverter : JsonConverter<ReactivePower>
{
public override ReactivePower Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
return new ReactivePower(reader.GetDecimal());
}
public override void Write(Utf8JsonWriter writer, ReactivePower value, JsonSerializerOptions options)
{
var rounded = value.Value.RoundToSignificantDigits(Units.JsonSignificantDigits);
writer.WriteNumberValue(rounded);
}
}

View File

@ -2,6 +2,9 @@
#define Sum #define Sum
using static System.Math; using static System.Math;
using System.Text.Json;
using System.Text.Json.Serialization;
using InnovEnergy.Lib.Utils;
namespace InnovEnergy.Lib.Units; namespace InnovEnergy.Lib.Units;
@ -10,7 +13,7 @@ using T = Resistance;
public readonly partial struct Resistance public readonly partial struct Resistance
{ {
public Decimal Value { get; } public Decimal Value { get; }
public override String ToString() => Value + Unit; public override String ToString() => Value.RoundToSignificantDigits(Units.DisplaySignificantDigits) + Unit;
// scalar multiplication // scalar multiplication
@ -75,3 +78,19 @@ public readonly partial struct Resistance
public override Int32 GetHashCode() => Value.GetHashCode(); public override Int32 GetHashCode() => Value.GetHashCode();
} }
internal class ResistanceConverter : JsonConverter<Resistance>
{
public override Resistance Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
return new Resistance(reader.GetDecimal());
}
public override void Write(Utf8JsonWriter writer, Resistance value, JsonSerializerOptions options)
{
var rounded = value.Value.RoundToSignificantDigits(Units.JsonSignificantDigits);
writer.WriteNumberValue(rounded);
}
}

View File

@ -22,8 +22,8 @@ public readonly struct State : IReadOnlyList<String>
public static implicit operator State(Boolean s) => new(s.ToString()); public static implicit operator State(Boolean s) => new(s.ToString());
public static implicit operator State(List<String> s) => new((IReadOnlyList<String>)s); public static implicit operator State(List<String> s) => new((IReadOnlyList<String>)s);
public static implicit operator State(String[] s) => new((IReadOnlyList<String>)s); public static implicit operator State(String[] s) => new((IReadOnlyList<String>)s);
public static implicit operator State(List<Enum> es) => new(es.Select(e => e.ToString()).ToArray()); public static implicit operator State(List<Enum> es) => new(es.Select(e => e.ToString()).ToList());
public static implicit operator State(Enum[] es) => new(es.Select(e => e.ToString()).ToArray()); public static implicit operator State(Enum[] es) => new(es.Select(e => e.ToString()).ToList());
public static State operator |(State left, State right) => new(left, right); public static State operator |(State left, State right) => new(left, right);

View File

@ -2,6 +2,9 @@
#define Mean #define Mean
using static System.Math; using static System.Math;
using System.Text.Json;
using System.Text.Json.Serialization;
using InnovEnergy.Lib.Utils;
namespace InnovEnergy.Lib.Units; namespace InnovEnergy.Lib.Units;
@ -10,7 +13,7 @@ using T = Temperature;
public readonly partial struct Temperature public readonly partial struct Temperature
{ {
public Decimal Value { get; } public Decimal Value { get; }
public override String ToString() => Value + Unit; public override String ToString() => Value.RoundToSignificantDigits(Units.DisplaySignificantDigits) + Unit;
// scalar multiplication // scalar multiplication
@ -75,3 +78,19 @@ public readonly partial struct Temperature
public override Int32 GetHashCode() => Value.GetHashCode(); public override Int32 GetHashCode() => Value.GetHashCode();
} }
internal class TemperatureConverter : JsonConverter<Temperature>
{
public override Temperature Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
return new Temperature(reader.GetDecimal());
}
public override void Write(Utf8JsonWriter writer, Temperature value, JsonSerializerOptions options)
{
var rounded = value.Value.RoundToSignificantDigits(Units.JsonSignificantDigits);
writer.WriteNumberValue(rounded);
}
}

View File

@ -1,10 +1,27 @@
using System.Text.Json.Serialization; using System.Text.Json.Serialization;
using InnovEnergy.Lib.Units.Json;
namespace InnovEnergy.Lib.Units; namespace InnovEnergy.Lib.Units;
public static class Units public static class Units
{ {
static Units()
{
JsonConverters = typeof(Units)
.Assembly
.GetTypes()
.Where(t => t.IsAssignableTo(typeof(JsonConverter)))
.Select(Activator.CreateInstance)
.Cast<JsonConverter>()
.ToArray();
}
public static IReadOnlyList<JsonConverter> JsonConverters { get; }
public static Byte DisplaySignificantDigits { get; set; } = 3;
public static Byte JsonSignificantDigits { get; set; } = 3;
public const Decimal MaxRelativeError = 0.05m; // 5% public const Decimal MaxRelativeError = 0.05m; // 5%
public static Current A (this Decimal value) => new Current(value); public static Current A (this Decimal value) => new Current(value);
@ -17,13 +34,5 @@ public static class Units
public static Angle Rad (this Decimal value) => new Angle(value); public static Angle Rad (this Decimal value) => new Angle(value);
public static Temperature Celsius(this Decimal value) => new Temperature(value); public static Temperature Celsius(this Decimal value) => new Temperature(value);
public static readonly IReadOnlyList<JsonConverter> JsonConverters = new JsonConverter[]
{
new CurrentConverter(),
new VoltageConverter(),
new PowerConverter(),
new ResistanceConverter(),
// TODO
};
} }

View File

@ -2,6 +2,9 @@
#define Equal #define Equal
using static System.Math; using static System.Math;
using System.Text.Json;
using System.Text.Json.Serialization;
using InnovEnergy.Lib.Utils;
namespace InnovEnergy.Lib.Units; namespace InnovEnergy.Lib.Units;
@ -10,7 +13,7 @@ using T = Voltage;
public readonly partial struct Voltage public readonly partial struct Voltage
{ {
public Decimal Value { get; } public Decimal Value { get; }
public override String ToString() => Value + Unit; public override String ToString() => Value.RoundToSignificantDigits(Units.DisplaySignificantDigits) + Unit;
// scalar multiplication // scalar multiplication
@ -75,3 +78,19 @@ public readonly partial struct Voltage
public override Int32 GetHashCode() => Value.GetHashCode(); public override Int32 GetHashCode() => Value.GetHashCode();
} }
internal class VoltageConverter : JsonConverter<Voltage>
{
public override Voltage Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
return new Voltage(reader.GetDecimal());
}
public override void Write(Utf8JsonWriter writer, Voltage value, JsonSerializerOptions options)
{
var rounded = value.Value.RoundToSignificantDigits(Units.JsonSignificantDigits);
writer.WriteNumberValue(rounded);
}
}

View File

@ -1,32 +1,36 @@
using DecimalMath; using DecimalMath;
using static System.Math;
using static DecimalMath.DecimalEx;
namespace InnovEnergy.Lib.Utils; namespace InnovEnergy.Lib.Utils;
public static class DecimalUtils public static class DecimalUtils
{ {
public static Double RoundToSignificantFigures(this Double num, Int32 n) public static Double RoundToSignificantDigits(this Double num, Int32 n)
{ {
if (num == 0) if (num == 0)
return 0; return 0;
var d = Math.Ceiling(Math.Log10(num < 0 ? -num : num)); var d = Ceiling(Log10(num < 0 ? -num : num));
var power = n - (Int32)d; var power = n - (Int32)d;
var magnitude = Math.Pow(10, power); var magnitude = Math.Pow(10, power);
var shifted = Math.Round(num * magnitude); var shifted = Round(num * magnitude);
return shifted / magnitude; return shifted / magnitude;
} }
public static Decimal RoundToSignificantFigures(this Decimal num, Int32 n) public static Decimal RoundToSignificantDigits(this Decimal num, Int32 n)
{ {
if (num == 0) if (num == 0)
return 0; return 0;
var d = Math.Ceiling(DecimalEx.Log10(num < 0 ? -num : num)); var d = Ceiling(Log10(num < 0 ? -num : num));
var power = n - (Int32)d; var power = n - (Int32)d;
var magnitude = DecimalEx.Pow(10, power); var magnitude = DecimalEx.Pow(10, power);
var shifted = Math.Round(num * magnitude); var shifted = Round(num * magnitude);
return shifted / magnitude; return shifted / magnitude;
} }
} }

View File

@ -106,7 +106,7 @@ public static class EnumerableUtils
public static IEnumerable<T> NullableToEnumerable<T>(this T? t) public static IEnumerable<T> NullableToEnumerable<T>(this T? t)
{ {
if (t is not null) if (t is not null)
yield return t!; yield return t;
} }
public static IEnumerable<(T left, T right)> Pairwise<T>(this IEnumerable<T> ts) public static IEnumerable<(T left, T right)> Pairwise<T>(this IEnumerable<T> ts)
@ -246,7 +246,7 @@ public static class EnumerableUtils
public static IEnumerable<T> Generate<T>(this T seed, Func<T, T> next) public static IEnumerable<T> Generate<T>(this T seed, Func<T, T> next)
{ {
var value = seed; var value = seed;
while (true) while (value is not null)
{ {
yield return value; yield return value;
value = next(value); value = next(value);