Skip to content

Commit

Permalink
[c#] add support for init-only setters on generated classes
Browse files Browse the repository at this point in the history
  • Loading branch information
enioluwas committed Jun 29, 2022
1 parent 79de73c commit 89974ee
Show file tree
Hide file tree
Showing 13 changed files with 540 additions and 13 deletions.
10 changes: 5 additions & 5 deletions compiler/Main.hs
Original file line number Diff line number Diff line change
Expand Up @@ -112,11 +112,11 @@ csCodegen options@Cs {..} = do
typeMapping = if collection_interfaces
then csCollectionInterfacesTypeMapping
else csTypeMapping
fieldMapping = if readonly_properties
then ReadOnlyProperties
else if fields
then PublicFields
else Properties
fieldMapping
| readonly_properties = ReadOnlyProperties
| init_only_properties = InitOnlyProperties
| fields = PublicFields
| otherwise = Properties
constructorOptions = if constructor_parameters
then ConstructorParameters
else DefaultWithProtectedBase
Expand Down
4 changes: 3 additions & 1 deletion compiler/Options.hs
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ data Options
, namespace :: [String]
, collection_interfaces :: Bool
, readonly_properties :: Bool
, init_only_properties :: Bool
, fields :: Bool
, jobs :: Maybe Int
, no_banner :: Bool
Expand Down Expand Up @@ -106,9 +107,10 @@ cs :: Options
cs = Cs
{ collection_interfaces = def &= name "c" &= help "Use interfaces rather than concrete collection types"
, readonly_properties = def &= name "r" &= help "Generate private property setters"
, init_only_properties = def &= name "init-only" &= help "Generate init-only property setters"
, fields = def &= name "f" &= help "Generate public fields rather than properties"
, structs_enabled = True &= explicit &= name "structs" &= help "Generate C# types for Bond structs and enums (true by default, use \"--structs=false\" to disable)"
, constructor_parameters = def &= explicit &= name "preview-constructor-parameters" &= help "PREVIEW FEATURE: Generate a constructor that takes all the fields as parameters. Typically used with readonly-properties."
, constructor_parameters = def &= explicit &= name "preview-constructor-parameters" &= help "PREVIEW FEATURE: Generate a constructor that takes all the fields as parameters. Typically used with readonly-properties or init-only-properties."
} &=
name "c#" &=
help "Generate C# code"
Expand Down
4 changes: 3 additions & 1 deletion compiler/src/Language/Bond/Codegen/Cs/Types_cs.hs
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,8 @@ data StructMapping =
data FieldMapping =
PublicFields | -- ^ public fields
Properties | -- ^ auto-properties
ReadOnlyProperties -- ^ auto-properties with private setter
ReadOnlyProperties | -- ^ auto-properties with private setter
InitOnlyProperties -- ^ auto-properties with init-only setter
deriving Eq

-- | Options for how constructors should be generated.
Expand Down Expand Up @@ -186,6 +187,7 @@ namespace #{csNamespace}
PublicFields -> [lt|#{optional fieldInitializer $ csDefault f};|]
Properties -> [lt| { get; set; }|]
ReadOnlyProperties -> [lt| { get; private set; }|]
InitOnlyProperties -> [lt| { get; init; }|]
fieldInitializer x = [lt| = #{x}|]
new = if isBaseField fieldName structBase then "new " else "" :: String

Expand Down
14 changes: 14 additions & 0 deletions compiler/tests/TestMain.hs
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,13 @@ tests = testGroup "Compiler tests"
]
"complex_inheritance"
"constructor-parameters"
, verifyCodegenVariation
[ "c#"
, "--preview-constructor-parameters"
, "--init-only-properties"
]
"complex_inheritance"
"constructor-parameters_init"
, verifyCodegenVariation
[ "c#"
, "--preview-constructor-parameters"
Expand Down Expand Up @@ -180,6 +187,13 @@ tests = testGroup "Compiler tests"
]
"empty_struct"
"constructor-parameters"
, verifyCodegenVariation
[ "c#"
, "--preview-constructor-parameters"
, "--init-only-properties"
]
"empty_struct"
"constructor-parameters_init"
]
, testGroup "Java"
[ verifyJavaCodegen "attributes"
Expand Down
10 changes: 5 additions & 5 deletions compiler/tests/Tests/Codegen.hs
Original file line number Diff line number Diff line change
Expand Up @@ -91,11 +91,11 @@ verifyFiles options baseName variation =
extra options
where
verify = verifyFile options baseName
fieldMapping Cs {..} = if readonly_properties
then ReadOnlyProperties
else if fields
then PublicFields
else Properties
fieldMapping Cs {..}
| readonly_properties = ReadOnlyProperties
| init_only_properties = InitOnlyProperties
| fields = PublicFields
| otherwise = Properties
constructorOptions Cs {..} = if constructor_parameters
then ConstructorParameters
else DefaultWithProtectedBase
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,210 @@


// suppress "Missing XML comment for publicly visible type or member"
#pragma warning disable 1591


#region ReSharper warnings
// ReSharper disable PartialTypeWithSinglePart
// ReSharper disable RedundantNameQualifier
// ReSharper disable InconsistentNaming
// ReSharper disable CheckNamespace
// ReSharper disable UnusedParameter.Local
// ReSharper disable RedundantUsingDirective
#endregion

namespace Test
{
using System.Collections.Generic;

[System.CodeDom.Compiler.GeneratedCode("gbc", "0.12.1.0")]
public enum TestEnum
{
EnumVal1,
EnumVal2,
EnumVal3,
}

[global::Bond.Schema]
[System.CodeDom.Compiler.GeneratedCode("gbc", "0.12.1.0")]
public partial class Simple
{
[global::Bond.Id(0)]
public int someInt { get; init; }

[global::Bond.Id(1)]
public int anotherInt { get; init; }

[global::Bond.Id(2), global::Bond.Type(typeof(global::Bond.Tag.wstring))]
public string someString { get; init; }

public Simple(
int someInt,
int anotherInt,
string someString)
{
this.someInt = someInt;
this.anotherInt = anotherInt;
this.someString = someString;
}

public Simple()
{
someString = "";
}
}

[global::Bond.Schema]
[System.CodeDom.Compiler.GeneratedCode("gbc", "0.12.1.0")]
public partial class Foo
{
[global::Bond.Id(0), global::Bond.Type(typeof(global::Bond.Tag.wstring))]
public string someText { get; init; }

public Foo(
string someText)
{
this.someText = someText;
}

public Foo()
{
someText = "BaseText1";
}
}

[global::Bond.Schema]
[System.CodeDom.Compiler.GeneratedCode("gbc", "0.12.1.0")]
public partial class Bar
: Foo
{
[global::Bond.Id(0)]
public TestEnum testEnum { get; init; }

[global::Bond.Id(1), global::Bond.Type(typeof(global::Bond.Tag.wstring))]
new public string someText { get; init; }

[global::Bond.Id(2)]
public int someInt { get; init; }

[global::Bond.Id(3), global::Bond.Type(typeof(global::Bond.Tag.wstring))]
public string moreText { get; init; }

[global::Bond.Id(4), global::Bond.Type(typeof(List<Simple>))]
public IList<Simple> someList { get; init; }

[global::Bond.Id(5), global::Bond.Type(typeof(Dictionary<global::Bond.Tag.wstring, double>))]
public IDictionary<string, double> someMap { get; init; }

[global::Bond.Id(6), global::Bond.Type(typeof(HashSet<global::Bond.Tag.wstring>))]
public ISet<string> someSet { get; init; }

public Bar(
// Base class parameters
string someText,

// This class parameters
TestEnum testEnum,
string someText0,
int someInt,
string moreText,
IList<Simple> someList,
IDictionary<string, double> someMap,
ISet<string> someSet
) : base(
someText)
{
this.testEnum = testEnum;
this.someText = someText0;
this.someInt = someInt;
this.moreText = moreText;
this.someList = someList;
this.someMap = someMap;
this.someSet = someSet;
}

public Bar()
{
testEnum = TestEnum.Val2;
someText = "DerivedText1";
moreText = "";
someList = new List<Simple>();
someMap = new Dictionary<string, double>();
someSet = new HashSet<string>();
}
}

[global::Bond.Schema]
[System.CodeDom.Compiler.GeneratedCode("gbc", "0.12.1.0")]
public partial class Baz
: Bar
{
[global::Bond.Id(0), global::Bond.Type(typeof(global::Bond.Tag.wstring))]
new public string someText { get; init; }

[global::Bond.Id(1), global::Bond.Type(typeof(global::Bond.Tag.wstring))]
public string evenMoreText { get; init; }

[global::Bond.Id(2), global::Bond.Type(typeof(global::Bond.Tag.wstring))]
public string someText1 { get; init; }

public Baz(
// Base class parameters
string someText,
TestEnum testEnum,
string someText0,
int someInt,
string moreText,
IList<Simple> someList,
IDictionary<string, double> someMap,
ISet<string> someSet,

// This class parameters
string someText1,
string evenMoreText,
string someText10
) : base(
someText,
testEnum,
someText0,
someInt,
moreText,
someList,
someMap,
someSet)
{
this.someText = someText1;
this.evenMoreText = evenMoreText;
this.someText1 = someText10;
}

public Baz()
{
someText = "";
evenMoreText = "";
someText1 = "";
}
}

[global::Bond.Schema]
[System.CodeDom.Compiler.GeneratedCode("gbc", "0.12.1.0")]
public partial class DerivedEmpty
: Foo
{


public DerivedEmpty(
// Base class parameters
string someText
) : base(
someText)
{

}

public DerivedEmpty()
{

}
}
} // Test
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@


// suppress "Missing XML comment for publicly visible type or member"
#pragma warning disable 1591


#region ReSharper warnings
// ReSharper disable PartialTypeWithSinglePart
// ReSharper disable RedundantNameQualifier
// ReSharper disable InconsistentNaming
// ReSharper disable CheckNamespace
// ReSharper disable UnusedParameter.Local
// ReSharper disable RedundantUsingDirective
#endregion

namespace tests
{
using System.Collections.Generic;

[global::Bond.Schema]
[System.CodeDom.Compiler.GeneratedCode("gbc", "0.12.1.0")]
public partial class Empty
{

public Empty()
{

}
}
} // tests
Loading

0 comments on commit 89974ee

Please sign in to comment.