Skip to content

Commit 6557389

Browse files
committed
Add relations to CodeGen
1 parent b5be5bc commit 6557389

File tree

5 files changed

+231
-2
lines changed

5 files changed

+231
-2
lines changed
Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
// Licensed under MIT No Attribution, see LICENSE file at the root.
2+
// Copyright 2013 Andreas Gullberg Larsen ([email protected]). Maintained at https://github.com/angularsen/UnitsNet.
3+
4+
using System.Collections.Generic;
5+
using System.IO;
6+
using CodeGen.JsonTypes;
7+
using Newtonsoft.Json;
8+
9+
namespace CodeGen.Generators
10+
{
11+
internal static class QuantityRelationsParser
12+
{
13+
private static List<Relation> ParseRelations(string rootDir)
14+
{
15+
var relationsFileName = Path.Combine(rootDir, "Common/UnitRelations.json");
16+
return JsonConvert.DeserializeObject<List<Relation>>(File.ReadAllText(relationsFileName)) ?? new List<Relation>();
17+
}
18+
19+
public static void ApplyRelations(string rootDir, IEnumerable<Quantity> quantities)
20+
{
21+
var relations = ParseRelations(rootDir);
22+
var timespanRelations = new List<Relation>();
23+
24+
foreach (var relation in relations)
25+
{
26+
relation.ResultQuantity = relation.Result?.Split('.')[0] ?? string.Empty;
27+
relation.LeftQuantity = relation.Left?.Split('.')[0] ?? string.Empty;
28+
relation.RightQuantity = relation.Right?.Split('.')[0] ?? string.Empty;
29+
30+
if (relation.LeftQuantity == "Duration")
31+
{
32+
timespanRelations.Add(relation with
33+
{
34+
Left = relation.Left?.Replace("Duration.", "TimeSpan.Total") ?? string.Empty,
35+
LeftQuantity = "TimeSpan",
36+
});
37+
}
38+
39+
if (relation.RightQuantity == "Duration")
40+
{
41+
timespanRelations.Add(relation with
42+
{
43+
Right = relation.Right?.Replace("Duration.", "TimeSpan.Total") ?? string.Empty,
44+
RightQuantity = "TimeSpan",
45+
});
46+
}
47+
}
48+
49+
relations.AddRange(timespanRelations);
50+
51+
foreach (var quantity in quantities)
52+
{
53+
var quantityRelations = new List<Relation>();
54+
55+
foreach (var relation in relations)
56+
{
57+
if (relation.LeftQuantity == quantity.Name)
58+
{
59+
quantityRelations.Add(relation);
60+
if (relation is { Operator: "*", RightQuantity: "TimeSpan" or "double" })
61+
{
62+
quantityRelations.Add(relation.Swapped());
63+
}
64+
}
65+
66+
if (relation.RightQuantity == quantity.Name)
67+
{
68+
if (relation.Operator == "inverse" || relation.Operator == "*" && relation.Left != relation.Right)
69+
{
70+
quantityRelations.Add(relation.Swapped());
71+
}
72+
73+
if (relation is { Operator: "/", Left: "double" })
74+
{
75+
quantityRelations.Add(relation);
76+
}
77+
}
78+
}
79+
80+
quantity.Relations = quantityRelations.ToArray();
81+
}
82+
}
83+
}
84+
}

CodeGen/Generators/UnitsNetGen/QuantityGenerator.cs

Lines changed: 113 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@ internal class QuantityGenerator : GeneratorBase
1717
private readonly string _valueType;
1818
private readonly Unit _baseUnit;
1919

