Skip to content

Commit

Permalink
Merge pull request #1052 from microsoft/fix1051
Browse files Browse the repository at this point in the history
Add implicit conversions between `bool` and `VARIANT_BOOL`
  • Loading branch information
AArnott authored Sep 22, 2023
2 parents 33ecc79 + f9e49cc commit dd815b2
Show file tree
Hide file tree
Showing 5 changed files with 120 additions and 2 deletions.
23 changes: 21 additions & 2 deletions src/Microsoft.Windows.CsWin32/Generator.GeneratedCode.cs
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,11 @@ private class GeneratedCode
/// </summary>
private readonly Dictionary<MethodDefinitionHandle, Exception?> methodsGenerating = new();

/// <summary>
/// The constants that are or have been generated.
/// </summary>
private readonly Dictionary<FieldDefinitionHandle, Exception?> constantsGenerating = new();

/// <summary>
/// A collection of the names of special types we are or have generated.
/// </summary>
Expand Down Expand Up @@ -303,12 +308,26 @@ internal void GenerateConstant(FieldDefinitionHandle fieldDefinitionHandle, Acti
{
this.ThrowIfNotGenerating();

if (this.fieldsToSyntax.ContainsKey(fieldDefinitionHandle) || this.parent?.fieldsToSyntax.ContainsKey(fieldDefinitionHandle) is true)
if (this.constantsGenerating.TryGetValue(fieldDefinitionHandle, out Exception? failure) || this.parent?.constantsGenerating.TryGetValue(fieldDefinitionHandle, out failure) is true)
{
if (failure is object)
{
throw new GenerationFailedException("This constant already failed in generation previously.", failure);
}

return;
}

generator();
this.constantsGenerating.Add(fieldDefinitionHandle, null);
try
{
generator();
}
catch (Exception ex)
{
this.constantsGenerating[fieldDefinitionHandle] = ex;
throw;
}
}

internal void GenerateMacro(string macroName, Action generator)
Expand Down
5 changes: 5 additions & 0 deletions src/Microsoft.Windows.CsWin32/Generator.TypeDef.cs
Original file line number Diff line number Diff line change
Expand Up @@ -200,6 +200,11 @@ private StructDeclarationSyntax DeclareTypeDefStruct(TypeDefinition typeDef, Typ
members = AddOrReplaceMembers(members, this.ExtractMembersFromTemplate(name.Identifier.ValueText));
this.TryGenerateType("Windows.Win32.Foundation.PC" + name.Identifier.ValueText.Substring(1)); // the template references its constant version
break;
case "VARIANT_BOOL":
members = AddOrReplaceMembers(members, this.ExtractMembersFromTemplate(name.Identifier.ValueText));
this.TryGenerateConstant("VARIANT_TRUE", out _); // the template references its constant version
this.TryGenerateConstant("VARIANT_FALSE", out _); // the template references its constant version
break;
case "BSTR":
case "HRESULT":
case "NTSTATUS":
Expand Down
6 changes: 6 additions & 0 deletions src/Microsoft.Windows.CsWin32/templates/VARIANT_BOOL.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
partial struct VARIANT_BOOL
{
internal VARIANT_BOOL(bool value) => this.Value = value ? VARIANT_TRUE : VARIANT_FALSE;
public static implicit operator bool(VARIANT_BOOL value) => value != VARIANT_FALSE;
public static implicit operator VARIANT_BOOL(bool value) => value ? VARIANT_TRUE : VARIANT_FALSE;
}
87 changes: 87 additions & 0 deletions test/GenerationSandbox.Tests/VARIANT_BOOLTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.

using Windows.Win32.Foundation;

public class VARIANT_BOOLTests
{
[Fact]
public void Ctor_bool()
{
VARIANT_BOOL b = true;
bool b2 = b;
Assert.True(b);
Assert.True(b2);

Assert.False(default(VARIANT_BOOL));
}

[Fact]
public void Ctor_int()
{
Assert.Equal(2, new VARIANT_BOOL(2).Value);
}

[Fact]
public void ExplicitCast()
{
Assert.Equal(2, ((VARIANT_BOOL)2).Value);
}

[Theory]
[InlineData(3)]
[InlineData(-1)]
[InlineData(0)]
[InlineData(1)]
[InlineData(0xfff)]
public void LossyConversionFromBOOLtoBool(short ordinal)
{
VARIANT_BOOL nativeBool = new VARIANT_BOOL(ordinal);
bool managedBool = nativeBool;
Assert.Equal(ordinal != 0, managedBool);
BOOLEAN roundtrippedNativeBool = managedBool;
Assert.Equal(managedBool ? 1 : 0, roundtrippedNativeBool);
}

[Fact]
public void BOOLEqualsComparesExactValue()
{
VARIANT_BOOL b1 = new VARIANT_BOOL(1);
VARIANT_BOOL b2 = new VARIANT_BOOL(2);
Assert.Equal(b1, b1);
Assert.NotEqual(b1, b2);
}

[Fact]
public void BOOL_OverridesEqualityOperator()
{
var @true = new VARIANT_BOOL(true);
var @false = new VARIANT_BOOL(false);
Assert.True(@true == new VARIANT_BOOL(true));
Assert.False(@true != new VARIANT_BOOL(true));
Assert.True(@true != @false);
Assert.False(@true == @false);

var two = new VARIANT_BOOL(2);
Assert.False(two == @true);
Assert.True(two != @true);
}

[Fact]
public void LogicalOperators_And()
{
VARIANT_BOOL @true = true, @false = false;
Assert.False(@false && @false);
Assert.False(@true && @false);
Assert.True(@true && @true);
}

[Fact]
public void LogicalOperators_Or()
{
VARIANT_BOOL @true = true, @false = false;
Assert.True(@true || @false);
Assert.False(@false || @false);
Assert.True(@true || @true);
}
}
1 change: 1 addition & 0 deletions test/Microsoft.Windows.CsWin32.Tests/StructTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,7 @@ public void SpecialStruct_ByRequest(string structName)
[CombinatorialData]
public void InterestingStructs(
[CombinatorialValues(
"VARIANT_BOOL", // has a custom conversion to bool and relies on other members being generated
"DRIVER_OBJECT", // has an inline array of delegates
"DEVICE_RELATIONS", // ends with an inline "flexible" array
"D3DHAL_CONTEXTCREATEDATA", // contains a field that is a pointer to a struct that is normally managed
Expand Down

0 comments on commit dd815b2

Please sign in to comment.