1
+ <!DOCTYPE html> < html lang ="en "> < head > < meta charset ="utf-8 "> < meta name ="viewport " content ="width=device-width, initial-scale=1.0 "> < meta name ="generator " content ="rustdoc "> < meta name ="description " content =" "> < title > bpaf::_documentation::_0_intro - Rust</ title > < script > if ( window . location . protocol !== "file:" ) document . head . insertAdjacentHTML ( "beforeend" , "SourceSerif4-Regular-46f98efaafac5295.ttf.woff2,FiraSans-Regular-018c141bf0843ffd.woff2,FiraSans-Medium-8f9a781e4970d388.woff2,SourceCodePro-Regular-562dcc5011b6de7d.ttf.woff2,SourceCodePro-Semibold-d899c5a5c4aeb14a.ttf.woff2" . split ( "," ) . map ( f => `<link rel="preload" as="font" type="font/woff2" crossorigin href="../../../static.files/${ f } ">` ) . join ( "" ) ) </ script > < link rel ="stylesheet " href ="../../../static.files/normalize-76eba96aa4d2e634.css "> < link rel ="stylesheet " href ="../../../static.files/rustdoc-492a78a4a87dcc01.css "> < meta name ="rustdoc-vars " data-root-path ="../../../ " data-static-root-path ="../../../static.files/ " data-current-crate ="bpaf " data-themes ="" data-resource-suffix ="" data-rustdoc-version ="1.82.0 (f6e511eec 2024-10-15) " data-channel ="1.82.0 " data-search-js ="search-a99f1315e7cc5121.js " data-settings-js ="settings-4313503d2e1961c2.js " > < script src ="../../../static.files/storage-118b08c4c78b968e.js "> </ script > < script defer src ="../sidebar-items.js "> </ script > < script defer src ="../../../static.files/main-921df33f47b8780c.js "> </ script > < noscript > < link rel ="stylesheet " href ="../../../static.files/noscript-3b12f09e550e0385.css "> </ noscript > < link rel ="alternate icon " type ="image/png " href ="../../../static.files/favicon-32x32-422f7d1d52889060.png "> < link rel ="icon " type ="image/svg+xml " href ="../../../static.files/favicon-2c020d218678b618.svg "> </ head > < body class ="rustdoc mod "> <!--[if lte IE 11]><div class="warning">This old browser is unsupported and will most likely display funky things.</div><![endif]--> < nav class ="mobile-topbar "> < button class ="sidebar-menu-toggle " title ="show sidebar "> </ button > </ nav > < nav class ="sidebar "> < div class ="sidebar-crate "> < h2 > < a href ="../../../bpaf/index.html "> bpaf</ a > < span class ="version "> 0.9.15</ span > </ h2 > </ div > < h2 class ="location "> < a href ="# "> Module _0_< wbr > intro</ a > </ h2 > < div class ="sidebar-elems "> < h2 > < a href ="../index.html "> In bpaf::< wbr > _< wbr > documentation</ a > </ h2 > </ div > </ nav > < div class ="sidebar-resizer "> </ div > < main > < div class ="width-limiter "> < rustdoc-search > </ rustdoc-search > < section id ="main-content " class ="content "> < div class ="main-heading "> < h1 > Module < a href ="../../index.html "> bpaf</ a > ::< wbr > < a href ="../index.html "> _documentation</ a > ::< wbr > < a class ="mod " href ="# "> _0_intro</ a > < button id ="copy-path " title ="Copy item path to clipboard "> Copy item path</ button > </ h1 > < span class ="out-of-band "> < a class ="src " href ="../../../src/bpaf/_documentation.rs.html#11 "> source</ a > · < button id ="toggle-all-docs " title ="collapse all docs "> [< span > −</ span > ]</ button > </ span > </ div > < details class ="toggle top-doc " open > < summary class ="hideme "> < span > Expand description</ span > </ summary > < div class ="docblock "> < p > </ p >
2
+ < table width ='100% ' cellspacing ='0 ' style ='border: hidden; '> < tr >
3
+ < td style ='width: 33%; text-align: left; '>
4
+ </ td >
5
+ < td style ='width: 34%; text-align: center; '>
6
+ < p > < a href ="../index.html " title ="mod bpaf::_documentation "> ↑ Project documentation ↑</ a > </ p >
7
+ </ td >
8
+ < td style ='width: 33%; text-align: right; '>
9
+ < p > < a href ="../_1_tutorials/index.html " title ="mod bpaf::_documentation::_1_tutorials "> Tutorials →</ a > </ p >
10
+ </ td >
11
+ </ tr > </ table >
12
+ < h5 id ="introduction-and-design-goals "> < a class ="doc-anchor " href ="#introduction-and-design-goals "> §</ a > Introduction and design goals</ h5 >
13
+ < p > A quick intro. What, why and how</ p >
14
+ < p > < code > bpaf</ code > is a lightweight and flexible command line parser that uses both combinatoric and derive
15
+ style API</ p >
16
+ < p > Combinatoric API usually means a bit more typing but no dependency on proc macros and more help
17
+ from the IDE, derive API uses proc macro to save on typing but your IDE will be less likely to
18
+ help you. Picking one API style does not lock you out from using the other style, you can mix
19
+ and match both in a single parser</ p >
20
+ < h2 id ="examples-of-both-styles "> < a class ="doc-anchor " href ="#examples-of-both-styles "> §</ a > Examples of both styles</ h2 > < details > < summary > Combinatoric example</ summary >
21
+
22
+ < div class ="example-wrap "> < pre class ="rust rust-example-rendered "> < code > < span class ="kw "> use </ span > bpaf::< span class ="kw-2 "> *</ span > ;
23
+
24
+ < span class ="attr "> #[derive(Debug, Clone)]
25
+ </ span > < span class ="kw "> pub struct </ span > Options {
26
+ message: String,
27
+ }
28
+
29
+ < span class ="kw "> pub fn </ span > options() -> OptionParser<Options> {
30
+ < span class ="kw "> let </ span > message = positional(< span class ="string "> "MESSAGE"</ span > ).help(< span class ="string "> "Message to print in a big friendly letters"</ span > );
31
+ < span class ="macro "> construct!</ span > (Options { message }).to_options()
32
+ }
33
+
34
+ < span class ="kw "> fn </ span > main() {
35
+ < span class ="macro "> println!</ span > (< span class ="string "> "{:?}"</ span > , options().run())
36
+ }</ code > </ pre > </ div >
37
+ </ details >
38
+ < details > < summary > Derive example</ summary >
39
+
40
+ < div class ="example-wrap "> < pre class ="rust rust-example-rendered "> < code > < span class ="kw "> use </ span > bpaf::< span class ="kw-2 "> *</ span > ;
41
+
42
+ < span class ="attr "> #[derive(Debug, Clone, Bpaf)]
43
+ #[bpaf(options)]
44
+ </ span > < span class ="kw "> pub struct </ span > Options {
45
+ < span class ="doccomment "> /// Message to print in a big friendly letters
46
+ </ span > < span class ="attr "> #[bpaf(positional(< span class ="string "> "MESSAGE"</ span > ))]
47
+ </ span > message: String,
48
+ }
49
+
50
+ < span class ="kw "> fn </ span > main() {
51
+ < span class ="macro "> println!</ span > (< span class ="string "> "{:?}"</ span > , options().run())
52
+ }</ code > </ pre > </ div >
53
+ </ details >
54
+ < details > < summary > Output</ summary >
55
+ < p > With everything in place users should be able to pass their arguments</ p >
56
+ < div class ='bpaf-doc '>
57
+ $ app "Hello world"< br >
58
+ Options { message: "Hello world" }
59
+ </ div >
60
+ < p > As well as read the help message generated by the library</ p >
61
+ < div class ='bpaf-doc '>
62
+ $ app --help< br >
63
+ < p > < b > Usage</ b > : < tt > < b > app</ b > </ tt > < tt > < i > MESSAGE</ i > </ tt > </ p > < p > < div >
64
+ < b > Available positional items:</ b > </ div > < dl > < dt > < tt > < i > MESSAGE</ i > </ tt > </ dt >
65
+ < dd > Message to print in a big friendly letters</ dd >
66
+ </ dl >
67
+ </ p > < p > < div >
68
+ < b > Available options:</ b > </ div > < dl > < dt > < tt > < b > -h</ b > </ tt > , < tt > < b > --help</ b > </ tt > </ dt >
69
+ < dd > Prints help information</ dd >
70
+ </ dl >
71
+ </ p >
72
+ < style >
73
+ div .bpaf-doc {
74
+ padding : 14px ;
75
+ background-color : var (--code-block-background-color );
76
+ font-family : "Source Code Pro" , monospace;
77
+ margin-bottom : 0.75em ;
78
+ }
79
+ div .bpaf-doc dt { margin-left : 1em ; }
80
+ div .bpaf-doc dd { margin-left : 3em ; }
81
+ div .bpaf-doc dl { margin-top : 0 ; padding-left : 1em ; }
82
+ div .bpaf-doc { padding-left : 1em ; }
83
+ </ style >
84
+ </ div >
85
+ </ details >
86
+ < h2 id ="design-goals "> < a class ="doc-anchor " href ="#design-goals "> §</ a > Design goals</ h2 > < h3 id ="parse-dont-validate "> < a class ="doc-anchor " href ="#parse-dont-validate "> §</ a > Parse, don’t validate</ h3 >
87
+ < p > < code > bpaf</ code > tries hard to let you move as many invariants about the user input you are
88
+ trying to parse into rust types: for mutually exclusive options you can get < code > enum</ code > with
89
+ exclusive items going into separate branches, and you can collect results into types like
90
+ < a href ="https://doc.rust-lang.org/1.82.0/alloc/collections/btree/set/struct.BTreeSet.html " title ="struct alloc::collections::btree::set::BTreeSet "> < code > BTreeSet</ code > </ a > , or whatever custom type you might have with
91
+ custom parsing. Ideas for
92
+ < a href ="https://geeklaunch.io/blog/make-invalid-states-unrepresentable/ "> making invalid states unrepresentable</ a >
93
+ and < a href ="https://lexi-lambda.github.io/blog/2019/11/05/parse-don-t-validate/ "> using parsing over validation</ a >
94
+ are not new.</ p >
95
+ < p > That said you can also validate your inputs if this fits your situation better. If you want to
96
+ ensure that the sum of every numeric field must be divisible by both 3 and 5, but only when it’s
97
+ Thursday - you can do that too.</ p >
98
+ < h3 id ="flexibility "> < a class ="doc-anchor " href ="#flexibility "> §</ a > Flexibility</ h3 >
99
+ < p > While aiming to be a general-purpose command line parser < code > bpaf</ code > offers a few backdoors that
100
+ allow you to parse pretty much anything you want: chained commands, custom blocks of options,
101
+ DOS-style options (< code > /ofile.pas</ code > ), < code > dd</ code > style options (< code > if=file of=out</ code > ), etc. A similar idea applies
102
+ to what the parser can produce - if your app operates with boxed string slices internally - < code > bpaf</ code >
103
+ will give you < code > Box<str></ code > instead of < code > String</ code > if you ask it to.</ p >
104
+ < p > The only restriction is that you cannot use information from items parsed earlier (but not
105
+ the fact that something was parsed successfully or not) to decide to how to parse further
106
+ options, and even then you can side step this restriction by passing some shared state as a
107
+ parameter to the parsers.</ p >
108
+ < h3 id ="reusability "> < a class ="doc-anchor " href ="#reusability "> §</ a > Reusability</ h3 >
109
+ < p > Parsers in < code > bpaf</ code > are not monolithic and you can share their parts across multiple binaries,
110
+ workspace members or even independent projects. Say you have multiple binaries in a workspace
111
+ that perform different operations on some input. You can declare a parser for the input
112
+ specifically, along with all the validations, help messages or shell dynamic completion
113
+ functions you need and use it across all the binaries alongside the arguments specific to
114
+ those binaries.</ p >
115
+ < h3 id ="composition-transformation "> < a class ="doc-anchor " href ="#composition-transformation "> §</ a > Composition, transformation</ h3 >
116
+ < p > Parsers in < code > bpaf</ code > are not finalized either, say you have a parser that describes a single input
117
+ for your program, it can take multiple arguments or perform extra validations, etc. You can
118
+ always compose this parser with any other parser to produce tuples of both results for example.
119
+ Or to make it so parser runs multiple times and collects results into a < code > Vec</ code > .</ p >
120
+ < h3 id ="performance "> < a class ="doc-anchor " href ="#performance "> §</ a > Performance</ h3 >
121
+ < p > While performance is an explicit non-goal - < code > bpaf</ code > does nothing that would pessimize it either,
122
+ so performance is on par or better compared to other fully featured parsers.</ p >
123
+ < h3 id ="correctness "> < a class ="doc-anchor " href ="#correctness "> §</ a > Correctness</ h3 >
124
+ < p > < code > bpaf</ code > would parse only items it can represent and will reject anything it cannot represent
125
+ in the output. Say your parser accepts both < code > --intel</ code > and < code > --att</ code > flags, but encodes the result
126
+ into < code > enum Style { Intel, Att }</ code > , < code > bpaf</ code > will accept those flags separately, but not if they
127
+ are used both at once. If the parser later collects multiple styles into a < code > Vec<Style></ code > then it
128
+ will accept any combinationof those flags.</ p >
129
+ < h3 id ="user-friendly "> < a class ="doc-anchor " href ="#user-friendly "> §</ a > User friendly</ h3 >
130
+ < p > < code > bpaf</ code > tries to provide user-friendly error messages, and suggestions for typos but also scripts
131
+ for shell completion, < code > man</ code > pages and markdown documentation for the web.</ p >
132
+ < p > </ p >
133
+ < table width ='100% ' cellspacing ='0 ' style ='border: hidden; '> < tr >
134
+ < td style ='width: 33%; text-align: left; '>
135
+ </ td >
136
+ < td style ='width: 34%; text-align: center; '>
137
+ < p > < a href ="../index.html " title ="mod bpaf::_documentation "> ↑ Project documentation ↑</ a > </ p >
138
+ </ td >
139
+ < td style ='width: 33%; text-align: right; '>
140
+ < p > < a href ="../_1_tutorials/index.html " title ="mod bpaf::_documentation::_1_tutorials "> Tutorials →</ a > </ p >
141
+ </ td >
142
+ </ tr > </ table >
143
+ </ div > </ details > </ section > </ div > </ main > </ body > </ html >
0 commit comments