20+
private readonly string[] _decimalTypes = { "BitRate", "Information", "Power" };
21+
2022
public QuantityGenerator(Quantity quantity)
2123
{
2224
_quantity = quantity ?? throw new ArgumentNullException(nameof(quantity));
@@ -39,8 +41,12 @@ public string Generate()
3941
using System;
4042
using System.Diagnostics.CodeAnalysis;
4143
using System.Globalization;
42-
using System.Linq;
43-
using System.Runtime.Serialization;
44+
using System.Linq;");
45+
if (_quantity.Relations.Any(r => r.Operator is "*" or "/"))
46+
Writer.WL(@"#if NET7_0_OR_GREATER
47+
using System.Numerics;
48+
#endif");
49+
Writer.WL(@"using System.Runtime.Serialization;
4450
using UnitsNet.InternalHelpers;
4551
using UnitsNet.Units;
4652
@@ -67,6 +73,35 @@ namespace UnitsNet
6773
public readonly partial struct {_quantity.Name} :
6874
{(_quantity.GenerateArithmetic ? "IArithmeticQuantity" : "IQuantity")}<{_quantity.Name}, {_unitEnumName}, {_quantity.ValueType}>,");
6975

76+
if (_quantity.Relations.Any(r => r.Operator is "*" or "/"))
77+
{
78+
Writer.WL(@$"
79+
#if NET7_0_OR_GREATER");
80+
foreach (var relation in _quantity.Relations)
81+
{
82+
if (relation.LeftQuantity == _quantity.Name)
83+
{
84+
switch (relation.Operator)
85+
{
86+
case "*":
87+
Writer.W(@"
88+
IMultiplyOperators");
89+
break;
90+
case "/":
91+
Writer.W(@"
92+
IDivisionOperators");
93+
break;
94+
default:
95+
continue;
96+
}
97+
Writer.WL($"<{relation.LeftQuantity}, {relation.RightQuantity}, {relation.ResultQuantity}>,");
98+
}
99+
}
100+
101+
Writer.WL(@$"
102+
#endif");
103+
}
104+
70105
if (_quantity.ValueType == "decimal") Writer.WL(@$"
71106
IDecimalQuantity,");
72107

@@ -100,6 +135,7 @@ namespace UnitsNet
100135
GenerateStaticFactoryMethods();
101136
GenerateStaticParseMethods();
102137
GenerateArithmeticOperators();
138+
GenerateRelationalOperators();
103139
GenerateEqualityAndComparison();
104140
GenerateConversionMethods();
105141
GenerateToString();
@@ -696,6 +732,81 @@ private void GenerateLogarithmicArithmeticOperators()
696732
" );
697733
}
698734

735+
private void GenerateRelationalOperators()
736+
{
737+
if (!_quantity.Relations.Any()) return;
738+
739+
Writer.WL($@"
740+
#region Relational Operators
741+
");
742+
743+
foreach (Relation relation in _quantity.Relations)
744+
{
745+
if (relation.Operator == "inverse")
746+
{
747+
Writer.WL($@"
748+
/// <summary>Calculates the inverse of this quantity.</summary>
749+
/// <returns>The corresponding inverse quantity, <see cref=""{relation.RightQuantity}""/>.</returns>
750+
public {relation.RightQuantity} Inverse()
751+
{{
752+
return {relation.Left.Split('.')[1]} == 0.0 ? {relation.RightQuantity}.Zero : {relation.RightQuantity}.From{relation.Right.Split('.')[1]}(1 / {relation.Left.Split('.')[1]});
753+
}}
754+
");
755+
}
756+
else
757+
{
758+
var leftParameter = relation.LeftQuantity.ToCamelCase();
759+
var leftConversionProperty = relation.Left.Split('.').ElementAtOrDefault(1);
760+
var rightParameter = relation.RightQuantity.ToCamelCase();
761+
var rightConversionProperty = relation.Right.Split('.').ElementAtOrDefault(1);
762+
763+
if (leftParameter == rightParameter)
764+
{
765+
leftParameter = "left";
766+
rightParameter = "right";
767+
}
768+
769+
var leftPart = $"{leftParameter}.{leftConversionProperty}";
770+
var rightPart = $"{rightParameter}.{rightConversionProperty}";
771+
772+
if (leftParameter == "double")
773+
{
774+
leftParameter = "value";
775+
leftPart = "value";
776+
}
777+
778+
if (rightParameter == "double")
779+
{
780+
rightParameter = "value";
781+
rightPart = "value";
782+
}
783+
784+
var leftCast = _decimalTypes.Contains(relation.LeftQuantity) ? "(double)" : "";
785+
var rightCast = _decimalTypes.Contains(relation.RightQuantity) ? "(double)" : "";
786+
787+
var expression = $"{leftCast}{leftPart} {relation.Operator} {rightCast}{rightPart}";
788+
789+
if (relation.Result is not ("double" or "decimal"))
790+
{
791+
expression = $"{relation.Result}({expression})";
792+
}
793+
794+
Writer.WL($@"
795+
/// <summary>Get <see cref=""{relation.ResultQuantity}""/> from <see cref=""{relation.LeftQuantity}""/> {relation.Operator} <see cref=""{relation.RightQuantity}""/>.</summary>
796+
public static {relation.ResultQuantity} operator {relation.Operator}({relation.LeftQuantity} {leftParameter}, {relation.RightQuantity} {rightParameter})
797+
{{
798+
return {expression};
799+
}}
800+
");
801+
}
802+
}
803+
804+
Writer.WL($@"
805+
806+
#endregion
807+
");
808+
}
809+
699810
private void GenerateEqualityAndComparison()
700811
{
701812
Writer.WL($@"

CodeGen/JsonTypes/Quantity.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ internal class Quantity
1818
public int LogarithmicScalingFactor = 1;
1919
public string Name = null!;
2020
public Unit[] Units = Array.Empty<Unit>();
21+
public Relation[] Relations = Array.Empty<Relation>();
2122
public string? XmlDocRemarks;
2223
public string XmlDocSummary = null!;
2324
public string? ObsoleteText;

CodeGen/JsonTypes/Relation.cs

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
// Licensed under MIT No Attribution, see LICENSE file at the root.
2+
// Copyright 2013 Andreas Gullberg Larsen ([email protected]). Maintained at https://github.com/angularsen/UnitsNet.
3+
4+
namespace CodeGen.JsonTypes
5+
{
6+
internal record Relation
7+
{
8+
// 0649 Field is never assigned to
9+
#pragma warning disable 0649
10+
11+
public string Operator = null!;
12+
public string Result = null!;
13+
public string Left = null!;
14+
public string Right = null!;
15+
16+
public string ResultQuantity = null!;
17+
public string LeftQuantity = null!;
18+
public string RightQuantity = null!;
19+
20+
public Relation Swapped() => this with
21+
{
22+
Left = Right,
23+
Right = Left,
24+
LeftQuantity = RightQuantity,
25+
RightQuantity = LeftQuantity
26+
};
27+
28+
// 0649 Field is never assigned to
29+
#pragma warning restore 0649
30+
}
31+
}

CodeGen/Program.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,8 @@ public static int Main(bool verbose = false, DirectoryInfo? repositoryRoot = nul
6969

7070
QuantityNameToUnitEnumValues quantityNameToUnitEnumValues = UnitEnumValueAllocator.AllocateNewUnitEnumValues($"{rootDir}/Common/UnitEnumValues.g.json", quantities);
7171

72+
QuantityRelationsParser.ApplyRelations(rootDir, quantities);
73+
7274
UnitsNetGenerator.Generate(rootDir, quantities, quantityNameToUnitEnumValues);
7375

7476
if (updateNanoFrameworkDependencies)

0 commit comments

Comments
 (0)