Skip to content

Commit 4144ab6

Browse files
authored
Merge pull request #65 from Ted-Jin-Lab/development
Results and Quantity.
2 parents daec701 + d0a36f2 commit 4144ab6

7 files changed

Lines changed: 146 additions & 21 deletions

File tree

Directory.Build.props

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
<?xml version="1.0" encoding="utf-8"?>
22
<Project>
33
<PropertyGroup>
4-
<Version>2025.11.20.2</Version>
4+
<Version>2025.11.20.3</Version>
55
<ImplicitUsings>enable</ImplicitUsings>
66
<Nullable>enable</Nullable>
77
<LangVersion>preview</LangVersion>

Tests/TedToolkit.Console/Absorptance.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,4 +13,5 @@ public static void Test()
1313
double d = a;
1414
AbsorbedDose e = 10.0;
1515
}
16+
1617
}

Tests/TedToolkit.Console/AssemblyInfo.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,4 +8,4 @@
88
[assembly: NumberExtension<int, Angle>]
99
[assembly: NumberExtension<double, Angle>]
1010

11-
[assembly:Quantities<double>(QuantitySystems.SI)]
11+
[assembly:Quantities<double>(QuantitySystems.SI, "AbsorbedDose")]

Tests/TedToolkit.Console/TestValidator.cs

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,15 @@ public partial class DateTimeResult
1515
}
1616

1717
[GenerateValidResult<TestClass2>]
18-
public partial class TestClass2Result
18+
public partial class TestClass2Result;
19+
20+
21+
[GenerateValidResult<TestRecord>]
22+
public partial class TestRecordResult;
23+
24+
public record TestRecord
1925
{
26+
public int Value { get; init; } = 0;
2027
}
2128

2229
public struct TestStruct;

src/analyzers/TedToolkit.Quantities.Analyzer/QuantityStructGenerator.cs

Lines changed: 48 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,25 @@ public void GenerateCode(SourceProductionContext context)
124124
])))))
125125
.WithSemicolonToken(Token(SyntaxKind.SemicolonToken)),
126126

