Skip to content

Commit e929244

Browse files
committed
ref struct GlobalOptionsBuilder
1 parent 2ea5149 commit e929244

File tree

3 files changed

+95
-41
lines changed

3 files changed

+95
-41
lines changed

sandbox/GeneratorSandbox/GeneratorSandbox.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
<PropertyGroup>
44
<OutputType>Exe</OutputType>
55
<TargetFramework>net8.0</TargetFramework>
6-
<LangVersion>13</LangVersion>
6+
<LangVersion>14</LangVersion>
77

88
<ImplicitUsings>enable</ImplicitUsings>
99
<Nullable>disable</Nullable>

sandbox/GeneratorSandbox/Program.cs

Lines changed: 65 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -9,56 +9,84 @@
99

1010

1111

12-
var app = ConsoleApp.Create();
12+
//var app = ConsoleApp.Create();
1313

1414

15-
args = ["--x", "10", "--y", "20", "-f", "Orange", "-v", "--prefix-output", "takoyakix"];
15+
//args = ["--x", "10", "--y", "20", "-f", "Orange", "-v", "--prefix-output", "takoyakix"];
1616

1717

18-
// Enum.TryParse<Fruit>("", true,
19-
// parse immediately
18+
//// Enum.TryParse<Fruit>("", true,
19+
//// parse immediately
2020

2121

22+
//app.ConfigureGlobalOption(x =>
23+
//{
24+
// var verbose = x.AddGlobalOption<bool>($"takoyaki", "", true);
25+
// var noColor = x.AddGlobalOption<bool>("--no-color", "Don't colorize output.");
26+
// var dryRun = x.AddGlobalOption<bool>("--dry-run");
27+
// var prefixOutput = x.AddRequiredGlobalOption<string>("--prefix-output|-pp|-po", "Prefix output with level.");
28+
29+
// return new GlobalOptions(verbose, noColor, dryRun, prefixOutput);
30+
//});
31+
32+
//app.ConfigureServices(x =>
33+
//{
34+
35+
// // new ConsoleAppContext("",
2236

23-
app.ConfigureGlobalOption(x =>
24-
{
25-
var verbose = x.AddGlobalOption<bool>($"takoyaki", "", true);
26-
var noColor = x.AddGlobalOption<bool>("--no-color", "Don't colorize output.");
27-
var dryRun = x.AddGlobalOption<bool>("--dry-run");
28-
var prefixOutput = x.AddRequiredGlobalOption<string>("--prefix-output|-pp|-po", "Prefix output with level.");
2937

30-
return (verbose, noColor, dryRun, prefixOutput);
31-
});
3238

