-
Notifications
You must be signed in to change notification settings - Fork 75
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Avoid attributes recomputation #109
Changes from 2 commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -9,6 +9,23 @@ open System.Text.RegularExpressions | |
|
||
open FSharp.Reflection | ||
|
||
[<AutoOpen>] | ||
module private FastAttributes = | ||
let inline hasAttribute<'T when 'T :> Attribute> (attributes: obj[]) = | ||
attributes |> Array.tryFindIndex (fun x -> x :? 'T) <> None | ||
|
||
let inline hasAttribute2<'T when 'T :> Attribute> (attributes1: obj[]) (attributes2: Attribute[]) = | ||
(hasAttribute<'T> attributes1) || (attributes2 |> Array.tryFindIndex (fun x -> x :? 'T) <> None) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Same |
||
|
||
let inline tryGetAttribute<'T when 'T :> Attribute> (attributes: obj[]) = | ||
attributes |> Array.tryFind (fun x -> x :? 'T) |> Option.map (fun x -> x :?> 'T) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Replace with There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
|
||
let inline tryGetAttribute2<'T when 'T :> Attribute> (attributes: obj[]) (attributes2: Attribute[]) = | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Please use There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'll rename them. But I can't change the type of the first argument, it's what There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Pretty sure you could map the array though. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes, everything in it is an In fact if it's ok with you i'll find what makes the second array contains |
||
match tryGetAttribute<'T> attributes with | ||
| Some _ as attr -> attr | ||
| None -> | ||
attributes2 |> Array.tryFind (fun x -> x :? 'T) |> Option.map (fun x -> x :?> 'T) | ||
|
||
let defaultHelpParam = "help" | ||
let defaultHelpDescription = "display this list of options." | ||
|
||
|
@@ -21,9 +38,9 @@ let getDefaultHelpParam (t : Type) = | |
prefixString + defaultHelpParam | ||
|
||
/// construct a CLI param from UCI name | ||
let generateOptionName (uci : UnionCaseInfo) = | ||
let generateOptionName (uci : UnionCaseInfo) (attributes1: obj[]) (attributes2: Attribute[])= | ||
let prefixString = | ||
match uci.TryGetAttribute<CliPrefixAttribute>(true) with | ||
match tryGetAttribute2<CliPrefixAttribute> attributes1 attributes2 with | ||
| None -> CliPrefix.DoubleDash | ||
| Some pf -> pf.Prefix | ||
|
||
|
@@ -133,7 +150,7 @@ let tryGetDuEnumerationParser label (t : Type) = | |
let tagReader = lazy(FSharpValue.PreComputeUnionTagReader(t, allBindings)) | ||
let extractUciInfo (uci : UnionCaseInfo) = | ||
let name = | ||
match uci.TryGetAttribute<CustomCommandLineAttribute>() with | ||
match tryGetAttribute<CustomCommandLineAttribute> (uci.GetCustomAttributes()) with | ||
| None -> generateEnumName uci.Name | ||
| Some attr -> attr.Name | ||
|
||
|
@@ -280,18 +297,21 @@ let rec private preComputeUnionCaseArgInfo (stack : Type list) (helpParam : Help | |
let current = ref None | ||
let tryGetCurrent = fun () -> !current | ||
|
||
let isNoCommandLine = lazy(uci.ContainsAttribute<NoCommandLineAttribute> (true)) | ||
let isAppSettingsCSV = lazy(uci.ContainsAttribute<ParseCSVAttribute> ()) | ||
let isExactlyOnce = lazy(uci.ContainsAttribute<ExactlyOnceAttribute> (true)) | ||
let isMandatory = lazy(isExactlyOnce.Value || uci.ContainsAttribute<MandatoryAttribute> (true)) | ||
let isUnique = lazy(isExactlyOnce.Value || uci.ContainsAttribute<UniqueAttribute> (true)) | ||
let isInherited = lazy(uci.ContainsAttribute<InheritAttribute> ()) | ||
let isGatherAll = lazy(uci.ContainsAttribute<GatherAllSourcesAttribute> ()) | ||
let isRest = lazy(uci.ContainsAttribute<RestAttribute> ()) | ||
let isHidden = lazy(uci.ContainsAttribute<HiddenAttribute> ()) | ||
let attributes = lazy(uci.GetCustomAttributes()) | ||
let declaringTypeAttributes = lazy(uci.DeclaringType.GetCustomAttributes() |> Array.ofSeq) | ||
|
||
let isNoCommandLine = lazy(hasAttribute2<NoCommandLineAttribute> attributes.Value declaringTypeAttributes.Value) | ||
let isAppSettingsCSV = lazy(hasAttribute<ParseCSVAttribute> attributes.Value) | ||
let isExactlyOnce = lazy(hasAttribute2<ExactlyOnceAttribute> attributes.Value declaringTypeAttributes.Value) | ||
let isMandatory = lazy(isExactlyOnce.Value || hasAttribute2<MandatoryAttribute> attributes.Value declaringTypeAttributes.Value) | ||
let isUnique = lazy(isExactlyOnce.Value || hasAttribute2<UniqueAttribute> attributes.Value declaringTypeAttributes.Value) | ||
let isInherited = lazy(hasAttribute<InheritAttribute> attributes.Value) | ||
let isGatherAll = lazy(hasAttribute<GatherAllSourcesAttribute> attributes.Value) | ||
let isRest = lazy(hasAttribute<RestAttribute> attributes.Value) | ||
let isHidden = lazy(hasAttribute<HiddenAttribute> attributes.Value) | ||
|
||
let mainCommandName = lazy( | ||
match uci.TryGetAttribute<MainCommandAttribute> () with | ||
match tryGetAttribute<MainCommandAttribute> attributes.Value with | ||
| None -> None | ||
| Some _ when isNoCommandLine.Value -> arguExn "parameter '%O' contains conflicting attributes 'MainCommand' and 'NoCommandLine'." uci | ||
| Some _ when types.Length = 0 -> arguExn "parameter '%O' contains MainCommand attribute but has unsupported arity 0." uci | ||
|
@@ -304,7 +324,7 @@ let rec private preComputeUnionCaseArgInfo (stack : Type list) (helpParam : Help | |
let isMainCommand = lazy(Option.isSome mainCommandName.Value) | ||
|
||
let cliPosition = lazy( | ||
match uci.TryGetAttribute<CliPositionAttribute> () with | ||
match tryGetAttribute<CliPositionAttribute> attributes.Value with | ||
| Some attr -> | ||
match attr.Position with | ||
| CliPosition.Unspecified | ||
|
@@ -314,7 +334,7 @@ let rec private preComputeUnionCaseArgInfo (stack : Type list) (helpParam : Help | |
| None -> CliPosition.Unspecified) | ||
|
||
let customAssignmentSeparator = lazy( | ||
match uci.TryGetAttribute<CustomAssignmentAttribute> (true) with | ||
match tryGetAttribute2<CustomAssignmentAttribute> attributes.Value declaringTypeAttributes.Value with | ||
| Some attr -> | ||
if isMainCommand.Value && types.Length = 1 then | ||
arguExn "parameter '%O' of arity 1 contains incompatible attributes 'CustomAssignment' and 'MainCommand'." uci | ||
|
@@ -329,7 +349,7 @@ let rec private preComputeUnionCaseArgInfo (stack : Type list) (helpParam : Help | |
| None -> None) | ||
|
||
let isGatherUnrecognized = lazy( | ||
if uci.ContainsAttribute<GatherUnrecognizedAttribute>() then | ||
if hasAttribute<GatherUnrecognizedAttribute> attributes.Value then | ||
match types with | ||
| _ when isMainCommand.Value -> arguExn "parameter '%O' contains incompatible combination of attributes 'MainCommand' and 'GatherUnrecognized'." uci | ||
| [|t|] when t = typeof<string> -> true | ||
|
@@ -338,7 +358,7 @@ let rec private preComputeUnionCaseArgInfo (stack : Type list) (helpParam : Help | |
false) | ||
|
||
let appSettingsSeparators, appSettingsSplitOptions = | ||
match uci.TryGetAttribute<AppSettingsSeparatorAttribute> (true) with | ||
match tryGetAttribute2<AppSettingsSeparatorAttribute> attributes.Value declaringTypeAttributes.Value with | ||
| None -> [|","|], StringSplitOptions.None | ||
| Some attr when attr.Separators.Length = 0 -> | ||
arguExn "parameter '%O' specifies a null or empty AppSettings separator." uci | ||
|
@@ -408,23 +428,24 @@ let rec private preComputeUnionCaseArgInfo (stack : Type list) (helpParam : Help | |
if isMainCommand.Value || isNoCommandLine.Value then [] | ||
else | ||
let cliNames = [ | ||
match uci.TryGetAttribute<CustomCommandLineAttribute> () with | ||
| None -> yield generateOptionName uci | ||
match tryGetAttribute<CustomCommandLineAttribute> attributes.Value with | ||
| None -> yield generateOptionName uci attributes.Value declaringTypeAttributes.Value | ||
| Some attr -> yield attr.Name ; yield! attr.AltNames | ||
|
||
yield! | ||
uci.GetAttributes<AltCommandLineAttribute>() | ||
|> Seq.collect (fun attr -> attr.Names) | ||
attributes.Value | ||
|> Array.filter (fun x -> x :? AltCommandLineAttribute) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Could be inlined into a single Array.collect |
||
|> Array.collect(fun x -> (x :?> AltCommandLineAttribute).Names) | ||
] | ||
|
||
for name in cliNames do validateCliParam name | ||
|
||
cliNames) | ||
|
||
let appSettingsName = lazy( | ||
if uci.ContainsAttribute<NoAppSettingsAttribute> (true) then None | ||
if hasAttribute2<NoAppSettingsAttribute> attributes.Value declaringTypeAttributes.Value then None | ||
else | ||
match uci.TryGetAttribute<CustomAppSettingsAttribute> () with | ||
match tryGetAttribute<CustomAppSettingsAttribute> attributes.Value with | ||
| None -> Some <| generateAppSettingsName uci | ||
| Some _ when parsers.Value.Type = ArgumentType.SubCommand -> arguExn "CustomAppSettings in %O not supported in subcommands." uci | ||
| Some attr when not <| String.IsNullOrWhiteSpace attr.Name -> Some attr.Name | ||
|
@@ -437,12 +458,12 @@ let rec private preComputeUnionCaseArgInfo (stack : Type list) (helpParam : Help | |
| [] when isMainCommand.Value -> | ||
match parsers.Value with | ||
| Primitives ps -> | ||
let name = ps |> Seq.map (fun p -> sprintf "<%s>" p.Description) |> String.concat " " | ||
let name = ps |> Seq.map (fun p -> "<" + p.Description + ">" ) |> String.concat " " | ||
if isRest.Value then name + "..." else name | ||
| ListParam(_,p) -> sprintf "<%s>..." p.Description | ||
| _ -> arguExn "internal error in argu parser representation %O." uci | ||
| ListParam(_,p) -> "<" + p.Description + ">..." | ||
| _ -> raise <| new ArguException("internal error in argu parser representation " + (uci.ToString()) + ".") | ||
| _ when Option.isSome appSettingsName.Value -> appSettingsName.Value.Value | ||
| _ -> arguExn "parameter '%O' needs to have at least one parse source." uci) | ||
| _ -> raise <| new ArguException("parameter '" + (uci.ToString()) + "' needs to have at least one parse source.")) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm not a fan of this change, premature optimization where raised exception would be the dominating factor. Please revert. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ah yes I need to measure, I changed all the printf initialization but I don't think this one is hit. |
||
|
||
let fieldReader = Helpers.fieldReader uci | ||
let fieldCtor = Helpers.tupleConstructor types | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Shouldn't
Array.exists
suffice here?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah yes
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(I need to find a way to remember the name of this method, each time I stay on
contains
but it's not what I want and I end up rewriting it by other means)