127+
MethodDeclaration(IdentifierName(quantity.Name), Identifier("Clamp"))
128+
.WithModifiers(TokenList(Token(SyntaxKind.PublicKeyword)))
129+
.WithAttributeLists([GeneratedCodeAttribute(typeof(QuantityStructGenerator))])
130+
.WithXmlCommentInheritDoc(
131+
$"global::System.Math.Clamp({typeName.FullName}, {typeName.FullName}, {typeName.FullName})")
132+
.WithParameterList(ParameterList(
133+
[
134+
Parameter(Identifier("min")).WithType(IdentifierName(quantity.Name)),
135+
Parameter(Identifier("max")).WithType(IdentifierName(quantity.Name))
136+
]))
137+
.WithExpressionBody(ArrowExpressionClause(InvocationExpression(
138+
MemberAccessExpression(SyntaxKind.SimpleMemberAccessExpression,
139+
InvocationExpression(IdentifierName("Max"))
140+
.WithArgumentList(ArgumentList(
141+
[Argument(IdentifierName("min"))])),
142+
IdentifierName("Min")))
143+
.WithArgumentList(ArgumentList([Argument(IdentifierName("max"))]))))
144+
.WithSemicolonToken(Token(SyntaxKind.SemicolonToken)),
145+
127146
PropertyDeclaration(PredefinedType(Token(SyntaxKind.IntKeyword)), Identifier("Sign"))
128147
.WithModifiers(TokenList(Token(SyntaxKind.PublicKeyword)))
129148
.WithAttributeLists([GeneratedCodeAttribute(typeof(QuantityStructGenerator))])
@@ -173,7 +192,8 @@ public void GenerateCode(SourceProductionContext context)
173192
SimpleBaseType(GenericName(Identifier("global::TedToolkit.Quantities.IQuantity"))
174193
.WithTypeArgumentList(TypeArgumentList([
175194
IdentifierName(quantity.Name),
176-
IdentifierName(typeName.FullName)
195+
IdentifierName(typeName.FullName),
196+
IdentifierName(quantity.UnitName),
177197
]))),
178198
]))
179199
.WithAttributeLists([GeneratedCodeAttribute(typeof(QuantityStructGenerator))])
@@ -258,7 +278,7 @@ public void GenerateCode(SourceProductionContext context)
258278
.WithType(IdentifierName(quantity.UnitName))
259279
]))
260280
.WithAttributeLists([GeneratedCodeAttribute(typeof(QuantityStructGenerator))])
261-
.WithXmlComment()
281+
.WithXmlCommentInheritDoc((string?)null)
262282
.WithBody(Block(
263283
ReturnStatement(CastExpression(
264284
IdentifierName(typeName.FullName), ParenthesizedExpression(
@@ -387,16 +407,36 @@ public void GenerateCode(SourceProductionContext context)
387407

388408
#endregion
389409

410+
#region Units
411+
412+
MethodDeclaration(IdentifierName(quantity.Name), Identifier("From"))
413+
.WithModifiers(
414+
TokenList(Token(SyntaxKind.PublicKeyword), Token(SyntaxKind.StaticKeyword)))
415+
.WithAttributeLists([GeneratedCodeAttribute(typeof(QuantityStructGenerator))])
416+
.WithXmlComment()
417+
.WithParameterList(ParameterList(
418+
[
419+
Parameter(Identifier("value"))
420+
.WithType(IdentifierName(typeName.FullName)),
421+
Parameter(Identifier("unit"))
422+
.WithType(IdentifierName(quantity.UnitName))
423+
]))
424+
.WithBody(Block(
425+
ReturnStatement(ObjectCreationExpression(IdentifierName(quantity.Name))
426+
.WithArgumentList(ArgumentList(
427+
[
428+
Argument(IdentifierName("value")),
429+
Argument(IdentifierName("unit")),
430+
]))))),
431+
390432
..quantity.Units.SelectMany(u =>
391433
{
392434
var info = data.Units[u];
393435
var unitName = info.GetUnitName(data.Units.Values);
394436
var parameterName = "@" + char.ToLowerInvariant(unitName[0]) + unitName[1..];
395437
return (IEnumerable<MemberDeclarationSyntax>)
396438
[
397-
MethodDeclaration(
398-
IdentifierName(quantity.Name),
399-
Identifier("From" + unitName))
439+
MethodDeclaration(IdentifierName(quantity.Name), Identifier("From" + unitName))
400440
.WithModifiers(
401441
TokenList(Token(SyntaxKind.PublicKeyword), Token(SyntaxKind.StaticKeyword)))
402442
.WithAttributeLists([GeneratedCodeAttribute(typeof(QuantityStructGenerator))])
@@ -439,6 +479,9 @@ public void GenerateCode(SourceProductionContext context)
439479
];
440480
}),
441481

482+
#endregion
483+
484+
442485
#region Conversions
443486

444487
ConversionOperatorDeclaration(

src/analyzers/TedToolkit.ValidResults.SourceGenerator/ValidResultsGenerator.cs

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -152,9 +152,11 @@ private static void GenerateItem(SourceProductionContext context, Dictionary<ISy
152152
.WithModifiers(TokenList(Token(SyntaxKind.PublicKeyword), Token(SyntaxKind.StaticKeyword)))
153153
.WithAttributeLists([GeneratedCodeAttribute(typeof(ValidResultsGenerator))])
154154
.WithMembers([
155-
GenerateCreateTracker(IdentifierName(target.FullName).WithTypeParameterNames(parameterNames), true),
155+
GenerateCreateTracker(IdentifierName(target.FullName).WithTypeParameterNames(parameterNames),
156+
true),
156157
GenerateCreateTracker(IdentifierName(data.GetName().FullName), false),
157-
MethodDeclaration(IdentifierName(target.Name).WithTypeParameterNames(parameterNames), Identifier("ToValidResult"))
158+
MethodDeclaration(IdentifierName(target.Name).WithTypeParameterNames(parameterNames),
159+
Identifier("ToValidResult"))
158160
.WithTypeParameterNames(parameterNames)
159161
.WithModifiers(TokenList(Token(SyntaxKind.PublicKeyword), Token(SyntaxKind.StaticKeyword)))
160162
.WithAttributeLists([
@@ -169,13 +171,15 @@ private static void GenerateItem(SourceProductionContext context, Dictionary<ISy
169171
]))
170172
.WithExpressionBody(ArrowExpressionClause(InvocationExpression(MemberAccessExpression(
171173
SyntaxKind.SimpleMemberAccessExpression,
172-
IdentifierName(target.Name).WithTypeParameterNames(parameterNames), IdentifierName("Ok")))
174+
IdentifierName(target.Name).WithTypeParameterNames(parameterNames),
175+
IdentifierName("Ok")))
173176
.WithArgumentList(ArgumentList(
174177
[
175178
Argument(IdentifierName("value"))
176179
]))))
177180
.WithSemicolonToken(Token(SyntaxKind.SemicolonToken)),
178-
..GenerateStaticMembers(members, dictionary, trackerName, baseDataSymbol, extensionMethods, parameterNames)
181+
..GenerateStaticMembers(members, dictionary, trackerName, baseDataSymbol, extensionMethods,
182+
parameterNames)
179183
]),
180184
ClassDeclaration(trackerName)
181185
.WithTypeParameterNames(parameterNames)
@@ -282,6 +286,7 @@ private static IEnumerable<MemberDeclarationSyntax> GenerateStaticMembers(IReadO
282286
.OfType<IMethodSymbol>()
283287
.Where(p => !p.ReturnType.IsRefLikeType)
284288
.Where(p => !p.IsStatic)
289+
.Where(p => p.Name is not "<Clone>$")
285290
.Where(p => !staticMethods.Contains(new MethodSignature(p))))
286291
if (method.MethodKind is MethodKind.Ordinary)
287292
yield return OrdinaryMethod(method, dictionary, trackerName, paramNames);
@@ -316,7 +321,8 @@ bool IsEffectivelyPublic(IMethodSymbol method)
316321
}
317322

318323
private static IEnumerable<MemberDeclarationSyntax> GenerateMembers(IReadOnlyCollection<ISymbol> members,
319-
Dictionary<ISymbol?, SimpleType> dictionary, string trackerName, ITypeSymbol? baseTypeSymbol, IReadOnlyCollection<ITypeParamName> paramNames)
324+
Dictionary<ISymbol?, SimpleType> dictionary, string trackerName, ITypeSymbol? baseTypeSymbol,
325+
IReadOnlyCollection<ITypeParamName> paramNames)
320326
{
321327
var propertyOrFieldNames = baseTypeSymbol?.GetMembers().OfType<IPropertySymbol>().Select(i => i.Name)
322328
.Concat(baseTypeSymbol.GetMembers().OfType<IFieldSymbol>().Select(i => i.Name)).ToArray() ?? [];
@@ -334,7 +340,8 @@ private static IEnumerable<MemberDeclarationSyntax> GenerateMembers(IReadOnlyCol
334340
.Where(p => !propertyOrFieldNames.Contains(p.Name))
335341
.Where(p => !p.Type.IsRefLikeType))
336342
yield return GenerateProperty(property.Type, property.Name, property.ContainingType,
337-
dictionary, property.GetMethod is not null, property.SetMethod is not null, property.Parameters);
343+
dictionary, property.GetMethod is not null, property.SetMethod is { IsInitOnly : false },
344+
property.Parameters);
338345

339346
foreach (var field in members
340347
.OfType<IFieldSymbol>()
@@ -365,7 +372,8 @@ private static MemberDeclarationSyntax OrdinaryMethod(IMethodSymbol method,
365372
}
366373

367374
private static MemberDeclarationSyntax StaticOrdinaryMethod(IMethodSymbol method,
368-
Dictionary<ISymbol?, SimpleType> dictionary, MethodParametersHelper.MethodType type, string trackerName, IReadOnlyCollection<ITypeParamName> paramNames)
375+
Dictionary<ISymbol?, SimpleType> dictionary, MethodParametersHelper.MethodType type, string trackerName,
376+
IReadOnlyCollection<ITypeParamName> paramNames)
369377
{
370378
return MethodParametersHelper.GenerateMethodByParameters(method,
371379
[..method.Parameters.Select(p => new ParameterRelay(p))],

src/libraries/TedToolkit.Quantities/IQuantity.cs

Lines changed: 72 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,57 @@
1-
namespace TedToolkit.Quantities;
1+
using System.Numerics;
2+
3+
namespace TedToolkit.Quantities;
24

35
/// <summary>
46
/// Quantity
57
/// </summary>
68
/// <typeparam name="TQuantity"></typeparam>
79
/// <typeparam name="TValue"></typeparam>
8-
public interface IQuantity<TQuantity, out TValue> : IQuantity<TQuantity>
9-
where TValue : struct, IConvertible
10-
where TQuantity : IQuantity<TQuantity, TValue>
10+
/// <typeparam name="TUnit"></typeparam>
11+
public interface IQuantity<TQuantity, TValue, in TUnit> :
12+
IQuantityQuantity<TQuantity>,
13+
IQuantityValue<TValue>
14+
where TValue : struct,
15+
#if NET7_0_OR_GREATER
16+
INumber<TValue>,
17+
#endif
18+
IConvertible
19+
where TQuantity : struct, IQuantity<TQuantity, TValue, TUnit>
20+
where TUnit : Enum
21+
{
22+
#if NET7_0_OR_GREATER
23+
/// <summary/>
24+
static abstract TQuantity From(TValue value, TUnit unit);
25+
#endif
26+
27+
/// <summary>
28+
///
29+
/// </summary>
30+
/// <param name="unit"></param>
31+
/// <returns></returns>
32+
TValue As(TUnit unit);
33+
34+
/// <summary>
35+
///
36+
/// </summary>
37+
/// <param name="unit"></param>
38+
/// <param name="format"></param>
39+
/// <param name="formatProvider"></param>
40+
/// <returns></returns>
41+
string ToString(TUnit unit, string? format = null, IFormatProvider? formatProvider = null);
42+
}
43+
44+
/// <summary>
45+
///
46+
/// </summary>
47+
/// <typeparam name="TValue"></typeparam>
48+
public interface IQuantityValue<out TValue> :
49+
IQuantity
50+
where TValue : struct,
51+
#if NET7_0_OR_GREATER
52+
INumber<TValue>,
53+
#endif
54+
IConvertible
1155
{
1256
/// <summary>
1357
/// The Value. In the most case, you don't need it.
@@ -19,10 +63,32 @@ public interface IQuantity<TQuantity, out TValue> : IQuantity<TQuantity>
1963
/// Quantity
2064
/// </summary>
2165
/// <typeparam name="TQuantity"></typeparam>
22-
public interface IQuantity<TQuantity> :
66+
public interface IQuantityQuantity<TQuantity> :
2367
IQuantity,
2468
IEquatable<TQuantity>,
25-
IComparable<TQuantity>;
69+
IComparable<TQuantity>
70+
where TQuantity : struct, IQuantityQuantity<TQuantity>
71+
{
72+
#if NET7_0_OR_GREATER
73+
/// <summary/>
74+
static abstract TQuantity Zero { get; }
75+
76+
/// <summary/>
77+
static abstract TQuantity One { get; }
78+
#endif
79+
80+
/// <inheritdoc cref="Math.Abs(double)"/>
81+
TQuantity Abs();
82+
83+
/// <inheritdoc cref="Math.Min(double, double)"/>
84+
TQuantity Min(TQuantity val2);
85+
86+
/// <inheritdoc cref="Math.Max(double, double)"/>
87+
TQuantity Max(TQuantity val2);
88+
89+
/// <inheritdoc cref="Math.Clamp(double, double, double)"/>
90+
TQuantity Clamp(TQuantity min, TQuantity max);
91+
}
2692

2793
/// <summary>
2894
/// Quantity

0 commit comments

Comments
 (0)