33-
app.ConfigureServices(x =>
34-
{
3539

36-
// new ConsoleAppContext("",
3740

3841

42+
// // to use command body
43+
// //x.AddSingleton<GlobalOptions>(new GlobalOptions(verbose, noColor, dryRun, prefixOutput));
3944

45+
// //// variable for setup other DI
46+
// //x.AddLogging(l =>
47+
// //{
48+
// // var console = l.AddSimpleConsole();
49+
// // if (verbose)
50+
// // {
51+
// // console.SetMinimumLevel(LogLevel.Trace);
52+
// // }
53+
// //});
54+
//});
55+
56+
//app.Add<Commands>("");
57+
58+
//app.Run(args);
59+
60+
var app = ConsoleApp.Create();
61+
62+
63+
app.ConfigureGlobalOptions((ref builder) =>
64+
{
65+
var verbose = builder.AddGlobalOption<bool>($"takoyaki", "", true);
66+
var noColor = builder.AddGlobalOption<bool>("--no-color", "Don't colorize output.");
67+
var dryRun = builder.AddGlobalOption<bool>("--dry-run");
68+
var prefixOutput = builder.AddRequiredGlobalOption<string>("--prefix-output|-pp|-po", "Prefix output with level.");
4069

70+
return new GlobalOptions(verbose, noColor, dryRun, prefixOutput);
71+
});
4172

4273

43-
// to use command body
44-
//x.AddSingleton<GlobalOptions>(new GlobalOptions(verbose, noColor, dryRun, prefixOutput));
74+
app.Add("", (int x, int y, ConsoleAppContext context) =>
75+
{
76+
Console.WriteLine(context.CommandName);
77+
});
4578

46-
//// variable for setup other DI
47-
//x.AddLogging(l =>
48-
//{
49-
// var console = l.AddSimpleConsole();
50-
// if (verbose)
51-
// {
52-
// console.SetMinimumLevel(LogLevel.Trace);
53-
// }
54-
//});
79+
app.Add("tako", (int x, int y, ConsoleAppContext context) =>
80+
{
81+
Console.WriteLine(context.CommandName);
5582
});
5683

57-
app.Add<Commands>("");
5884

5985
app.Run(args);
6086

6187

88+
89+
6290
static T ParseArgumentEnum<T>(ref string[] args, int i)
6391
where T : struct, Enum
6492
{
@@ -83,12 +111,22 @@ static T ParseArgumentEnum<T>(ref string[] args, int i)
83111
public record GlobalOptions(bool Verbose, bool NoColor, bool DryRun, string PrefixOutput);
84112

85113

114+
internal delegate object TakoyakiX(FooStruct builder);
115+
116+
86117
public enum Fruit
87118
{
88119
Orange, Apple, Grape
89120
}
90121

91122

123+
124+
125+
public ref struct FooStruct
126+
{
127+
}
128+
129+
92130
public class Commands(GlobalOptions globalOptions)
93131
{
94132
/// <summary>

src/ConsoleAppFramework/ConsoleAppBaseCode.cs

Lines changed: 29 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -144,11 +144,13 @@ public RegisterCommandsAttribute(string commandPath)
144144
}
145145
146146
[AttributeUsage(AttributeTargets.Assembly, AllowMultiple = false, Inherited = false)]
147-
public class ConsoleAppFrameworkGeneratorOptionsAttribute : Attribute
147+
internal class ConsoleAppFrameworkGeneratorOptionsAttribute : Attribute
148148
{
149149
public bool DisableNamingConversion { get; set; }
150150
}
151151
152+
internal delegate object FuncGlobalOptionsBuilderObject(ref ConsoleApp.GlobalOptionsBuilder builder);
153+
152154
[UnconditionalSuppressMessage("Trimming", "IL2026")]
153155
[UnconditionalSuppressMessage("AOT", "IL3050")]
154156
internal static partial class ConsoleApp
@@ -461,6 +463,8 @@ public void Dispose()
461463
462464
internal partial class ConsoleAppBuilder
463465
{
466+
FuncGlobalOptionsBuilderObject? configureGlobalOptions;
467+
464468
public ConsoleAppBuilder()
465469
{
466470
}
@@ -522,18 +526,18 @@ static bool TryShowHelpOrVersion(ReadOnlySpan<string> args, int requiredParamete
522526
return false;
523527
}
524528
525-
object? configureGlobalOption;
526-
527-
public ConsoleAppBuilder ConfigureGlobalOption<T>(Func<GlobalOptionsBuilder, T> configure)
529+
public ConsoleAppBuilder ConfigureGlobalOptions(FuncGlobalOptionsBuilderObject configure)
528530
{
529-
this.configureGlobalOption = configure;
531+
this.configureGlobalOptions = configure;
530532
return this;
531533
}
532534
}
533535
534-
internal class GlobalOptionsBuilder
536+
internal ref struct GlobalOptionsBuilder
535537
{
536-
string[] args;
538+
Span<string> args;
539+
540+
ReadOnlySpan<string> Args => args;
537541
538542
public GlobalOptionsBuilder(string[] args)
539543
{
@@ -631,7 +635,7 @@ public T AddRequiredGlobalOption<T>([ConstantExpected] string name, [ConstantExp
631635
return default;
632636
}
633637
634-
static T ParseArgument<T>(ref string[] args, int i)
638+
static T ParseArgument<T>(ref Span<string> args, int i)
635639
{
636640
if (typeof(T) == typeof(bool))
637641
{
@@ -862,14 +866,26 @@ static bool TryParse<T>(string s, out T result)
862866
}
863867
}
864868
865-
static void RemoveRange(ref string[] args, int index, int length)
869+
static void RemoveRange(ref Span<string> args, int index, int length)
866870
{
867-
if (length == 0) return;
871+
if (length <= 0) return;
868872
869-
var temp = new string[args.Length - length];
870-
Array.Copy(args, temp, index);
871-
Array.Copy(args, index + length, temp, index, args.Length - index - length);
873+
// Fast path(removing from start/end) no need copy
874+
if (index == 0)
875+
{
876+
args = args.Slice(length);
877+
return;
878+
}
879+
else if (index + length == args.Length)
880+
{
881+
args = args.Slice(0, index);
882+
return;
883+
}
872884
885+
// Otherwise, need to copy
886+
var temp = new string[args.Length - length];
887+
args.Slice(0, index).CopyTo(temp);
888+
args.Slice(index + length).CopyTo(temp.AsSpan(index));
873889
args = temp;
874890
}
875891

0 commit comments

Comments
 (0)