├── .github └── workflows │ └── ci.yml ├── .gitignore ├── Cargo.toml ├── LICENSE-APACHE ├── LICENSE-MIT ├── README.md ├── proconio-derive ├── Cargo.toml ├── README.md └── src │ ├── derive_readable.rs │ ├── fastout.rs │ └── lib.rs └── proconio ├── Cargo.toml ├── README.md ├── src ├── lib.rs ├── marker.rs └── source │ ├── line.rs │ ├── mod.rs │ ├── once.rs │ └── tokens.rs └── tests ├── derive.rs ├── fastout.rs ├── interactive.rs ├── issue_14.rs ├── read_value.rs ├── stdin.rs ├── ui.rs └── ui └── fastout ├── argument-never-used.rs ├── argument-never-used.stderr ├── format-argument-must-be-a-string-literal.rs ├── format-argument-must-be-a-string-literal.stderr ├── print-macros-in-closures.rs ├── print-macros-in-closures.stderr ├── requires-at-least-a-format-string-argument.rs └── requires-at-least-a-format-string-argument.stderr /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | 3 | on: 4 | schedule: 5 | - cron: 0 0 1 * * 6 | push: 7 | pull_request: 8 | 9 | jobs: 10 | rustfmt: 11 | name: Rustfmt 12 | runs-on: ubuntu-24.04 13 | 14 | steps: 15 | - uses: actions/checkout@v4 16 | 17 | - uses: dtolnay/rust-toolchain@master 18 | with: 19 | toolchain: stable 20 | components: rustfmt 21 | 22 | - name: "`cargo fmt --all -- --check`" 23 | run: cargo fmt --all -- --check 24 | 25 | build: 26 | strategy: 27 | fail-fast: false 28 | matrix: 29 | channel: 30 | - 1.70.0 31 | - stable 32 | - beta 33 | target_triple: 34 | - x86_64-pc-windows-msvc 35 | - x86_64-pc-windows-gnu 36 | - aarch64-apple-darwin 37 | - x86_64-unknown-linux-gnu 38 | - x86_64-unknown-linux-musl 39 | include: 40 | - channel: 1.70.0 41 | target_triple: x86_64-pc-windows-msvc 42 | host_triple: x86_64-pc-windows-msvc 43 | os: windows-latest 44 | - channel: 1.70.0 45 | target_triple: x86_64-pc-windows-gnu 46 | host_triple: x86_64-pc-windows-gnu 47 | os: windows-latest 48 | - channel: 1.70.0 49 | target_triple: aarch64-apple-darwin 50 | host_triple: aarch64-apple-darwin 51 | os: macOS-15 52 | - channel: 1.70.0 53 | target_triple: x86_64-unknown-linux-gnu 54 | host_triple: x86_64-unknown-linux-gnu 55 | os: ubuntu-24.04 56 | - channel: 1.70.0 57 | target_triple: x86_64-unknown-linux-musl 58 | host_triple: x86_64-unknown-linux-gnu 59 | os: ubuntu-24.04 60 | - channel: stable 61 | target_triple: x86_64-pc-windows-msvc 62 | host_triple: x86_64-pc-windows-msvc 63 | os: windows-latest 64 | - channel: stable 65 | target_triple: x86_64-pc-windows-gnu 66 | host_triple: x86_64-pc-windows-gnu 67 | os: windows-latest 68 | - channel: stable 69 | target_triple: aarch64-apple-darwin 70 | host_triple: aarch64-apple-darwin 71 | os: macOS-15 72 | - channel: stable 73 | target_triple: x86_64-unknown-linux-gnu 74 | host_triple: x86_64-unknown-linux-gnu 75 | os: ubuntu-24.04 76 | - channel: stable 77 | target_triple: x86_64-unknown-linux-musl 78 | host_triple: x86_64-unknown-linux-gnu 79 | os: ubuntu-24.04 80 | - channel: beta 81 | target_triple: x86_64-pc-windows-msvc 82 | host_triple: x86_64-pc-windows-msvc 83 | os: windows-latest 84 | - channel: beta 85 | target_triple: x86_64-pc-windows-gnu 86 | host_triple: x86_64-pc-windows-gnu 87 | os: windows-latest 88 | - channel: beta 89 | target_triple: aarch64-apple-darwin 90 | host_triple: aarch64-apple-darwin 91 | os: macOS-15 92 | - channel: beta 93 | target_triple: x86_64-unknown-linux-gnu 94 | host_triple: x86_64-unknown-linux-gnu 95 | os: ubuntu-24.04 96 | - channel: beta 97 | target_triple: x86_64-unknown-linux-musl 98 | host_triple: x86_64-unknown-linux-gnu 99 | os: ubuntu-24.04 100 | 101 | name: ${{ matrix.channel }}-${{ matrix.target_triple }} 102 | runs-on: ${{ matrix.os }} 103 | 104 | steps: 105 | - uses: actions/checkout@v4 106 | 107 | - name: "`sudo apt-get install musl-tools`" 108 | run: sudo apt-get install musl-tools 109 | if: matrix.target_triple == 'x86_64-unknown-linux-musl' 110 | 111 | - uses: dtolnay/rust-toolchain@master 112 | with: 113 | toolchain: ${{ matrix.channel }}-${{ matrix.host_triple }} 114 | targets: ${{ matrix.target_triple }} 115 | components: clippy 116 | 117 | - name: "`cargo clippy --workspace --all-targets --all-features --target ${{ matrix.target_triple }} -v -- -D warnings`" 118 | run: cargo clippy --workspace --all-targets --all-features --target ${{ matrix.target_triple }} -v -- -D warnings 119 | 120 | - name: "`cargo test --no-fail-fast --workspace --all-features --target ${{ matrix.target_triple }} -v`" 121 | run: cargo test --no-fail-fast --workspace --all-features --target ${{ matrix.target_triple }} -v 122 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | **/target 2 | **/*.rs.bk 3 | Cargo.lock 4 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [workspace] 2 | members = ["proconio", "proconio-derive"] 3 | -------------------------------------------------------------------------------- /LICENSE-APACHE: -------------------------------------------------------------------------------- 1 | 2 | Apache License 3 | Version 2.0, January 2004 4 | http://www.apache.org/licenses/ 5 | 6 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 7 | 8 | 1. Definitions. 9 | 10 | "License" shall mean the terms and conditions for use, reproduction, 11 | and distribution as defined by Sections 1 through 9 of this document. 12 | 13 | "Licensor" shall mean the copyright owner or entity authorized by 14 | the copyright owner that is granting the License. 15 | 16 | "Legal Entity" shall mean the union of the acting entity and all 17 | other entities that control, are controlled by, or are under common 18 | control with that entity. For the purposes of this definition, 19 | "control" means (i) the power, direct or indirect, to cause the 20 | direction or management of such entity, whether by contract or 21 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 22 | outstanding shares, or (iii) beneficial ownership of such entity. 23 | 24 | "You" (or "Your") shall mean an individual or Legal Entity 25 | exercising permissions granted by this License. 26 | 27 | "Source" form shall mean the preferred form for making modifications, 28 | including but not limited to software source code, documentation 29 | source, and configuration files. 30 | 31 | "Object" form shall mean any form resulting from mechanical 32 | transformation or translation of a Source form, including but 33 | not limited to compiled object code, generated documentation, 34 | and conversions to other media types. 35 | 36 | "Work" shall mean the work of authorship, whether in Source or 37 | Object form, made available under the License, as indicated by a 38 | copyright notice that is included in or attached to the work 39 | (an example is provided in the Appendix below). 40 | 41 | "Derivative Works" shall mean any work, whether in Source or Object 42 | form, that is based on (or derived from) the Work and for which the 43 | editorial revisions, annotations, elaborations, or other modifications 44 | represent, as a whole, an original work of authorship. For the purposes 45 | of this License, Derivative Works shall not include works that remain 46 | separable from, or merely link (or bind by name) to the interfaces of, 47 | the Work and Derivative Works thereof. 48 | 49 | "Contribution" shall mean any work of authorship, including 50 | the original version of the Work and any modifications or additions 51 | to that Work or Derivative Works thereof, that is intentionally 52 | submitted to Licensor for inclusion in the Work by the copyright owner 53 | or by an individual or Legal Entity authorized to submit on behalf of 54 | the copyright owner. For the purposes of this definition, "submitted" 55 | means any form of electronic, verbal, or written communication sent 56 | to the Licensor or its representatives, including but not limited to 57 | communication on electronic mailing lists, source code control systems, 58 | and issue tracking systems that are managed by, or on behalf of, the 59 | Licensor for the purpose of discussing and improving the Work, but 60 | excluding communication that is conspicuously marked or otherwise 61 | designated in writing by the copyright owner as "Not a Contribution." 62 | 63 | "Contributor" shall mean Licensor and any individual or Legal Entity 64 | on behalf of whom a Contribution has been received by Licensor and 65 | subsequently incorporated within the Work. 66 | 67 | 2. Grant of Copyright License. Subject to the terms and conditions of 68 | this License, each Contributor hereby grants to You a perpetual, 69 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 70 | copyright license to reproduce, prepare Derivative Works of, 71 | publicly display, publicly perform, sublicense, and distribute the 72 | Work and such Derivative Works in Source or Object form. 73 | 74 | 3. Grant of Patent License. Subject to the terms and conditions of 75 | this License, each Contributor hereby grants to You a perpetual, 76 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 77 | (except as stated in this section) patent license to make, have made, 78 | use, offer to sell, sell, import, and otherwise transfer the Work, 79 | where such license applies only to those patent claims licensable 80 | by such Contributor that are necessarily infringed by their 81 | Contribution(s) alone or by combination of their Contribution(s) 82 | with the Work to which such Contribution(s) was submitted. If You 83 | institute patent litigation against any entity (including a 84 | cross-claim or counterclaim in a lawsuit) alleging that the Work 85 | or a Contribution incorporated within the Work constitutes direct 86 | or contributory patent infringement, then any patent licenses 87 | granted to You under this License for that Work shall terminate 88 | as of the date such litigation is filed. 89 | 90 | 4. Redistribution. You may reproduce and distribute copies of the 91 | Work or Derivative Works thereof in any medium, with or without 92 | modifications, and in Source or Object form, provided that You 93 | meet the following conditions: 94 | 95 | (a) You must give any other recipients of the Work or 96 | Derivative Works a copy of this License; and 97 | 98 | (b) You must cause any modified files to carry prominent notices 99 | stating that You changed the files; and 100 | 101 | (c) You must retain, in the Source form of any Derivative Works 102 | that You distribute, all copyright, patent, trademark, and 103 | attribution notices from the Source form of the Work, 104 | excluding those notices that do not pertain to any part of 105 | the Derivative Works; and 106 | 107 | (d) If the Work includes a "NOTICE" text file as part of its 108 | distribution, then any Derivative Works that You distribute must 109 | include a readable copy of the attribution notices contained 110 | within such NOTICE file, excluding those notices that do not 111 | pertain to any part of the Derivative Works, in at least one 112 | of the following places: within a NOTICE text file distributed 113 | as part of the Derivative Works; within the Source form or 114 | documentation, if provided along with the Derivative Works; or, 115 | within a display generated by the Derivative Works, if and 116 | wherever such third-party notices normally appear. The contents 117 | of the NOTICE file are for informational purposes only and 118 | do not modify the License. You may add Your own attribution 119 | notices within Derivative Works that You distribute, alongside 120 | or as an addendum to the NOTICE text from the Work, provided 121 | that such additional attribution notices cannot be construed 122 | as modifying the License. 123 | 124 | You may add Your own copyright statement to Your modifications and 125 | may provide additional or different license terms and conditions 126 | for use, reproduction, or distribution of Your modifications, or 127 | for any such Derivative Works as a whole, provided Your use, 128 | reproduction, and distribution of the Work otherwise complies with 129 | the conditions stated in this License. 130 | 131 | 5. Submission of Contributions. Unless You explicitly state otherwise, 132 | any Contribution intentionally submitted for inclusion in the Work 133 | by You to the Licensor shall be under the terms and conditions of 134 | this License, without any additional terms or conditions. 135 | Notwithstanding the above, nothing herein shall supersede or modify 136 | the terms of any separate license agreement you may have executed 137 | with Licensor regarding such Contributions. 138 | 139 | 6. Trademarks. This License does not grant permission to use the trade 140 | names, trademarks, service marks, or product names of the Licensor, 141 | except as required for reasonable and customary use in describing the 142 | origin of the Work and reproducing the content of the NOTICE file. 143 | 144 | 7. Disclaimer of Warranty. Unless required by applicable law or 145 | agreed to in writing, Licensor provides the Work (and each 146 | Contributor provides its Contributions) on an "AS IS" BASIS, 147 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 148 | implied, including, without limitation, any warranties or conditions 149 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 150 | PARTICULAR PURPOSE. You are solely responsible for determining the 151 | appropriateness of using or redistributing the Work and assume any 152 | risks associated with Your exercise of permissions under this License. 153 | 154 | 8. Limitation of Liability. In no event and under no legal theory, 155 | whether in tort (including negligence), contract, or otherwise, 156 | unless required by applicable law (such as deliberate and grossly 157 | negligent acts) or agreed to in writing, shall any Contributor be 158 | liable to You for damages, including any direct, indirect, special, 159 | incidental, or consequential damages of any character arising as a 160 | result of this License or out of the use or inability to use the 161 | Work (including but not limited to damages for loss of goodwill, 162 | work stoppage, computer failure or malfunction, or any and all 163 | other commercial damages or losses), even if such Contributor 164 | has been advised of the possibility of such damages. 165 | 166 | 9. Accepting Warranty or Additional Liability. While redistributing 167 | the Work or Derivative Works thereof, You may choose to offer, 168 | and charge a fee for, acceptance of support, warranty, indemnity, 169 | or other liability obligations and/or rights consistent with this 170 | License. However, in accepting such obligations, You may act only 171 | on Your own behalf and on Your sole responsibility, not on behalf 172 | of any other Contributor, and only if You agree to indemnify, 173 | defend, and hold each Contributor harmless for any liability 174 | incurred by, or claims asserted against, such Contributor by reason 175 | of your accepting any such warranty or additional liability. 176 | 177 | END OF TERMS AND CONDITIONS 178 | 179 | Copyright for original `input!` macro is held by Hideyuki Tanaka, 2019. The 180 | original macro is licensed under BSD 3-clause license. 181 | 182 | Redistribution and use in source and binary forms, with or without 183 | modification, are permitted provided that the following conditions are met: 184 | 185 | 1. Redistributions of source code must retain the above copyright notice, this 186 | list of conditions and the following disclaimer. 187 | 188 | 2. Redistributions in binary form must reproduce the above copyright notice, 189 | this list of conditions and the following disclaimer in the documentation 190 | and/or other materials provided with the distribution. 191 | 192 | 3. Neither the name of the copyright holder nor the names of its contributors 193 | may be used to endorse or promote products derived from this software 194 | without specific prior written permission. 195 | 196 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 197 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 198 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 199 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 200 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 201 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 202 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 203 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 204 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 205 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 206 | -------------------------------------------------------------------------------- /LICENSE-MIT: -------------------------------------------------------------------------------- 1 | The MIT License 2 | Copyright 2019 (C) statiolake 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy of 5 | this software and associated documentation files (the "Software"), to deal in 6 | the Software without restriction, including without limitation the rights to 7 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 8 | the Software, and to permit persons to whom the Software is furnished to do so, 9 | subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in all 12 | copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 16 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 17 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 18 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 19 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 20 | 21 | Copyright for original `input!` macro is held by Hideyuki Tanaka, 2019. The 22 | original macro is licensed under BSD 3-clause license. 23 | 24 | Redistribution and use in source and binary forms, with or without 25 | modification, are permitted provided that the following conditions are met: 26 | 27 | 1. Redistributions of source code must retain the above copyright notice, this 28 | list of conditions and the following disclaimer. 29 | 30 | 2. Redistributions in binary form must reproduce the above copyright notice, 31 | this list of conditions and the following disclaimer in the documentation 32 | and/or other materials provided with the distribution. 33 | 34 | 3. Neither the name of the copyright holder nor the names of its contributors 35 | may be used to endorse or promote products derived from this software 36 | without specific prior written permission. 37 | 38 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 39 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 40 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 41 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 42 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 43 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 44 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 45 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 46 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 47 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 48 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # proconio / proconio-derive 2 | 3 | `proconio` is an easy IO library for competitive programming, aiming to be used 4 | with AtCoder. 5 | 6 | ## Current status 7 | 8 | ### proconio 9 | 10 | [![crates.io](https://img.shields.io/crates/v/proconio.svg)](https://crates.io/crates/proconio) 11 | [![docs.rs](https://docs.rs/proconio/badge.svg)](https://docs.rs/proconio) 12 | 13 | ### proconio-derive 14 | 15 | [![crates.io](https://img.shields.io/crates/v/proconio-derive.svg)](https://crates.io/crates/proconio-derive) 16 | [![docs.rs](https://docs.rs/proconio-derive/badge.svg)](https://docs.rs/proconio-derive) 17 | -------------------------------------------------------------------------------- /proconio-derive/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "proconio-derive" 3 | version = "0.2.1" 4 | authors = ["statiolake "] 5 | edition = "2018" 6 | rust-version = "1.67.1" 7 | repository = "https://github.com/statiolake/proconio-rs" 8 | license = "MIT OR Apache-2.0" 9 | readme = "README.md" 10 | description = "Procedural macros for proconio" 11 | 12 | [lib] 13 | proc-macro = true 14 | 15 | [dependencies] 16 | quote = "1.0.3" 17 | proc-macro2 = "1.0.9" 18 | 19 | [dependencies.syn] 20 | version = "1.0.17" 21 | features = ["full", "extra-traits", "visit"] 22 | 23 | [dev-dependencies.proconio] 24 | version = "0.5.0" 25 | path = "../proconio" 26 | -------------------------------------------------------------------------------- /proconio-derive/README.md: -------------------------------------------------------------------------------- 1 | # proconio-derive 2 | 3 | [![crates.io](https://img.shields.io/crates/v/proconio-derive.svg)](https://crates.io/crates/proconio-derive) 4 | [![docs.rs](https://docs.rs/proconio-derive/badge.svg)](https://docs.rs/proconio-derive) 5 | 6 | This is procedural macros for proconio. 7 | -------------------------------------------------------------------------------- /proconio-derive/src/derive_readable.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2019 statiolake 2 | // 3 | // Licensed under the Apache License, Version 2.0 or the MIT license , at your option. This file may not be copied, modified, or 6 | // distributed except according to those terms. 7 | 8 | use proc_macro::TokenStream; 9 | use proc_macro2::{Span as Span2, TokenStream as TokenStream2}; 10 | use quote::quote; 11 | use quote::ToTokens; 12 | use syn::parse_macro_input; 13 | use syn::parse_quote; 14 | use syn::spanned::Spanned; 15 | use syn::{Data, DataStruct, DeriveInput, Fields, Ident, Type}; 16 | 17 | pub fn main(attr: TokenStream, input: TokenStream) -> TokenStream { 18 | if !attr.is_empty() { 19 | let mut attr = attr.into_iter(); 20 | let start = attr 21 | .next() 22 | .expect(concat!( 23 | "Attribute is empty. ", 24 | "This is a bug in `proconio`. ", 25 | "Please report this issue from ", 26 | "." 27 | )) 28 | .span(); 29 | let end = attr.fold(start, |_, item| item.span()); 30 | let compile_error = crate::compile_error_at( 31 | quote!("no extra attribute is suppported."), 32 | Span2::from(start), 33 | Span2::from(end), 34 | ); 35 | 36 | return compile_error.into_token_stream().into(); 37 | } 38 | 39 | let mut ast = parse_macro_input!(input as DeriveInput); 40 | 41 | // derive actually Readable 42 | let derive = match derive_readable_impl(&ast) { 43 | Ok(derive) => derive, 44 | Err(error) => return error, 45 | }; 46 | 47 | // modify AST to use actual Readable::Output type 48 | if let Err(error) = replace_type(&mut ast) { 49 | return error; 50 | } 51 | 52 | quote!(#ast #derive).into() 53 | } 54 | 55 | fn replace_type(ast: &mut DeriveInput) -> Result<(), TokenStream> { 56 | let data = get_data_mut(ast)?; 57 | 58 | for field in data.fields.iter_mut() { 59 | let (start, end) = { 60 | let ty = field.ty.clone().into_token_stream(); 61 | crate::get_span_range(ty.into()) 62 | }; 63 | 64 | let new_ty: Type = { 65 | let ty = field.ty.clone().into_token_stream(); 66 | parse_quote!(<#ty as ::proconio::source::Readable>::Output) 67 | }; 68 | 69 | // Restore original spanning info 70 | let respanned = crate::set_span_range(new_ty, start, end); 71 | field.ty = respanned; 72 | } 73 | 74 | Ok(()) 75 | } 76 | 77 | fn derive_readable_impl(ast: &DeriveInput) -> Result { 78 | let name = get_name(ast); 79 | let fields = &get_data(ast)?.fields; 80 | 81 | let field_info = field_info(fields); 82 | let generate = generate(fields, &name, &field_info); 83 | let reads = field_info.iter().map(|f| &f.read); 84 | 85 | let res = quote! { 86 | impl ::proconio::source::Readable for #name { 87 | type Output = #name; 88 | fn read>(source: &mut S) -> #name { 89 | #(#reads)* 90 | #generate 91 | } 92 | } 93 | }; 94 | 95 | Ok(res) 96 | } 97 | 98 | fn get_name(ast: &DeriveInput) -> Ident { 99 | ast.ident.clone() 100 | } 101 | 102 | fn get_data(ast: &DeriveInput) -> Result<&DataStruct, TokenStream> { 103 | let start = ast.span(); 104 | let end = ast.ident.span(); 105 | 106 | let data = &ast.data; 107 | 108 | match data { 109 | Data::Struct(data) => Ok(data), 110 | _ => Err(crate::compile_error_at( 111 | quote!("Readable can only derivable for structs."), 112 | start, 113 | end, 114 | ) 115 | .into_token_stream() 116 | .into()), 117 | } 118 | } 119 | 120 | fn get_data_mut(ast: &mut DeriveInput) -> Result<&mut DataStruct, TokenStream> { 121 | let start = ast.span(); 122 | let end = ast.ident.span(); 123 | let data = &mut ast.data; 124 | 125 | match data { 126 | Data::Struct(data) => Ok(data), 127 | _ => Err(crate::compile_error_at( 128 | quote!("Readable can only derivable for structs."), 129 | start, 130 | end, 131 | ) 132 | .into_token_stream() 133 | .into()), 134 | } 135 | } 136 | 137 | struct FieldInfo { 138 | ident: Ident, 139 | read: TokenStream2, 140 | } 141 | 142 | fn field_info(fields: &Fields) -> Vec { 143 | match fields { 144 | Fields::Named(_) => field_named(fields), 145 | Fields::Unnamed(_) => field_unnamed(fields), 146 | Fields::Unit => Vec::new(), 147 | } 148 | } 149 | 150 | fn field_named(fields: &Fields) -> Vec { 151 | let mut res = Vec::new(); 152 | 153 | for field in fields { 154 | let ident = field.ident.as_ref().cloned(); 155 | let ident = ident.expect(concat!( 156 | "Named field doesn't have name. ", 157 | "This is a bug in `proconio`. ", 158 | "Please report this issue from ", 159 | "." 160 | )); 161 | let ty = field.ty.clone(); 162 | let read = quote! { 163 | let #ident = <#ty as ::proconio::source::Readable>::read(source); 164 | }; 165 | 166 | res.push(FieldInfo { ident, read }); 167 | } 168 | 169 | res 170 | } 171 | 172 | fn field_unnamed(fields: &Fields) -> Vec { 173 | let mut res = Vec::new(); 174 | 175 | for (idx, field) in fields.iter().enumerate() { 176 | let ident = format!("field{idx}"); 177 | let ident = Ident::new(&ident, Span2::call_site()); 178 | let ty = field.ty.clone(); 179 | let read = quote! { 180 | let #ident = <#ty as ::proconio::source::Readable>::read(source); 181 | }; 182 | 183 | res.push(FieldInfo { ident, read }); 184 | } 185 | 186 | res 187 | } 188 | 189 | fn generate(fields: &Fields, name: &Ident, field_info: &[FieldInfo]) -> TokenStream2 { 190 | let idents = field_info.iter().map(|f| &f.ident); 191 | 192 | match fields { 193 | Fields::Named(_) => { 194 | quote! { 195 | #name { 196 | #(#idents,)* 197 | } 198 | } 199 | } 200 | 201 | Fields::Unnamed(_) => { 202 | quote! { 203 | #name(#(#idents,)*) 204 | } 205 | } 206 | 207 | Fields::Unit => { 208 | quote! { 209 | #name 210 | } 211 | } 212 | } 213 | } 214 | -------------------------------------------------------------------------------- /proconio-derive/src/fastout.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2019 statiolake 2 | // 3 | // Licensed under the Apache License, Version 2.0 or the MIT license , at your option. This file may not be copied, modified, or 6 | // distributed except according to those terms. 7 | 8 | use proc_macro::TokenStream; 9 | use proc_macro2::Span as Span2; 10 | use quote::quote; 11 | use quote::ToTokens; 12 | use syn::spanned::Spanned; 13 | use syn::visit::{self, Visit}; 14 | use syn::{parse_macro_input, parse_quote}; 15 | use syn::{Block, ExprClosure, ExprMacro, ItemFn, Macro, Path, Stmt}; 16 | 17 | pub fn main(attr: TokenStream, input: TokenStream) -> TokenStream { 18 | let mut itemfn: ItemFn = parse_macro_input!(input as ItemFn); 19 | 20 | if !attr.is_empty() { 21 | let (start, end) = crate::get_span_range(attr); 22 | 23 | let compile_error = crate::compile_error_at( 24 | quote!("no extra attribute is suppported."), 25 | Span2::from(start), 26 | Span2::from(end), 27 | ); 28 | 29 | itemfn.block.stmts = vec![compile_error]; 30 | return itemfn.into_token_stream().into(); 31 | } 32 | 33 | if let Err(compile_errors) = error_for_print_macros_in_closures(&itemfn.block) { 34 | itemfn.block.stmts = compile_errors; 35 | return itemfn.into_token_stream().into(); 36 | } 37 | 38 | itemfn.block = Box::new(insert_new_print_macros(&itemfn.block)); 39 | 40 | itemfn.into_token_stream().into() 41 | } 42 | 43 | fn error_for_print_macros_in_closures(block: &Block) -> std::result::Result<(), Vec> { 44 | let mut visitor = BlockVisitor::default(); 45 | visitor.visit_block(block); 46 | return if visitor.compile_errors.is_empty() { 47 | Ok(()) 48 | } else { 49 | Err(visitor.compile_errors) 50 | }; 51 | 52 | #[derive(Default)] 53 | struct BlockVisitor { 54 | compile_errors: Vec, 55 | } 56 | 57 | impl<'ast> Visit<'ast> for BlockVisitor { 58 | fn visit_expr_closure(&mut self, item: &'ast ExprClosure) { 59 | let mut visitor = ClosureVisitor::default(); 60 | visitor.visit_expr_closure(item); 61 | self.compile_errors.extend(visitor.compile_errors); 62 | } 63 | } 64 | 65 | #[derive(Default)] 66 | struct ClosureVisitor { 67 | compile_errors: Vec, 68 | } 69 | 70 | impl<'ast> Visit<'ast> for ClosureVisitor { 71 | fn visit_expr_macro(&mut self, item: &'ast ExprMacro) { 72 | let Macro { path, .. } = &item.mac; 73 | if equals(path, "print") || equals(path, "println") { 74 | // Closure containing print macro is prohibited because closure *may* passed to the 75 | // function which requires the closure to be `Send`. For example, std::thread::spawn() 76 | // takes an closure and run the closure in another thread. That causes an error since 77 | // StdoutLock is not thread-safe. The problem is, the error message is too-complecated 78 | // for beginners since the error originates from invisible codes inserted by this 79 | // procedural macro. Yes, if the closure don't have to be `Send`, it's OK to have 80 | // print macros in it. However such a trait boundary is not yet resolved at the time 81 | // of macro expansion, so it is impossible to change behavior selectively here. For 82 | // that reason, all closures must not have print! call in it regardless of whether it 83 | // requires `Send` or not for now. 84 | 85 | // emit an error for each position of print macro. 86 | self.compile_errors.push(crate::compile_error_at( 87 | quote!( 88 | "Closures in a #[fastout] function cannot contain `print!` or \ 89 | `println!` macro\n\ 90 | \n\ 91 | note: If you want to run your entire logic in a thread having extended \ 92 | size of stack, you can define a new function instead. See \ 93 | documentation (https://docs.rs/proconio/#\ 94 | closures-having-print-or-println-in-fastout-function) for more \ 95 | details.\n\ 96 | \n\ 97 | note: This is because if you use this closure with \ 98 | `std::thread::spawn()` or any other functions requiring `Send` for an \ 99 | argument closure, the compiler emits an error about thread unsafety for \ 100 | our internal implementations. If you are using the closure just in a \ 101 | single thread, it's actually no problem, but we cannot check the trait \ 102 | bounds at the macro-expansion time. So for now, all closures having \ 103 | `print!` or `println!` is prohibited regardless of the `Send` \ 104 | requirements." 105 | ), 106 | item.span(), 107 | item.span(), 108 | )); 109 | } 110 | visit::visit_expr_macro(self, item); 111 | } 112 | } 113 | 114 | fn equals(path: &Path, ident: &str) -> bool { 115 | matches!(path.get_ident(), Some(path_ident) if path_ident == ident) 116 | } 117 | } 118 | 119 | fn insert_new_print_macros(block: &Block) -> Block { 120 | parse_quote! {{ 121 | let __proconio_stdout = ::std::io::stdout(); 122 | let mut __proconio_stdout = ::std::io::BufWriter::new(__proconio_stdout.lock()); 123 | 124 | #[allow(unused_macros)] 125 | macro_rules! print { 126 | ($($tt:tt)*) => {{ 127 | use std::io::Write as _; 128 | ::std::write!(__proconio_stdout, $($tt)*).unwrap(); 129 | }}; 130 | } 131 | 132 | #[allow(unused_macros)] 133 | macro_rules! println { 134 | ($($tt:tt)*) => {{ 135 | use std::io::Write as _; 136 | ::std::writeln!(__proconio_stdout, $($tt)*).unwrap(); 137 | }}; 138 | } 139 | 140 | let __proconio_res = #block; 141 | <::std::io::BufWriter<::std::io::StdoutLock> as ::std::io::Write>::flush(&mut __proconio_stdout).unwrap(); 142 | return __proconio_res; 143 | }} 144 | } 145 | -------------------------------------------------------------------------------- /proconio-derive/src/lib.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2019 statiolake 2 | // 3 | // Licensed under the Apache License, Version 2.0 or the MIT license , at your option. This file may not be copied, modified, or 6 | // distributed except according to those terms. 7 | 8 | #![recursion_limit = "128"] 9 | #![allow(clippy::needless_doctest_main)] 10 | 11 | //! Macros to easily derive `Readable` and make stdout faster. 12 | //! 13 | //! proconio_derive provides two procedural macros (attributes): `derive_readable` and `fastout`. 14 | //! 15 | //! # Examples for `#[derive_readable]` 16 | //! 17 | //! ``` 18 | //! # extern crate proconio; 19 | //! # extern crate proconio_derive; 20 | //! use proconio::input; 21 | //! # use proconio::source::auto::AutoSource; 22 | //! use proconio_derive::derive_readable; 23 | //! 24 | //! // Unit struct can derive readable. This generates a no-op for the reading. Not ignoring 25 | //! // the read value, but simply skip reading process. You cannot use it to discard the input. 26 | //! #[derive_readable] 27 | //! #[derive(PartialEq, Debug)] 28 | //! struct Weight; 29 | //! 30 | //! #[derive_readable] 31 | //! #[derive(PartialEq, Debug)] 32 | //! struct Cost(i32); 33 | //! 34 | //! #[derive_readable] 35 | //! #[derive(Debug)] 36 | //! struct Edge { 37 | //! from: usize, 38 | //! to: proconio::marker::Usize1, // The real Edge::to has type usize. 39 | //! weight: Weight, 40 | //! cost: Cost, 41 | //! } 42 | //! 43 | //! fn main() { 44 | //! # let source = AutoSource::from("12 32 35"); 45 | //! input! { 46 | //! # from source, 47 | //! edge: Edge, 48 | //! } 49 | //! 50 | //! // if you enter "12 32 35" to the stdin, the values are as follows. 51 | //! assert_eq!(edge.from, 12); 52 | //! assert_eq!(edge.to, 31); 53 | //! assert_eq!(edge.weight, Weight); 54 | //! assert_eq!(edge.cost, Cost(35)); 55 | //! } 56 | //! ``` 57 | //! 58 | //! # Examples for `#[fastout]` 59 | //! 60 | //! ``` 61 | //! use proconio_derive::fastout; 62 | //! 63 | //! #[fastout] 64 | //! fn main() { 65 | //! print!("{}{}, ", 'h', "ello"); // "hello" (no newline) 66 | //! println!("{}!", "world"); // "world!\n" 67 | //! println!("{}", 123456789); // "123456789\n" 68 | //! } 69 | //! ``` 70 | extern crate proc_macro; 71 | 72 | use proc_macro::{Delimiter, Group, Ident, Punct, Spacing, Span, TokenStream, TokenTree}; 73 | use proc_macro2::{Span as Span2, TokenStream as TokenStream2}; 74 | use quote::ToTokens; 75 | use syn::parse::Parse; 76 | use syn::Stmt; 77 | 78 | mod derive_readable; 79 | mod fastout; 80 | 81 | /// Derives `Readable` for your own type. 82 | /// 83 | /// If every member of your struct implements `Readable`, your own type can also be `Readable`. 84 | /// All you have to do is just add `#[derive_readable]` to your type definition. This macro 85 | /// automatically implements `Readable` to your struct and translate your struct's member type to 86 | /// the output type of the read. For example, if you have `Usize1` in your struct, it will 87 | /// actually be defined as `usize`. Of course the `Usize1`'s `Readable` implementation is used to 88 | /// read. 89 | #[proc_macro_attribute] 90 | pub fn derive_readable(attr: TokenStream, input: TokenStream) -> TokenStream { 91 | derive_readable::main(attr, input) 92 | } 93 | 94 | /// Enables buffering for stdout. 95 | /// 96 | /// You cannot create a closure containing `print!` or `println!` in `#[fastout]` function. This 97 | /// is because the closure cannot implement `Send` since `StdoutLock`, which is not a `Send`, is 98 | /// internally captured into the closure. This causes a trait bound mismatch when used with 99 | /// function requiring its argument closure to be a `Send`, such as `std::thread::spawn()`. 100 | /// 101 | /// ```compile_fail 102 | /// use proconio::fastout; 103 | /// 104 | /// use std::thread; 105 | /// 106 | /// #[fastout] 107 | /// fn main() { 108 | /// thread::Builder::new() 109 | /// .stack_size(32 * 1024 * 1024) 110 | /// .spawn(|| { 111 | /// println!("Hi!"); 112 | /// }) 113 | /// .unwrap() 114 | /// .join() 115 | /// .unwrap(); 116 | /// } 117 | /// ``` 118 | /// 119 | /// It is too conservative to make all of such closures compilation error because it is actually no 120 | /// problem to use such a closure only inside a single thread. However, since trait bound check is 121 | /// done after macro expansions, there is no way to check whther the closure is required to be a 122 | /// `Send` or not. And the compiler error message for actual mismatch of a `Send` requirement is 123 | /// too confusing, pointing out codes you didn't write (macro-expanded codes) as an error position. 124 | /// In conclusion, for user-friendliness, all of them are prohibited for now. 125 | /// 126 | /// Internally this is the same with 127 | /// 128 | /// ``` 129 | /// let __proconio_stdout = ::std::io::stdout(); 130 | /// let mut __proconio_stdout = ::std::io::BufWriter::new(__proconio_stdout.lock()); 131 | /// 132 | /// #[allow(unused_macros)] 133 | /// macro_rules! print { 134 | /// ($($tt:tt)*) => {{ 135 | /// use std::io::Write as _; 136 | /// ::std::write!(__proconio_stdout, $($tt)*).unwrap(); 137 | /// }}; 138 | /// } 139 | /// 140 | /// #[allow(unused_macros)] 141 | /// macro_rules! println { 142 | /// ($($tt:tt)*) => {{ 143 | /// use std::io::Write as _; 144 | /// ::std::writeln!(__proconio_stdout, $($tt)*).unwrap(); 145 | /// }}; 146 | /// } 147 | /// 148 | /// let __proconio_res = { 149 | /// // Your code goes here 150 | /// }; 151 | /// <::std::io::BufWriter<::std::io::StdoutLock> as ::std::io::Write>::flush( 152 | /// &mut __proconio_stdout 153 | /// ).unwrap(); 154 | /// return __proconio_res; 155 | /// ``` 156 | #[proc_macro_attribute] 157 | pub fn fastout(attr: TokenStream, input: TokenStream) -> TokenStream { 158 | fastout::main(attr, input) 159 | } 160 | 161 | fn compile_error_at(args: TokenStream2, start: Span2, end: Span2) -> Stmt { 162 | let start = start.unwrap(); 163 | let end = end.unwrap(); 164 | 165 | let group = TokenStream::from(args) 166 | .into_iter() 167 | .map(|x| set_span(x, Span::call_site())) 168 | .collect(); 169 | 170 | let r = vec![ 171 | set_span(Ident::new("compile_error", start), start), 172 | set_span(Punct::new('!', Spacing::Alone), start), 173 | set_span(Group::new(Delimiter::Parenthesis, group), end), 174 | set_span(Punct::new(';', Spacing::Alone), end), 175 | ]; 176 | 177 | syn::parse(r.into_iter().collect()).expect(concat!( 178 | "Failed to parse auto-generated compile_error! macro. ", 179 | "This is a bug in `proconio`. ", 180 | "Please report this issue from ", 181 | "." 182 | )) 183 | } 184 | 185 | fn set_span>(token: T, span: Span) -> TokenTree { 186 | let mut token = token.into(); 187 | token.set_span(span); 188 | token 189 | } 190 | 191 | fn get_span_range(tokens: TokenStream) -> (Span, Span) { 192 | let mut tokens = tokens.into_iter(); 193 | 194 | let start = match tokens.next() { 195 | Some(start) => start.span(), 196 | None => return (Span::call_site(), Span::call_site()), 197 | }; 198 | let end = tokens.fold(start, |_, item| item.span()); 199 | 200 | (start, end) 201 | } 202 | 203 | fn set_span_range(tokens: T, start: Span, end: Span) -> T { 204 | let tokens = TokenStream::from(tokens.into_token_stream()).into_iter(); 205 | 206 | let mut first = true; 207 | let tokens = tokens.map(|mut token| { 208 | if first { 209 | token.set_span(start); 210 | first = false; 211 | } else { 212 | token.set_span(end); 213 | } 214 | 215 | token 216 | }); 217 | 218 | syn::parse(tokens.collect()).expect(concat!( 219 | "Failed to parse respanned token stream. ", 220 | "This is a bug in `proconio`. ", 221 | "Please report this issue from ", 222 | "." 223 | )) 224 | } 225 | -------------------------------------------------------------------------------- /proconio/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "proconio" 3 | version = "0.5.0" 4 | authors = ["statiolake "] 5 | edition = "2018" 6 | rust-version = "1.70.0" 7 | repository = "https://github.com/statiolake/proconio-rs" 8 | keywords = ["io", "procon", "procon"] 9 | categories = ["command-line-interface"] 10 | license = "MIT OR Apache-2.0" 11 | readme = "README.md" 12 | description = "Easy IO library for competitive programming" 13 | 14 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 15 | 16 | [[test]] 17 | name = "stdin" 18 | path = "tests/stdin.rs" 19 | harness = false 20 | 21 | [[test]] 22 | name = "read_value" 23 | path = "tests/read_value.rs" 24 | harness = false 25 | 26 | [[test]] 27 | name = "interactive" 28 | path = "tests/interactive.rs" 29 | harness = false 30 | 31 | [[test]] 32 | name = "derive" 33 | path = "tests/derive.rs" 34 | required-features = ["derive"] 35 | 36 | [[test]] 37 | name = "fastout" 38 | path = "tests/fastout.rs" 39 | required-features = ["derive"] 40 | 41 | [[test]] 42 | name = "ui" 43 | path = "tests/ui.rs" 44 | required-features = ["derive"] 45 | 46 | [[test]] 47 | name = "issue_14" 48 | path = "tests/issue_14.rs" 49 | required-features = ["derive"] 50 | harness = false 51 | 52 | [dependencies] 53 | 54 | [dependencies.proconio-derive] 55 | version = "0.2.0" 56 | path = "../proconio-derive" 57 | optional = true 58 | 59 | [dev-dependencies] 60 | rustversion = "1.0.2" 61 | trybuild = "=1.0.67" 62 | assert_cli = "0.6.3" 63 | # Pin backtrace version because assert_cli -> failure -> backtrace transitively 64 | # depends on it, and backtrace 0.3.75+ requires a newer Rust version than our 65 | # MSRV (1.70.0) 66 | backtrace = "=0.3.74" 67 | 68 | [features] 69 | derive = ["proconio-derive"] 70 | -------------------------------------------------------------------------------- /proconio/README.md: -------------------------------------------------------------------------------- 1 | # proconio 2 | 3 | [![crates.io](https://img.shields.io/crates/v/proconio.svg)](https://crates.io/crates/proconio) 4 | [![docs.rs](https://docs.rs/proconio/badge.svg)](https://docs.rs/proconio) 5 | 6 | Easy IO library for competitive programming. 7 | 8 | `proconio` provides an easy way to read values from stdin (or other source). The main is `input!` macro. 9 | 10 | The macro's user interface is basically the same with [tanakh's input macro](https://qiita.com/tanakh/items/0ba42c7ca36cd29d0ac8). 11 | 12 | ```rust 13 | use proconio::input; 14 | 15 | input! { 16 | n: u8, 17 | m: u32, 18 | l: i32, 19 | } 20 | 21 | // now you can use n, m and l as variable. 22 | println!("{} {} {}", n, m, l); 23 | ``` 24 | 25 | For more details, see documentation. 26 | -------------------------------------------------------------------------------- /proconio/src/lib.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2019 statiolake 2 | // 3 | // Licensed under the Apache License, Version 2.0 or the MIT license , at your option. This file may not be copied, modified, or 6 | // distributed except according to those terms. 7 | 8 | #![allow(clippy::needless_doctest_main, clippy::print_literal)] 9 | 10 | //! Easy IO library for competitive programming. 11 | //! 12 | //! `proconio` provides an easy way to read values from stdin (or other source). The main feature 13 | //! provided by this crate is `input!` macro (and its family, `input_interactive!`, `read_value!`, 14 | //! and `read_value_interactive!`). 15 | //! 16 | //! # Examples 17 | //! 18 | //! The macro's user interface is basically the same with [tanakh's input 19 | //! macro](https://qiita.com/tanakh/items/0ba42c7ca36cd29d0ac8). 20 | //! 21 | //! ``` 22 | //! # extern crate proconio; 23 | //! # use proconio::source::auto::AutoSource; 24 | //! use proconio::input; 25 | //! # let source = AutoSource::from("32 54 -23"); 26 | //! 27 | //! input! { 28 | //! # from source, 29 | //! n: u8, 30 | //! m: u32, 31 | //! l: i32, 32 | //! } 33 | //! 34 | //! // now you can use n, m and l as variable. 35 | //! println!("{} {} {}", n, m, l); 36 | //! # assert_eq!(n, 32); 37 | //! # assert_eq!(m, 54); 38 | //! # assert_eq!(l, -23); 39 | //! ``` 40 | //! 41 | //! In above code, variables n, m and l are declared and stored values are read from stdin. 42 | //! 43 | //! You can declare mutable variables like below: 44 | //! 45 | //! ``` 46 | //! # extern crate proconio; 47 | //! # use proconio::source::auto::AutoSource; 48 | //! use proconio::input; 49 | //! # let source = AutoSource::from("32 54"); 50 | //! 51 | //! input! { 52 | //! # from source, 53 | //! n: u32, 54 | //! mut m: u32, 55 | //! } 56 | //! 57 | //! m += n; // OK: m is mutable 58 | //! # assert_eq!(n, 32); 59 | //! # assert_eq!(m, 86); 60 | //! ``` 61 | //! 62 | //! You can read an array or a matrix like this: 63 | //! 64 | //! ``` 65 | //! # extern crate proconio; 66 | //! # use proconio::source::auto::AutoSource; 67 | //! use proconio::input; 68 | //! # let source = AutoSource::from("5 4 1 2 3 4 5 1 2 3 4 5 1 2 3 4 5 1 2 3 4 5"); 69 | //! 70 | //! input! { 71 | //! # from source, 72 | //! n: usize, 73 | //! m: usize, 74 | //! a: [[i32; n]; m] // `a` is Vec>, (m, n)-matrix. 75 | //! } 76 | //! # assert_eq!( 77 | //! # a, 78 | //! # [ 79 | //! # [1, 2, 3, 4, 5], 80 | //! # [1, 2, 3, 4, 5], 81 | //! # [1, 2, 3, 4, 5], 82 | //! # [1, 2, 3, 4, 5] 83 | //! # ] 84 | //! # ); 85 | //! ``` 86 | //! 87 | //! If the first input is the length of the array, you can omit the length. This is the only way 88 | //! to read jagged array (an array of arrays of which the member arrays can be of different sizes) 89 | //! at once. (Of course you can use `input!` multiple times in for-loop to read such an array 90 | //! since `input!` can be used multiple times.) 91 | //! 92 | //! ``` 93 | //! # extern crate proconio; 94 | //! # use proconio::source::auto::AutoSource; 95 | //! use proconio::input; 96 | //! # let source = AutoSource::from("3 3 1 2 3 0 2 1 2"); 97 | //! 98 | //! input! { 99 | //! # from source, 100 | //! n: usize, 101 | //! a: [[i32]; n], 102 | //! } 103 | //! 104 | //! // if you enter "3 3 1 2 3 0 2 1 2" to the stdin, the result is as follows. 105 | //! assert_eq!( 106 | //! a, 107 | //! vec![ 108 | //! vec![1, 2, 3], 109 | //! vec![], 110 | //! vec![1, 2], 111 | //! ] 112 | //! ); 113 | //! ``` 114 | //! 115 | //! Strings can be read as `Vec` or `Vec`. Use `Bytes` and `Chars` to do so: 116 | //! 117 | //! ``` 118 | //! # extern crate proconio; 119 | //! # use proconio::source::auto::AutoSource; 120 | //! use proconio::input; 121 | //! use proconio::marker::{Bytes, Chars}; 122 | //! # let source = AutoSource::from(" string chars\nbytes"); 123 | //! 124 | //! input! { 125 | //! # from source, 126 | //! string: String, // read as String 127 | //! chars: Chars, // read as Vec 128 | //! bytes: Bytes, // read as Vec 129 | //! } 130 | //! 131 | //! // if you enter "string chars bytes" to the stdin, they are like this. 132 | //! assert_eq!(string, "string"); 133 | //! assert_eq!(chars, ['c', 'h', 'a', 'r', 's']); 134 | //! assert_eq!(bytes, b"bytes"); 135 | //! ``` 136 | //! 137 | //! You can read tuples: 138 | //! 139 | //! ``` 140 | //! # extern crate proconio; 141 | //! # use proconio::source::auto::AutoSource; 142 | //! use proconio::input; 143 | //! # let source = AutoSource::from("1 2 3 4 5"); 144 | //! 145 | //! input! { 146 | //! # from source, 147 | //! t: (i32, i32, i32, i32, i32), 148 | //! } 149 | //! 150 | //! // if you enter "1 2 3 4 5" to the stdin, `t` is like this. 151 | //! assert_eq!(t, (1, 2, 3, 4, 5)); 152 | //! ``` 153 | //! 154 | //! And you can freely combine these types. 155 | //! 156 | //! ``` 157 | //! # extern crate proconio; 158 | //! # use proconio::source::auto::AutoSource; 159 | //! use proconio::input; 160 | //! # let source = AutoSource::from("4 3 1 1 1 1 2 2 2 2 3 3 3 3 4 4 4 4 5 5 5 5"); 161 | //! 162 | //! input! { 163 | //! # from source, 164 | //! n: usize, 165 | //! m: usize, 166 | //! t: [([u32; m], i32); n], 167 | //! } 168 | //! # assert_eq!( 169 | //! # t, 170 | //! # [ 171 | //! # (vec![1,1,1],1), 172 | //! # (vec![2,2,2],2), 173 | //! # (vec![3,3,3],3), 174 | //! # (vec![4,4,4],4), 175 | //! # ] 176 | //! # ); 177 | //! ``` 178 | //! 179 | //! You can use `input!` macro multiple times. For the second time, `input!` macro reads rest of 180 | //! input. It works even if the first input stops at the middle of a line. The subsequent reads 181 | //! will be started at the rest of the line. This may be helpful for problems where multiple 182 | //! datasets are given once. 183 | //! 184 | //! ``` 185 | //! # extern crate proconio; 186 | //! # use proconio::source::auto::AutoSource; 187 | //! use proconio::input; 188 | //! # let mut source = AutoSource::from("4 2 1 2 2 3 4 2 1 2 2 3 4"); 189 | //! 190 | //! input! { 191 | //! # from &mut source, 192 | //! n: usize, 193 | //! } 194 | //! 195 | //! for i in 0..n { 196 | //! input! { 197 | //! # from &mut source, 198 | //! m: usize, 199 | //! a: [i32; m], 200 | //! } 201 | //! # assert_eq!(a[0], if i % 2 == 0 { 1 } else { 3 }); 202 | //! # assert_eq!(a[1], if i % 2 == 0 { 2 } else { 4 }); 203 | //! } 204 | //! ``` 205 | //! 206 | //! In addition to `Chars` and `Bytes`, `Usize1` and `Isize1` are also special types. They are 207 | //! read as `usize` and `isize` respectively, but the read value is decremented. It enables us to 208 | //! automatically convert 1-indexed vertices numbers to 0-indexed array indices. 209 | //! 210 | //! ``` 211 | //! # extern crate proconio; 212 | //! # use proconio::source::auto::AutoSource; 213 | //! use proconio::input; 214 | //! use proconio::marker::Usize1; 215 | //! # let mut source = AutoSource::from("4 1 3 3 4 6 1 5 3"); 216 | //! 217 | //! input! { 218 | //! # from &mut source, 219 | //! n: usize, 220 | //! edges: [(Usize1, Usize1); n], 221 | //! } 222 | //! 223 | //! // if you enter "4 1 3 3 4 6 1 5 3", the decremented value is stored. 224 | //! assert_eq!(edges[0], (0, 2)); 225 | //! assert_eq!(edges[1], (2, 3)); 226 | //! assert_eq!(edges[2], (5, 0)); 227 | //! assert_eq!(edges[3], (4, 2)); 228 | //! ``` 229 | //! 230 | //! `Usize1` and `Isize1` doesn't hold actual value, so you cannot have value of the type. Thus, 231 | //! they are only useful inside `input!` or `#[derive_readable]`. You can think the reason these 232 | //! types exist is to tell "how to read the value". This how-to can be defined through `Readable` 233 | //! trait. This trait doesn't require the output type to be the same with the implementor. 234 | //! `Usize1` is implementing `Readable` trait, and there the type of read value is defined as 235 | //! `usize`. You can implement `Readable` for your own type to read values in customized way. 236 | //! 237 | //! Finally, you can make your own types `Readable` using `#[derive_readable]` attribute. Types 238 | //! used in the struct are automatically translated to their output types, so a member declared as 239 | //! `Usize1` has type `usize` as real struct. 240 | //! 241 | //! **Note:** Using `#[derive_readable]` requires `derive` feature enabled. To do so, open your 242 | //! Cargo.toml and modify the line of proconio from: 243 | //! 244 | //! ```toml 245 | //! proconio = "=(version)" 246 | //! ``` 247 | //! 248 | //! to: 249 | //! 250 | //! ```toml 251 | //! proconio = { version = "=(version)", features = ["derive"] } 252 | //! ``` 253 | //! 254 | //! Example of `#[derive_readable]`: 255 | //! 256 | //! ``` 257 | //! # #[cfg(feature = "derive")] 258 | //! # { 259 | //! # extern crate proconio; 260 | //! use proconio::input; 261 | //! # use proconio::source::auto::AutoSource; 262 | //! use proconio::derive_readable; 263 | //! 264 | //! // Unit struct can derive readable. This generates a no-op for the reading. Not ignoring 265 | //! // the read value, but simply skip reading process. You cannot use it to discard the input. 266 | //! #[derive_readable] 267 | //! #[derive(PartialEq, Debug)] 268 | //! struct Weight; 269 | //! 270 | //! #[derive_readable] 271 | //! #[derive(PartialEq, Debug)] 272 | //! struct Cost(i32); 273 | //! 274 | //! #[derive_readable] 275 | //! #[derive(Debug)] 276 | //! struct Edge { 277 | //! from: usize, 278 | //! to: proconio::marker::Usize1, // The real Edge::to has type usize. 279 | //! weight: Weight, 280 | //! cost: Cost, 281 | //! } 282 | //! 283 | //! fn main() { 284 | //! # let source = AutoSource::from("12 32 35"); 285 | //! input! { 286 | //! # from source, 287 | //! edge: Edge, 288 | //! } 289 | //! 290 | //! // if you enter "12 32 35" to the stdin, the values are as follows. 291 | //! assert_eq!(edge.from, 12); 292 | //! assert_eq!(edge.to, 31); 293 | //! assert_eq!(edge.weight, Weight); 294 | //! assert_eq!(edge.cost, Cost(35)); 295 | //! } 296 | //! # } 297 | //! ``` 298 | //! 299 | //! # `read_value!` macro 300 | //! 301 | //! `read_value!` macro is a macro used inside the `input!` macro, but using it directly is also 302 | //! useful in some cases. Typically when you don't need to store the value into a variable. 303 | //! 304 | //! ```rust 305 | //! # extern crate proconio; 306 | //! use proconio::source::auto::AutoSource; 307 | //! use proconio::read_value; 308 | //! let mut source = AutoSource::from("2 3 4"); 309 | //! let mut sum = 0; 310 | //! for _ in 0..read_value!(from &mut source, usize) { 311 | //! sum += read_value!(from &mut source, u32); 312 | //! } 313 | //! assert_eq!(sum, 7); 314 | //! ``` 315 | //! 316 | //! # Interactive version 317 | //! 318 | //! The normal `input!` and `read_value!` macro reads the entire input at once in judge environment 319 | //! to optimize I/O performance. However this does not work well with interactive problems, since 320 | //! in those problems you need to communicate with the judge by writing and reading alternately. 321 | //! 322 | //! In this case, you can manually create LineSource for stdin. There's handy interactive version of 323 | //! the macros doing exactly that. They are `input_interactive!` and `read_value_interactive!`. 324 | //! 325 | //! The usage of those macros are exactly the same with the normal ones. Refer to the document of 326 | //! [input!](input) and [read_value!](read_value) for further information. 327 | //! 328 | //! # `#[fastout]` 329 | //! 330 | //! If you import `proconio::fastout`, you can use `#[fastout]` attribute. Adding this attribute 331 | //! to your `main()`, your `print!` and `println!` become faster. 332 | //! 333 | //! **Note:** Using `#[proconio::fastout]` requires `derive` feature enabled. To do so, open your 334 | //! Cargo.toml and modify the line of proconio from: 335 | //! 336 | //! ```toml 337 | //! proconio = "=(version)" 338 | //! ``` 339 | //! 340 | //! to: 341 | //! 342 | //! ```toml 343 | //! proconio = { version = "=(version)", features = ["derive"] } 344 | //! ``` 345 | //! 346 | //! Example of `#[fastout]`: 347 | //! 348 | //! ``` 349 | //! # #[cfg(feature = "derive")] 350 | //! # { 351 | //! # extern crate proconio; 352 | //! use proconio::fastout; 353 | //! 354 | //! #[fastout] 355 | //! fn main() { 356 | //! print!("{}{}, ", 'h', "ello"); // "hello" (no newline) 357 | //! println!("{}!", "world"); // "world!\n" 358 | //! println!("{}", 123456789); // "123456789\n" 359 | //! } 360 | //! # } 361 | //! ``` 362 | //! 363 | //! ## Closures having `print!` or `println!` in `#[fastout]` function 364 | //! 365 | //! You cannot create a closure containing `print!` or `println!` in `#[fastout]` function. This 366 | //! is because the closure becomes thread-unsafe since the closure refers the unlocked stdout 367 | //! introduced by `#[fastout]` attribute. If this were not prohibited, an invalid usage of such a 368 | //! closure would produce a very complex error messages. For example, `std::thread::spawn()`, 369 | //! which requires its argument closure to be thread-safe, causes a confusing error. 370 | //! 371 | //! Yes, it is too conservative to make all of such closures compilation error because it is 372 | //! actually no problem to use such a closure only inside a single thread. This is related to a 373 | //! limitation in `#[fastout]` implementation. 374 | //! 375 | //! For more technical details, see documentation for `#[fastout]` in `proconio-derive`. 376 | //! 377 | //! ### How to resolve this error 378 | //! 379 | //! Consider you want to run this code: 380 | //! 381 | //! ```compile_fail 382 | //! use proconio::fastout; 383 | //! 384 | //! #[fastout] 385 | //! fn main() { 386 | //! let thread = std::thread::spawn(|| { 387 | //! let x = 3; 388 | //! let y = x * x; 389 | //! println!("{}", y); 390 | //! }); 391 | //! 392 | //! thread.join().unwrap(); 393 | //! } 394 | //! ``` 395 | //! 396 | //! You will get an error like below. 397 | //! 398 | //! ```text 399 | //! error: Closures in a #[fastout] function cannot contain `print!` or `println!` macro 400 | //! 401 | //! note: If you want to run your entire logic in a thread having extended size of stack, you can 402 | //! define a new function instead. See documentation (https://.....) for more details. 403 | //! 404 | //! note: This is because if you use this closure with `std::thread::spawn()` or any other 405 | //! functions requiring `Send` for an argument closure, the compiler emits an error about thread 406 | //! unsafety for our internal implementations. If you are using the closure just in a single 407 | //! thread, it's actually no problem, but we cannot check the trait bounds at the macro-expansion 408 | //! time. So for now, all closures having `print!` or `println!` is prohibited regardless of the 409 | //! `Send` requirements. 410 | //! --> src/test.rs:10:9 411 | //! | 412 | //! 10 | println!("{}", y); 413 | //! | ^^^^^^^ 414 | //! ``` 415 | //! 416 | //! If your `print!` is relying on the calculation in the thread, you can instead return the result 417 | //! from the thread. 418 | //! 419 | //! ``` 420 | //! # #[cfg(feature = "derive")] 421 | //! # { 422 | //! use proconio::fastout; 423 | //! 424 | //! #[fastout] 425 | //! fn main() { 426 | //! let thread = std::thread::spawn(|| { 427 | //! let x = 3; 428 | //! x * x 429 | //! }); 430 | //! 431 | //! let y = thread.join().unwrap(); 432 | //! # assert_eq!(y, 9); 433 | //! println!("{}", y); 434 | //! } 435 | //! # } 436 | //! ``` 437 | //! 438 | //! If you are doing so complex job that it's too difficult to returning the results from your 439 | //! closure... 440 | //! 441 | //! ```compile_fail 442 | //! use proconio::fastout; 443 | //! 444 | //! # fn some_function(_: String) -> impl Iterator { vec!["hello".to_string(), "world".to_string()].into_iter() } 445 | //! # fn some_proc(x: &str) -> &str { x } 446 | //! 447 | //! #[fastout] 448 | //! fn main() { 449 | //! let context = "some context".to_string(); 450 | //! let thread = std::thread::spawn(move || { 451 | //! // Use many println! and the order is very important 452 | //! // It's possible to aggregate the result and print it later, but it's not easy to read 453 | //! // and seems ugly. 454 | //! println!("this is header."); 455 | //! for (i, item) in some_function(context).enumerate() { 456 | //! print!("Item #{}: ", i); 457 | //! print!("{}", some_proc(&item)); 458 | //! println!("({})", item); 459 | //! } 460 | //! }); 461 | //! 462 | //! thread.join().unwrap(); 463 | //! } 464 | //! ``` 465 | //! 466 | //! ...you can use a function instead. 467 | //! 468 | //! ``` 469 | //! # #[cfg(feature = "derive")] 470 | //! # { 471 | //! use proconio::fastout; 472 | //! 473 | //! # fn some_function(_: String) -> impl Iterator { vec!["hello".to_string(), "world".to_string()].into_iter() } 474 | //! # fn some_proc(x: &str) -> &str { x } 475 | //! 476 | //! // You can add #[fastout] here 477 | //! #[fastout] 478 | //! fn process(context: String) { 479 | //! // It's completely OK since this #[fastout] is a thing inside `process()` 480 | //! println!("this is header."); 481 | //! for (i, item) in some_function(context).enumerate() { 482 | //! print!("Item #{}: ", i); 483 | //! print!("{}", some_proc(&item)); 484 | //! println!("({})", item); 485 | //! } 486 | //! } 487 | //! 488 | //! // You must not add #[fastout] here! It causes deadlock. 489 | //! // #[fastout] 490 | //! fn main() { 491 | //! let context = "some context".to_string(); 492 | //! let thread = std::thread::spawn(move || process(context)); 493 | //! thread.join().unwrap(); 494 | //! } 495 | //! # } 496 | //! ``` 497 | //! 498 | //! **Important Note:** If you *spawn a new thread* which runs another function annotated with 499 | //! `#[fastout]`, you must not add `#[fastout]` to the caller. If you add `#[fastout]` in caller 500 | //! too, then the caller has the lock for the stdout, and so callee cannot acquire the lock forever 501 | //! --- deadlock. This is not the case when the caller and callee is executed in the same thread, 502 | //! since the lock of stdout is reentrant. We cannot warn about this kind of deadlock since we 503 | //! don't know annotations attached to the function to be called. (In the above example, we can't 504 | //! know whether the function `process()` has `#[fastout]` attribute or not.) 505 | //! 506 | //! If your code is so complex that you cannot avoid deadlock, you should give up using 507 | //! `#[fastout]` and simply use `println!` or manually handle your stdout in usual Rust way. 508 | //! 509 | //! ## Issues of printing order 510 | //! 511 | //! `#[fastout]` enables buffering to stdout, so if you print something in other functions between 512 | //! two prints in main, the order of printing may differ. In other words, the below example 513 | //! 514 | //! ``` 515 | //! # #[cfg(feature = "derive")] 516 | //! # { 517 | //! # use proconio::fastout; 518 | //! fn foo() { println!("between"); } 519 | //! #[fastout] 520 | //! fn main() { 521 | //! println!("hello"); 522 | //! foo(); 523 | //! println!("world"); 524 | //! } 525 | //! # } 526 | //! ``` 527 | //! 528 | //! *likely* prints like 529 | //! 530 | //! ```text 531 | //! between 532 | //! hello 533 | //! world 534 | //! ``` 535 | //! 536 | //! If you don't like this behavior, you can remove `#[fastout]` from your `main()`. 537 | //! 538 | 539 | #[cfg(feature = "derive")] 540 | pub use proconio_derive::*; 541 | 542 | pub mod marker; 543 | pub mod source; 544 | 545 | use crate::source::{auto::AutoSource, line::LineSource}; 546 | use std::sync::OnceLock; 547 | use std::{ 548 | io::{self, BufRead}, 549 | sync::Mutex, 550 | }; 551 | use std::{ 552 | io::{BufReader, Stdin}, 553 | sync::MutexGuard, 554 | }; 555 | 556 | // Prepares a short path to `Readable` to enables rust-analyzer to infer `Readable::Output`. 557 | #[doc(hidden)] 558 | pub use crate::source::Readable as __Readable; 559 | 560 | pub enum StdinSource { 561 | Normal(AutoSource), // for input! 562 | Interactive(LineSource), // for for input_interactive! 563 | Unknown(LineSource), // for is_stdin_empty() without input! or input_interactive! 564 | } 565 | 566 | impl source::Source for StdinSource { 567 | fn next_token(&mut self) -> Option<&str> { 568 | match self { 569 | StdinSource::Normal(source) => source.next_token(), 570 | StdinSource::Interactive(source) => source.next_token(), 571 | StdinSource::Unknown(source) => source.next_token(), 572 | } 573 | } 574 | 575 | fn is_empty(&mut self) -> bool { 576 | match self { 577 | StdinSource::Normal(source) => source.is_empty(), 578 | StdinSource::Interactive(source) => source.is_empty(), 579 | StdinSource::Unknown(source) => source.is_empty(), 580 | } 581 | } 582 | } 583 | 584 | #[doc(hidden)] 585 | pub static STDIN_SOURCE: OnceLock>>> = OnceLock::new(); 586 | 587 | /// Read input and define variable from specified source. 588 | /// 589 | /// Basic syntax is: 590 | /// 591 | /// ```text 592 | /// input! { 593 | /// from source, // optional: if you omitted, stdin is used by default. 594 | /// (mut) variable: type, // mut is optional: mut makes the variable mutable. 595 | /// (mut) variable: with runtime_readable, // RuntimeReadable version. 596 | /// ... 597 | /// } 598 | /// ``` 599 | /// 600 | /// The trailing comma is optional. `source` can be anything implementing `Source`. This macro 601 | /// moves out the specified source. If you want to prevent moving, you can use `&mut source` since 602 | /// `&mut S` where `S: Source` also implements `Source`. 603 | #[macro_export] 604 | macro_rules! input { 605 | // terminator 606 | (@from [$source:expr] @rest) => {}; 607 | 608 | // parse mutability 609 | (@from [$source:expr] @rest mut $($rest:tt)*) => { 610 | $crate::input! { 611 | @from [$source] 612 | @mut [mut] 613 | @rest $($rest)* 614 | } 615 | }; 616 | (@from [$source:expr] @rest $($rest:tt)*) => { 617 | $crate::input! { 618 | @from [$source] 619 | @mut [] 620 | @rest $($rest)* 621 | } 622 | }; 623 | 624 | // parse variable pattern 625 | (@from [$source:expr] @mut [$($mut:tt)?] @rest $var:tt: $($rest:tt)*) => { 626 | $crate::input! { 627 | @from [$source] 628 | @mut [$($mut)*] 629 | @var $var 630 | @kind [] 631 | @rest $($rest)* 632 | } 633 | }; 634 | 635 | // parse `with` (the marker of RuntimeReadable type) 636 | (@from [$source:expr] @mut [$($mut:tt)?] @var $var:tt @kind [] @rest with $($rest:tt)*) => { 637 | $crate::input! { 638 | @from [$source] 639 | @mut [$($mut)*] 640 | @var $var 641 | @dyn_kind [] 642 | @rest $($rest)* 643 | } 644 | }; 645 | 646 | // parse kind (Readable type) 647 | (@from [$source:expr] @mut [$($mut:tt)?] @var $var:tt @kind [$($kind:tt)*] @rest) => { 648 | let $($mut)* $var = $crate::read_value!(@source [$source] @kind [$($kind)*]); 649 | }; 650 | (@from [$source:expr] @mut [$($mut:tt)?] @var $var:tt @kind [$($kind:tt)*] @rest, $($rest:tt)*) => { 651 | $crate::input!(@from [$source] @mut [$($mut)*] @var $var @kind [$($kind)*] @rest); 652 | $crate::input!(@from [$source] @rest $($rest)*); 653 | }; 654 | (@from [$source:expr] @mut [$($mut:tt)?] @var $var:tt @kind [] @rest [$($tt:tt)*] $($rest:tt)*) => { 655 | $crate::input!(@from [$source] @mut [$($mut)*] @var $var @kind [[$($tt)*]] @rest $($rest)*); 656 | }; 657 | (@from [$source:expr] @mut [$($mut:tt)?] @var $var:tt @kind [] @rest ($($tt:tt)*) $($rest:tt)*) => { 658 | $crate::input!(@from [$source] @mut [$($mut)*] @var $var @kind [($($tt)*)] @rest $($rest)*); 659 | }; 660 | (@from [$source:expr] @mut [$($mut:tt)?] @var $var:tt @kind [] @rest $ty:ty, $($rest:tt)*) => { 661 | $crate::input!(@from [$source] @mut [$($mut)*] @var $var @kind [$ty] @rest, $($rest)*); 662 | }; 663 | (@from [$source:expr] @mut [$($mut:tt)?] @var $var:tt @kind [] @rest $ty:ty) => { 664 | $crate::input!(@from [$source] @mut [$($mut)*] @var $var @kind [$ty] @rest); 665 | }; 666 | 667 | // parse runtime kind (RuntimeReadable type) 668 | (@from [$source:expr] @mut [$($mut:tt)?] @var $var:tt @dyn_kind [$($dyn_kind:tt)*] @rest) => { 669 | let $($mut)* $var = $crate::read_value!(@source [$source] @dyn_kind [$($dyn_kind)*]); 670 | }; 671 | (@from [$source:expr] @mut [$($mut:tt)?] @var $var:tt @dyn_kind [$($dyn_kind:tt)*] @rest, $($rest:tt)*) => { 672 | $crate::input!(@from [$source] @mut [$($mut)*] @var $var @dyn_kind [$($dyn_kind)*] @rest); 673 | $crate::input!(@from [$source] @rest $($rest)*); 674 | }; 675 | (@from [$source:expr] @mut [$($mut:tt)?] @var $var:tt @dyn_kind [$($dyn_kind:tt)*] @rest $dyn_readable:expr) => { 676 | $crate::input!(@from [$source] @mut [$($mut)*] @var $var @dyn_kind [$($dyn_kind)* $dyn_readable] @rest); 677 | }; 678 | (@from [$source:expr] @mut [$($mut:tt)?] @var $var:tt @dyn_kind [$($dyn_kind:tt)*] @rest $dyn_readable:expr, $($rest:tt)*) => { 679 | $crate::input!(@from [$source] @mut [$($mut)*] @var $var @dyn_kind [$($dyn_kind)* $dyn_readable] @rest , $($rest)*); 680 | }; 681 | (@from $($tt:tt)*) => { 682 | compile_error!(concat!( 683 | "Reached unreachable statement while parsing macro input. ", 684 | "This is a bug in `proconio`. ", 685 | "Please report this issue from ", 686 | "." 687 | )); 688 | }; 689 | 690 | // interface 691 | (from $source:expr, $($rest:tt)*) => { 692 | #[allow(unused_variables, unused_mut)] 693 | let mut s = $source; 694 | $crate::input! { 695 | @from [&mut s] 696 | @rest $($rest)* 697 | } 698 | }; 699 | ($($rest:tt)*) => { 700 | let mut locked_stdin = $crate::__acquire_global_stdin_lock(); 701 | $crate::input! { 702 | @from [&mut *locked_stdin] 703 | @rest $($rest)* 704 | } 705 | drop(locked_stdin); // release the lock 706 | }; 707 | } 708 | 709 | /// Interactive version of input! macro. 710 | /// 711 | /// This macro is effectively an alias of: 712 | /// 713 | /// ```text 714 | /// let source = procontio::source::line::LineSource::new(BufReader::new(std::io::stdin())); 715 | /// input! { 716 | /// from &mut source, 717 | /// (mut) variable: type, 718 | /// ... 719 | /// } 720 | /// ``` 721 | /// 722 | /// With this macro, you always read inputs line-by-line. You can use this as a drop-in replacement 723 | /// for input! macro in interactive problems. Other than that, usage are the same with input! macro. 724 | /// Read the document of [input!](input) for further information. 725 | #[macro_export] 726 | macro_rules! input_interactive { 727 | ($($rest:tt)*) => { 728 | let mut locked_stdin = $crate::__acquire_global_stdin_lock(); 729 | $crate::input! { 730 | from &mut *locked_stdin, 731 | $($rest)* 732 | } 733 | drop(locked_stdin); // release the lock 734 | }; 735 | } 736 | 737 | /// Read input from specified source. 738 | /// Basic syntax is: 739 | /// 740 | /// ```text 741 | /// let variable = read_value!(type); 742 | /// let variable = read_value!(with runtime_readable); 743 | /// // or 744 | /// let variable = read_value!(from source, type); 745 | /// let variable = read_value!(from source, with runtime_readable); 746 | /// ``` 747 | /// 748 | /// You can use any types that can be used with input! macro. 749 | #[macro_export] 750 | macro_rules! read_value { 751 | // array and variable length array 752 | (@source [$source:expr] @kind [[$($kind:tt)*]]) => { 753 | $crate::read_value!(@array @source [$source] @kind [] @rest $($kind)*) 754 | }; 755 | (@array @source [$source:expr] @kind [$($kind:tt)*] @rest) => {{ 756 | let len = ::read($source); 757 | $crate::read_value!(@source [$source] @kind [[$($kind)*; len]]) 758 | }}; 759 | (@array @source [$source:expr] @kind [$($kind:tt)*] @rest ; $($rest:tt)*) => { 760 | $crate::read_value!(@array @source [$source] @kind [$($kind)*] @len [$($rest)*]) 761 | }; 762 | (@array @source [$source:expr] @kind [$($kind:tt)*] @rest $tt:tt $($rest:tt)*) => { 763 | $crate::read_value!(@array @source [$source] @kind [$($kind)* $tt] @rest $($rest)*) 764 | }; 765 | (@array @source [$source:expr] @kind [$($kind:tt)*] @len [$($len:tt)*]) => {{ 766 | let len = $($len)*; 767 | (0..len) 768 | .map(|_| $crate::read_value!(@source [$source] @kind [$($kind)*])) 769 | .collect::>() 770 | }}; 771 | 772 | // tuple 773 | (@source [$source:expr] @kind [($($kinds:tt)*)]) => { 774 | $crate::read_value!(@tuple @source [$source] @kinds [] @current [] @rest $($kinds)*) 775 | }; 776 | (@tuple @source [$source:expr] @kinds [$([$($kind:tt)*])*] @current [] @rest) => { 777 | ( 778 | $($crate::read_value!(@source [$source] @kind [$($kind)*]),)* 779 | ) 780 | }; 781 | (@tuple @source [$source:expr] @kinds [$($kinds:tt)*] @current [$($curr:tt)*] @rest) => { 782 | $crate::read_value!(@tuple @source [$source] @kinds [$($kinds)* [$($curr)*]] @current [] @rest) 783 | }; 784 | (@tuple @source [$source:expr] @kinds [$($kinds:tt)*] @current [$($curr:tt)*] @rest, $($rest:tt)*) => { 785 | $crate::read_value!(@tuple @source [$source] @kinds [$($kinds)* [$($curr)*]] @current [] @rest $($rest)*) 786 | }; 787 | (@tuple @source [$source:expr] @kinds [$($kinds:tt)*] @current [$($curr:tt)*] @rest $tt:tt $($rest:tt)*) => { 788 | $crate::read_value!(@tuple @source [$source] @kinds [$($kinds)*] @current [$($curr)* $tt] @rest $($rest)*) 789 | }; 790 | 791 | // normal other 792 | (@source [$source:expr] @kind [$kind:ty]) => { 793 | <$kind as $crate::__Readable>::read($source) 794 | }; 795 | 796 | // runtime readable 797 | (@source [$source:expr] @dyn_kind [$dyn_kind:expr]) => { 798 | $crate::source::RuntimeReadable::read($dyn_kind, $source) 799 | }; 800 | 801 | // unreachable 802 | (@source [$source:expr] @kind []) => { 803 | compile_error!(concat!( 804 | "Reached unreachable statement while parsing macro input. ", 805 | "This is a bug in `proconio`. ", 806 | "Please report this issue from ", 807 | "." 808 | )); 809 | }; 810 | 811 | // interface 812 | (from $source:expr, with $($rest:tt)*) => {{ 813 | #[allow(unused_variables, unused_mut)] 814 | let mut s = $source; 815 | $crate::read_value!(@source [&mut s] @dyn_kind [$($rest)*]) 816 | }}; 817 | (from $source:expr, $($rest:tt)*) => {{ 818 | #[allow(unused_variables, unused_mut)] 819 | let mut s = $source; 820 | $crate::read_value!(@source [&mut s] @kind [$($rest)*]) 821 | }}; 822 | ($($rest:tt)*) => {{ 823 | let mut locked_stdin = $crate::STDIN_SOURCE 824 | .get_or_init(|| { 825 | std::sync::Mutex::new($crate::StdinSource::Normal( 826 | $crate::source::auto::AutoSource::new(std::io::BufReader::new(std::io::stdin())), 827 | )) 828 | }) 829 | .lock() 830 | .expect(concat!( 831 | "failed to lock the stdin; please re-run this program. ", 832 | "If this issue repeatedly occur, this is a bug in `proconio`. ", 833 | "Please report this issue from ", 834 | "." 835 | )); 836 | let __res = $crate::read_value!(from &mut *locked_stdin, $($rest)*); 837 | drop(locked_stdin); // release the lock 838 | __res 839 | }}; 840 | } 841 | 842 | /// Interactive version of `read_value!` macro. 843 | /// 844 | /// This macro is equivalent to do the following: 845 | /// 846 | /// ```text 847 | /// let source = procontio::source::line::LineSource::new(BufReader::new(std::io::stdin())); 848 | /// let variable = read_value!(from &mut source, type); 849 | /// ``` 850 | /// 851 | /// With this macro, you always read inputs line-by-line. You can use this as a drop-in replacement 852 | /// for read_value! macro in interactive problems. Other than that, usage are the same with 853 | /// read_value! macro. Read the document of [read_value!](read_value) for further information. 854 | #[macro_export] 855 | macro_rules! read_value_interactive { 856 | ($($rest:tt)*) => { 857 | let mut locked_stdin = $crate::acquire_global_stdin_lock(); 858 | let __res = $crate::read_value!(from &mut *locked_stdin, $($rest)*); 859 | drop(locked_stdin); // release the lock 860 | __res 861 | }; 862 | } 863 | 864 | // Acquires the global stdin lock. This must be public because it appears in macro-expanded code, 865 | // but hidden in doc because this implementation detail should be considered as private. 866 | #[doc(hidden)] 867 | pub fn __acquire_global_stdin_lock() -> MutexGuard<'static, StdinSource>> { 868 | STDIN_SOURCE 869 | .get_or_init(|| { 870 | Mutex::new(StdinSource::Unknown(LineSource::new(BufReader::new( 871 | io::stdin(), 872 | )))) 873 | }) 874 | .lock() 875 | .expect(concat!( 876 | "failed to lock the stdin; please re-run this program. ", 877 | "If this issue repeatedly occur, this is a bug in `proconio`. ", 878 | "Please report this issue from ", 879 | "." 880 | )) 881 | } 882 | 883 | /// Checks if some of tokens are left on stdin. 884 | /// 885 | /// This is useful when the number of test cases is not specified like ICPC problems. 886 | /// 887 | /// ```text 888 | /// loop { 889 | /// if is_stdin_empty() { 890 | /// break; 891 | /// } 892 | /// 893 | /// // do the normal logic 894 | /// input! { ... } 895 | /// } 896 | /// ``` 897 | pub fn is_stdin_empty() -> bool { 898 | use source::Source; 899 | let mut lock = __acquire_global_stdin_lock(); 900 | lock.is_empty() 901 | } 902 | 903 | #[cfg(test)] 904 | mod tests { 905 | use std::marker::PhantomData; 906 | 907 | use crate::source::auto::AutoSource; 908 | 909 | #[test] 910 | fn input_empty() { 911 | let source = AutoSource::from(""); 912 | input! { 913 | from source, 914 | } 915 | } 916 | 917 | #[test] 918 | fn input_number() { 919 | let source = AutoSource::from(" 32 54 -23\r\r\n\nfalse"); 920 | 921 | input! { 922 | from source, 923 | n: u8, 924 | m: u32, 925 | l: i32, 926 | } 927 | 928 | assert_eq!(n, 32); 929 | assert_eq!(m, 54); 930 | assert_eq!(l, -23); 931 | } 932 | 933 | #[test] 934 | fn read_value_number() { 935 | let mut source = AutoSource::from(" 32 54 -23\r\r\n\nfalse"); 936 | 937 | assert_eq!(read_value!(from &mut source, u8), 32); 938 | assert_eq!(read_value!(from &mut source, u32), 54); 939 | assert_eq!(read_value!(from &mut source, i32), -23); 940 | } 941 | 942 | #[test] 943 | fn input_str() { 944 | use crate::marker::{Bytes, Chars}; 945 | let source = AutoSource::from(" string chars\nbytes"); 946 | 947 | input! { 948 | from source, 949 | string: String, 950 | chars: Chars, 951 | bytes: Bytes, 952 | } 953 | 954 | assert_eq!(string, "string"); 955 | assert_eq!(chars, ['c', 'h', 'a', 'r', 's']); 956 | assert_eq!(bytes, b"bytes"); 957 | } 958 | 959 | #[test] 960 | fn read_value_str() { 961 | use crate::marker::{Bytes, Chars}; 962 | let mut source = AutoSource::from(" string chars\nbytes"); 963 | 964 | assert_eq!(read_value!(from &mut source, String), "string"); 965 | assert_eq!( 966 | read_value!(from &mut source, Chars), 967 | ['c', 'h', 'a', 'r', 's'] 968 | ); 969 | assert_eq!(read_value!(from &mut source, Bytes), b"bytes"); 970 | } 971 | 972 | #[test] 973 | fn input_array() { 974 | let source = AutoSource::from("5 3 1 2 3 4 5 1 2 3 4 5 1 2 3 4 5 1 2 3 4 5"); 975 | 976 | input! { 977 | from source, 978 | n: usize, 979 | m: usize, 980 | a: [i32; n], 981 | b: [[i32; n]; m] // no trailing comma is OK 982 | } 983 | 984 | assert_eq!(a, [1, 2, 3, 4, 5]); 985 | assert_eq!(b, [[1, 2, 3, 4, 5], [1, 2, 3, 4, 5], [1, 2, 3, 4, 5]]); 986 | } 987 | 988 | #[test] 989 | fn read_value_array() { 990 | let mut source = AutoSource::from("5 3 1 2 3 4 5 1 2 3 4 5 1 2 3 4 5 1 2 3 4 5"); 991 | 992 | let n = read_value!(from &mut source, usize); 993 | let m = read_value!(from &mut source, usize); 994 | let a = read_value!(from &mut source, [i32; n]); 995 | let b = read_value!(from &mut source, [[i32; n]; m]); 996 | 997 | assert_eq!(a, [1, 2, 3, 4, 5]); 998 | assert_eq!(b, [[1, 2, 3, 4, 5], [1, 2, 3, 4, 5], [1, 2, 3, 4, 5]]); 999 | } 1000 | 1001 | #[test] 1002 | fn input_vla() { 1003 | let source = AutoSource::from("5 3 1 2 3 2 1 2 4 1 2 3 4 0 6 1 2 3 4 5 6"); 1004 | 1005 | input! { 1006 | from source, 1007 | n: usize, 1008 | a: [[i32]; n], 1009 | } 1010 | 1011 | assert_eq!( 1012 | a, 1013 | vec![ 1014 | vec![1, 2, 3], 1015 | vec![1, 2], 1016 | vec![1, 2, 3, 4], 1017 | vec![], 1018 | vec![1, 2, 3, 4, 5, 6], 1019 | ] 1020 | ); 1021 | } 1022 | 1023 | #[test] 1024 | fn read_value_vla() { 1025 | let mut source = AutoSource::from("5 3 1 2 3 2 1 2 4 1 2 3 4 0 6 1 2 3 4 5 6"); 1026 | 1027 | let n = read_value!(from &mut source, usize); 1028 | let a = read_value!(from &mut source, [[i32]; n]); 1029 | 1030 | assert_eq!( 1031 | a, 1032 | vec![ 1033 | vec![1, 2, 3], 1034 | vec![1, 2], 1035 | vec![1, 2, 3, 4], 1036 | vec![], 1037 | vec![1, 2, 3, 4, 5, 6], 1038 | ] 1039 | ); 1040 | } 1041 | 1042 | #[test] 1043 | fn input_tuple() { 1044 | let mut source = AutoSource::from("4 1 2 3 4 5 1 2 3 4 5 1 2 3 4 5 1 2 3 4 5"); 1045 | 1046 | let n = read_value!(from &mut source, usize); 1047 | let t = read_value!(from &mut source, [(i32, i32, i32, i32, i32); n]); 1048 | 1049 | assert_eq!( 1050 | t, 1051 | [ 1052 | (1, 2, 3, 4, 5), 1053 | (1, 2, 3, 4, 5), 1054 | (1, 2, 3, 4, 5), 1055 | (1, 2, 3, 4, 5) 1056 | ] 1057 | ); 1058 | } 1059 | 1060 | #[test] 1061 | fn input_multiple_times() { 1062 | let mut source = AutoSource::from("4 1 2 3 4\n1 2\r\n\r\r\n3 4"); 1063 | 1064 | input! { 1065 | from &mut source, 1066 | n: usize, 1067 | } 1068 | 1069 | for i in 0..n { 1070 | input! { 1071 | from &mut source, 1072 | j: i32, k: i32, 1073 | } 1074 | 1075 | assert_eq!(j, if i % 2 == 0 { 1 } else { 3 }); 1076 | assert_eq!(k, if i % 2 == 0 { 2 } else { 4 }); 1077 | } 1078 | } 1079 | 1080 | #[test] 1081 | fn input_iusize1() { 1082 | use crate::marker::Usize1; 1083 | 1084 | let mut source = AutoSource::from("4 1 2 3 4 5 6 7 8"); 1085 | 1086 | input! { 1087 | from &mut source, 1088 | n: usize, 1089 | } 1090 | 1091 | for i in 0..n { 1092 | input! { 1093 | from &mut source, 1094 | from: Usize1, to: Usize1 1095 | } 1096 | 1097 | assert_eq!(from, i * 2); 1098 | assert_eq!(to, i * 2 + 1); 1099 | } 1100 | } 1101 | 1102 | #[test] 1103 | #[should_panic] 1104 | fn input_zero_as_usize1() { 1105 | use crate::marker::Usize1; 1106 | let mut source = AutoSource::from("0"); 1107 | input! { 1108 | from &mut source, 1109 | _v: Usize1, 1110 | } 1111 | } 1112 | 1113 | #[test] 1114 | #[should_panic] 1115 | fn input_min_as_isize1() { 1116 | use crate::marker::Isize1; 1117 | let min_string = isize::MIN.to_string(); 1118 | let mut source = AutoSource::from(&*min_string); 1119 | input! { 1120 | from &mut source, 1121 | _v: Isize1, 1122 | } 1123 | } 1124 | 1125 | #[test] 1126 | fn input_mut() { 1127 | let mut source = AutoSource::from("8 1 2 3 4 5 6 7 8"); 1128 | 1129 | input! { 1130 | from &mut source, 1131 | mut n: usize, 1132 | } 1133 | 1134 | let mut sum = 0; 1135 | while n > 0 { 1136 | input!(from &mut source, x: u32); 1137 | sum += x; 1138 | n -= 1; 1139 | } 1140 | assert_eq!(sum, 36); 1141 | } 1142 | 1143 | #[test] 1144 | fn input_with_complex_type() { 1145 | let mut source = AutoSource::from("Hello\n2\n3 1 2 3\n4 5 ab\n4"); 1146 | input! { 1147 | from &mut source, 1148 | hello: crate::marker::Bytes, 1149 | from: crate::marker::Usize1, 1150 | vla: [crate::marker::Isize1], 1151 | tuple: (crate::marker::Usize1, crate::marker::Isize1, crate::marker::Chars), 1152 | unit: (crate::marker::Usize1), 1153 | } 1154 | assert_eq!(hello, b"Hello"); 1155 | assert_eq!(from, 1); 1156 | assert_eq!(vla, [0, 1, 2]); 1157 | assert_eq!(tuple, (3, 4, vec!['a', 'b'])); 1158 | assert_eq!(unit, (3,)); 1159 | } 1160 | 1161 | #[test] 1162 | fn input_single_tt_pattern() { 1163 | let mut source = AutoSource::from("3 42 0\n1 2 3\n"); 1164 | input! { 1165 | from &mut source, 1166 | (n, mut k): (usize, usize), 1167 | _: usize, 1168 | xs: [u32; n], 1169 | } 1170 | k += 1; 1171 | assert_eq!(n, 3); 1172 | assert_eq!(k, 43); 1173 | assert_eq!(xs, [1, 2, 3]); 1174 | } 1175 | 1176 | #[test] 1177 | fn input_generic() { 1178 | enum Array { 1179 | _Phantom( 1180 | std::convert::Infallible, 1181 | std::marker::PhantomData T>, 1182 | ), 1183 | } 1184 | 1185 | impl crate::source::Readable for Array { 1186 | type Output = [T::Output; N]; 1187 | 1188 | fn read>( 1189 | source: &mut S, 1190 | ) -> Self::Output { 1191 | std::array::from_fn(|_| T::read(source)) 1192 | } 1193 | } 1194 | 1195 | let source = AutoSource::from("1 2 3 4 5 6 7 8"); 1196 | 1197 | input! { 1198 | from source, 1199 | a: Array, 1200 | b: Array, 1201 | } 1202 | 1203 | assert_eq!(a, [1, 2, 3, 4, 5]); 1204 | assert_eq!(b, [6, 7, 8]); 1205 | } 1206 | 1207 | #[test] 1208 | fn read_value_generic() { 1209 | enum Array { 1210 | _Phantom( 1211 | std::convert::Infallible, 1212 | std::marker::PhantomData T>, 1213 | ), 1214 | } 1215 | 1216 | impl crate::source::Readable for Array { 1217 | type Output = [T::Output; N]; 1218 | 1219 | fn read>( 1220 | source: &mut S, 1221 | ) -> Self::Output { 1222 | std::array::from_fn(|_| T::read(source)) 1223 | } 1224 | } 1225 | 1226 | let mut source = AutoSource::from("1 2 3 4 5 6 7 8"); 1227 | 1228 | let a = read_value!(from &mut source, Array); 1229 | let b = read_value!(from &mut source, Array); 1230 | 1231 | assert_eq!(a, [1, 2, 3, 4, 5]); 1232 | assert_eq!(b, [6, 7, 8]); 1233 | } 1234 | 1235 | #[test] 1236 | fn input_runtime_readable() { 1237 | // VecReadable replicates the built-in Vec reader `input!(v: [T])` in user-land. 1238 | struct VecReadable { 1239 | n: usize, 1240 | _marker: PhantomData, 1241 | } 1242 | 1243 | impl VecReadable { 1244 | pub fn new(n: usize) -> Self { 1245 | VecReadable { 1246 | n, 1247 | _marker: PhantomData, 1248 | } 1249 | } 1250 | } 1251 | 1252 | impl crate::source::RuntimeReadable for VecReadable { 1253 | type Output = Vec; 1254 | 1255 | fn read>( 1256 | self, 1257 | source: &mut S, 1258 | ) -> Self::Output { 1259 | let mut res = vec![]; 1260 | for _ in 0..self.n { 1261 | input! { 1262 | from &mut *source, 1263 | v: T, 1264 | } 1265 | res.push(v); 1266 | } 1267 | res 1268 | } 1269 | } 1270 | 1271 | let mut source = AutoSource::from("4 1 2 3 4"); 1272 | input! { 1273 | from &mut source, 1274 | n: usize, 1275 | v: with VecReadable::::new(n), 1276 | } 1277 | 1278 | assert_eq!(v, [0, 1, 2, 3]); 1279 | } 1280 | 1281 | #[test] 1282 | fn read_value_runtime_readable() { 1283 | // VecReadable replicates the built-in Vec reader `input!(v: [T])` in user-land. 1284 | struct VecReadable { 1285 | n: usize, 1286 | _marker: PhantomData, 1287 | } 1288 | 1289 | impl VecReadable { 1290 | pub fn new(n: usize) -> Self { 1291 | VecReadable { 1292 | n, 1293 | _marker: PhantomData, 1294 | } 1295 | } 1296 | } 1297 | 1298 | impl crate::source::RuntimeReadable for VecReadable { 1299 | type Output = Vec; 1300 | 1301 | fn read>( 1302 | self, 1303 | source: &mut S, 1304 | ) -> Self::Output { 1305 | let mut res = vec![]; 1306 | for _ in 0..self.n { 1307 | input! { 1308 | from &mut *source, 1309 | v: T, 1310 | } 1311 | res.push(v); 1312 | } 1313 | res 1314 | } 1315 | } 1316 | 1317 | let mut source = AutoSource::from("4 1 2 3 4"); 1318 | let n = read_value!(from &mut source, usize); 1319 | let v = read_value!(from &mut source, with VecReadable::::new(n)); 1320 | 1321 | assert_eq!(v, [0, 1, 2, 3]); 1322 | } 1323 | 1324 | #[test] 1325 | #[should_panic] 1326 | fn input_err_different_type() { 1327 | let mut source = AutoSource::from("3.2\n"); 1328 | input! { 1329 | from &mut source, 1330 | _n: i32, 1331 | } 1332 | } 1333 | 1334 | #[test] 1335 | #[should_panic] 1336 | fn input_err_different_format() { 1337 | let mut source = AutoSource::from(""); 1338 | input! { 1339 | from &mut source, 1340 | _n: i32, 1341 | } 1342 | } 1343 | } 1344 | -------------------------------------------------------------------------------- /proconio/src/marker.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2019 statiolake 2 | // 3 | // Licensed under the Apache License, Version 2.0 or the MIT license , at your option. This file may not be copied, modified, or 6 | // distributed except according to those terms. 7 | 8 | //! Declares special marker types. 9 | 10 | use crate::source::{Readable, Source}; 11 | use std::io::BufRead; 12 | 13 | /// Chars: read a string as array of chars. 14 | pub enum Chars {} 15 | 16 | impl Readable for Chars { 17 | type Output = Vec; 18 | fn read>(source: &mut S) -> Vec { 19 | source.next_token_unwrap().chars().collect() 20 | } 21 | } 22 | 23 | /// Bytes: read a string as array of bytes. 24 | pub enum Bytes {} 25 | 26 | impl Readable for Bytes { 27 | type Output = Vec; 28 | fn read>(source: &mut S) -> Vec { 29 | source.next_token_unwrap().bytes().collect() 30 | } 31 | } 32 | 33 | /// Usize1: 1-indexed usize. Output of reading has type usize. 34 | pub enum Usize1 {} 35 | 36 | impl Readable for Usize1 { 37 | type Output = usize; 38 | fn read>(source: &mut S) -> usize { 39 | // panic if the subtraction overflows 40 | usize::read(source) 41 | .checked_sub(1) 42 | .expect("attempted to read the value 0 as a Usize1") 43 | } 44 | } 45 | 46 | /// Isize1: 1-indexed isize. Output of reading has type isize. 47 | pub enum Isize1 {} 48 | 49 | impl Readable for Isize1 { 50 | type Output = isize; 51 | fn read>(source: &mut S) -> isize { 52 | // FIXME: Which is appropriate, forbidding all negative values or only isize::MIN. For now 53 | // we disallow only isize::MIN. 54 | // ensure the value is more than isize::MIN, or subtract overflows. 55 | isize::read(source).checked_sub(1).unwrap_or_else(|| { 56 | panic!( 57 | concat!( 58 | "attempted to read the value {} as a Isize1:", 59 | " the value is isize::MIN and cannot be decremented" 60 | ), 61 | isize::MIN, 62 | ) 63 | }) 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /proconio/src/source/line.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2019 statiolake 2 | // 3 | // Licensed under the Apache License, Version 2.0 or the MIT license , at your option. This file may not be copied, modified, or 6 | // distributed except according to those terms. 7 | 8 | use super::Source; 9 | use crate::source::tokens::Tokens; 10 | use std::io::BufRead; 11 | 12 | /// Source reading stream line by line. 13 | /// 14 | /// It is a wrapper for `BufRead`. You can create `LineSource` from any type implementing 15 | /// `BufRead`. 16 | pub struct LineSource { 17 | tokens: Tokens, 18 | reader: R, 19 | } 20 | 21 | impl LineSource { 22 | /// Creates a `LineSource` by specified `BufRead`. 23 | pub fn new(reader: R) -> LineSource { 24 | // dummy values. 25 | LineSource { 26 | tokens: "".to_owned().into(), 27 | reader, 28 | } 29 | } 30 | 31 | fn prepare(&mut self) { 32 | while self.tokens.is_empty() { 33 | let mut line = String::new(); 34 | let num_bytes = self 35 | .reader 36 | .read_line(&mut line) 37 | .expect("failed to get linel maybe an IO error."); 38 | 39 | if num_bytes == 0 { 40 | // reached EOF 41 | return; 42 | } 43 | 44 | self.tokens = line.into(); 45 | } 46 | } 47 | } 48 | 49 | impl Source for LineSource { 50 | /// Gets a next token. 51 | fn next_token(&mut self) -> Option<&str> { 52 | // while tokens are empty, reads a new line. 53 | self.prepare(); 54 | self.tokens.next_token() 55 | } 56 | 57 | /// Check if tokens are empty 58 | fn is_empty(&mut self) -> bool { 59 | self.prepare(); 60 | self.tokens.is_empty() 61 | } 62 | } 63 | 64 | use std::io::BufReader; 65 | 66 | /// You can create `LineSource` from `&str`. Since `&[u8]` is a `Read`, `BufRead` can be easily 67 | /// created by wrapping using `BufReader`. 68 | impl<'a> From<&'a str> for LineSource> { 69 | fn from(s: &'a str) -> LineSource> { 70 | LineSource::new(BufReader::new(s.as_bytes())) 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /proconio/src/source/mod.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2019 statiolake 2 | // 3 | // Licensed under the Apache License, Version 2.0 or the MIT license , at your option. This file may not be copied, modified, or 6 | // distributed except according to those terms. 7 | 8 | //! Defines whitespace-splitted token stream wrapping actual stream like stdin. 9 | //! 10 | //! The main is trait `Source`. This is implemented to the following two type of source: 11 | //! 12 | //! 1. Read entire source at once. (`once::OnceSource`) 13 | //! 1. Read source line by line. (`line::LineSource`) 14 | //! 15 | //! `OnceSource` is very fast, while `LineSource` is handy for local debugging. `OnceSource` must 16 | //! read entire input before any other work and you must put EOF (Ctrl-D on Unix or Ctrl-Z on 17 | //! Windows) after input. LineSource reads source one by one. Simply press enter to input. 18 | //! 19 | //! There is another source named `auto::AutoSource`. `AutoSource` is `OnceSource` in release 20 | //! build, is `LineSource` in debug build. If you use debug build in local testing, `LineSource`, 21 | //! convenience version is used. In judge server it is compiled in release mode, so `OnceSource`, 22 | //! faster version is used. This is usually no problem in judging (except interactive problem?). 23 | //! 24 | //! You can specify the source to be used in `input!` as follows: 25 | //! 26 | //! ``` 27 | //! # extern crate proconio; 28 | //! use proconio::source::auto::AutoSource; 29 | //! use proconio::input; 30 | //! 31 | //! let source = AutoSource::from("32 54 -23"); 32 | //! input! { 33 | //! from source, 34 | //! n: u8, 35 | //! m: u32, 36 | //! l: i32, 37 | //! } 38 | //! 39 | //! println!("{} {} {}", n, m, l); 40 | //! assert_eq!(n, 32); 41 | //! assert_eq!(m, 54); 42 | //! assert_eq!(l, -23); 43 | //! ``` 44 | //! 45 | //! In above example, `OnceSource>` and `LineSource>` implements 46 | //! `From<&str>`, so you can create the source from a string literal. You can create an instance 47 | //! directly from the value of type implementing `BufRead` by using `OnceSource::new()` and 48 | //! `LineSource::new()`. 49 | //! 50 | //! If you use `input!` macro with no source specified then it uses `AutoSource` with stdin. So, 51 | //! locally `LineSource` are used, in the server `OnceSource` are used. `OnceSource` and 52 | //! `LineSource` behaves samely in point of the read result, but, unintentionally, it may differ in 53 | //! a bare possibility. If it should differ, you can manually specify `LineSource` as `source` of 54 | //! `input!`. 55 | use std::any::type_name; 56 | use std::fmt::Debug; 57 | use std::io::BufRead; 58 | use std::str::FromStr; 59 | 60 | pub mod line; 61 | pub mod once; 62 | mod tokens; 63 | 64 | pub mod auto { 65 | //! Defines `AutoSource`. 66 | //! 67 | //! It is `LineSource` for debug build, `OnceSource` for release build. 68 | 69 | #[cfg(debug_assertions)] 70 | pub use super::line::LineSource as AutoSource; 71 | #[cfg(not(debug_assertions))] 72 | pub use super::once::OnceSource as AutoSource; 73 | } 74 | 75 | /// The main trait. Types implementing this trait can be used for source of `input!` macro. 76 | pub trait Source { 77 | /// Gets a whitespace-splitted next token. 78 | fn next_token(&mut self) -> Option<&str>; 79 | 80 | /// Check if tokens are empty 81 | #[allow(clippy::wrong_self_convention)] 82 | fn is_empty(&mut self) -> bool; 83 | 84 | /// Force gets a whitespace-splitted next token. 85 | fn next_token_unwrap(&mut self) -> &str { 86 | self.next_token().expect(concat!( 87 | "failed to get the next token; ", 88 | "maybe reader reached an end of input. ", 89 | "ensure that arguments for `input!` macro is correctly ", 90 | "specified to match the problem input." 91 | )) 92 | } 93 | } 94 | 95 | // &mut S where S: Source is also source. 96 | impl> Source for &'_ mut S { 97 | fn next_token(&mut self) -> Option<&str> { 98 | (*self).next_token() 99 | } 100 | 101 | fn is_empty(&mut self) -> bool { 102 | (*self).is_empty() 103 | } 104 | } 105 | 106 | /// A trait representing which type can be read from `Source`. 107 | /// 108 | /// If you want to read your own type using `input!`, you can implement this trait for your type. 109 | /// Alternatively, you can add `#[derive_readable]` if you put `use 110 | /// proconio_derive::derive_readable` in your source. It automatically implements `Readable` if 111 | /// all members of your type are `Readable`. 112 | pub trait Readable { 113 | type Output; 114 | fn read>(source: &mut S) -> Self::Output; 115 | } 116 | 117 | // implementations of Readable for any `FromStr` types including primitives. 118 | impl Readable for T 119 | where 120 | T::Err: Debug, 121 | { 122 | type Output = T; 123 | fn read>(source: &mut S) -> T { 124 | let token = source.next_token_unwrap(); 125 | match token.parse() { 126 | Ok(v) => v, 127 | Err(e) => panic!( 128 | concat!( 129 | "failed to parse the input `{input}` ", 130 | "to the value of type `{ty}`: {err:?}; ", 131 | "ensure that the input format is collectly specified ", 132 | "and that the input value must handle specified type.", 133 | ), 134 | input = token, 135 | ty = type_name::(), 136 | err = e, 137 | ), 138 | } 139 | } 140 | } 141 | 142 | /// A trait that specifies how to read a value of some type from `Source` in such a way that is only 143 | /// known at runtime, such as reading a vector or graph whose size is specified at runtime. 144 | /// 145 | /// ``` 146 | /// # use proconio::source::RuntimeReadable; 147 | /// # use proconio::source::auto::AutoSource; 148 | /// # use proconio::source::Source; 149 | /// # use proconio::input; 150 | /// # use proconio::marker::Usize1; 151 | /// # use std::io::BufRead; 152 | /// struct DirectedGraph(usize, usize); 153 | /// impl RuntimeReadable for DirectedGraph { 154 | /// type Output = Vec>; 155 | /// 156 | /// fn read>(self, source: &mut S) -> Self::Output { 157 | /// let DirectedGraph(n, m) = self; 158 | /// 159 | /// input! { 160 | /// from source, 161 | /// edges: [(Usize1, Usize1); m], 162 | /// }; 163 | /// 164 | /// let mut g = vec![vec![]; n]; 165 | /// for e in edges { 166 | /// g[e.0].push(e.1); 167 | /// } 168 | /// g 169 | /// } 170 | /// } 171 | /// 172 | /// # let mut source = AutoSource::from("2 3\n1 1\n1 2\n2 2\n"); 173 | /// input! { 174 | /// # from source, 175 | /// n: usize, 176 | /// m: usize, 177 | /// g: with DirectedGraph(n, m), 178 | /// } 179 | /// ``` 180 | pub trait RuntimeReadable { 181 | type Output; 182 | fn read>(self, source: &mut S) -> Self::Output; 183 | } 184 | -------------------------------------------------------------------------------- /proconio/src/source/once.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2019 statiolake 2 | // 3 | // Licensed under the Apache License, Version 2.0 or the MIT license , at your option. This file may not be copied, modified, or 6 | // distributed except according to those terms. 7 | 8 | use super::Source; 9 | use crate::source::tokens::Tokens; 10 | use std::io::BufRead; 11 | use std::marker::PhantomData; 12 | 13 | /// Source reading entire content for the first time. 14 | /// 15 | /// It is a wrapper for `BufRead`. You can create `OnceSource` from any type implementing 16 | /// `BufRead`. 17 | pub struct OnceSource { 18 | tokens: Tokens, 19 | 20 | // to consume `R`. Actually `OnceSource` is not need to have `R`, since reading is done in its 21 | // constructor. This is for the consistency with `LineSource` (To use smoothly through `AutoSource`). 22 | _read: PhantomData, 23 | } 24 | 25 | impl OnceSource { 26 | /// Creates `Source` using specified reader of `BufRead`. 27 | pub fn new(mut source: R) -> OnceSource { 28 | let mut context = String::new(); 29 | source 30 | .read_to_string(&mut context) 31 | .expect("failed to read from source; maybe an IO error."); 32 | 33 | OnceSource { 34 | tokens: context.into(), 35 | _read: PhantomData, 36 | } 37 | } 38 | } 39 | 40 | impl Source for OnceSource { 41 | /// Gets a next token. 42 | fn next_token(&mut self) -> Option<&str> { 43 | self.tokens.next_token() 44 | } 45 | 46 | /// Check if tokens are empty 47 | fn is_empty(&mut self) -> bool { 48 | self.tokens.is_empty() 49 | } 50 | } 51 | 52 | use std::io::BufReader; 53 | 54 | /// You can create `OnceSource` from `&str`. Since `&[u8]` is a `Read`, `BufRead` can be easily 55 | /// created by wrapping using `BufReader`. 56 | impl<'a> From<&'a str> for OnceSource> { 57 | fn from(s: &'a str) -> OnceSource> { 58 | OnceSource::new(BufReader::new(s.as_bytes())) 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /proconio/src/source/tokens.rs: -------------------------------------------------------------------------------- 1 | use std::{iter::Peekable, ptr::NonNull, str::SplitWhitespace}; 2 | 3 | pub(super) struct Tokens { 4 | // iterator that refers to `current_context` 5 | tokens: Peekable>, 6 | 7 | // context `tokens` reffering to 8 | _current_context: CurrentContext, 9 | } 10 | 11 | impl Tokens { 12 | pub(super) fn next_token(&mut self) -> Option<&str> { 13 | self.tokens.next() 14 | } 15 | 16 | pub(super) fn is_empty(&mut self) -> bool { 17 | self.tokens.peek().is_none() 18 | } 19 | } 20 | 21 | impl From for Tokens { 22 | fn from(current_context: String) -> Self { 23 | let current_context = CurrentContext::from(current_context); 24 | 25 | // # Safety 26 | // 27 | // - `tokens` is dropped before `current_context`. 28 | // - `current_context` is not accessed directly until dropped. 29 | unsafe { 30 | let tokens = current_context.0.as_ref().split_whitespace().peekable(); 31 | Self { 32 | tokens, 33 | _current_context: current_context, 34 | } 35 | } 36 | } 37 | } 38 | 39 | // # Safety 40 | // 41 | // - `current_context` is not accessed directly until dropped. 42 | // - `Box: Send`. 43 | unsafe impl Send for Tokens {} 44 | 45 | // # Safety 46 | // 47 | // - `current_context` is not accessed directly until dropped. 48 | // - `Box: Sync`. 49 | unsafe impl Sync for Tokens {} 50 | 51 | struct CurrentContext(NonNull); 52 | 53 | impl From for CurrentContext { 54 | fn from(s: String) -> Self { 55 | // deallocating the extra capacity 56 | let s = s.into_boxed_str(); 57 | 58 | Self(NonNull::new(Box::leak(s)).unwrap()) 59 | } 60 | } 61 | 62 | impl Drop for CurrentContext { 63 | fn drop(&mut self) { 64 | // # Safety 65 | // 66 | // The pointee should be no longer refferred. 67 | unsafe { drop(Box::from_raw(self.0.as_mut())) }; 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /proconio/tests/derive.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2019 statiolake 2 | // 3 | // Licensed under the Apache License, Version 2.0 or the MIT license , at your option. This file may not be copied, modified, or 6 | // distributed except according to those terms. 7 | 8 | use proconio::derive_readable; 9 | use proconio::input; 10 | use proconio::source::auto::AutoSource; 11 | 12 | #[derive_readable] 13 | #[derive(PartialEq, Debug)] 14 | struct Weight; 15 | 16 | #[derive_readable] 17 | #[derive(PartialEq, Debug)] 18 | struct Cost(pub(crate) i32); 19 | 20 | #[derive_readable] 21 | #[derive(Debug)] 22 | struct Edge { 23 | from: usize, 24 | pub to: proconio::marker::Usize1, 25 | pub(self) weight: Weight, 26 | pub(crate) cost: Cost, 27 | } 28 | 29 | #[test] 30 | fn derive() { 31 | let source = AutoSource::from(" 12 32 35"); 32 | input! { 33 | from source, 34 | edge: Edge, 35 | } 36 | 37 | assert_eq!(edge.from, 12); 38 | assert_eq!(edge.to, 31); 39 | assert_eq!(edge.weight, Weight); 40 | assert_eq!(edge.cost, Cost(35)); 41 | } 42 | -------------------------------------------------------------------------------- /proconio/tests/fastout.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2019 statiolake 2 | // 3 | // Licensed under the Apache License, Version 2.0 or the MIT license , at your option. This file may not be copied, modified, or 6 | // distributed except according to those terms. 7 | 8 | use proconio::fastout; 9 | 10 | #[fastout] 11 | fn foo() -> i32 { 12 | println!("4"); 13 | 3 14 | } 15 | 16 | #[allow(clippy::print_literal)] 17 | #[fastout] 18 | fn main() { 19 | let clo = || "AtCoder"; // OK; 20 | let name = clo(); 21 | // let _err = || println!("hello"); // error even it's not spown 22 | // std::thread::spawn(|| { 23 | // std::println!("hello"); 24 | // }); // of course error 25 | println!(); 26 | println!("hello, world, {}!", name); 27 | println!("{}", foo()); 28 | print!("{}{}, ", 'h', "ello"); // "hello" (no newline) 29 | println!("{}!", "world"); // "world!\n" 30 | println!("{}", 123_456_789); // "123456789\n" 31 | } 32 | -------------------------------------------------------------------------------- /proconio/tests/interactive.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2019 statiolake 2 | // 3 | // Licensed under the Apache License, Version 2.0 or the MIT license , at your option. This file may not be copied, modified, or 6 | // distributed except according to those terms. 7 | 8 | use proconio::{input_interactive, is_stdin_empty}; 9 | 10 | fn test_stdin() { 11 | assert!(!is_stdin_empty()); 12 | input_interactive! { 13 | n: usize, 14 | } 15 | assert!(!is_stdin_empty()); 16 | println!("{n}"); 17 | 18 | for c in 0..n { 19 | println!("start {c}"); 20 | assert!(!is_stdin_empty()); 21 | input_interactive! { 22 | i: isize, 23 | j: isize, 24 | } 25 | 26 | println!("{i} {j}"); 27 | } 28 | assert!(is_stdin_empty()); 29 | } 30 | 31 | fn test_for(input: &str, expected_stdout: &str) { 32 | use assert_cli::Assert; 33 | use std::env::args; 34 | Assert::command(&[&*args().next().unwrap(), "foo"]) 35 | .stdin(input) 36 | .stdout() 37 | .is(expected_stdout) 38 | .and() 39 | .stderr() 40 | .is("") 41 | .unwrap(); 42 | } 43 | 44 | fn main() { 45 | use std::env::args; 46 | if args().len() == 1 { 47 | test_for( 48 | "3\n1 2\n3 4\n5 6\n", 49 | "3\nstart 0\n1 2\nstart 1\n3 4\nstart 2\n5 6\n", 50 | ); 51 | return; 52 | } 53 | 54 | test_stdin(); 55 | } 56 | -------------------------------------------------------------------------------- /proconio/tests/issue_14.rs: -------------------------------------------------------------------------------- 1 | // The test target source is at issue_14_target.rs 2 | 3 | use proconio::fastout; 4 | 5 | #[fastout] 6 | #[rustversion::attr(since(1.43.0), allow(clippy::match_single_binding))] 7 | fn test_issue_14() { 8 | println!("-1"); 9 | match 0 { 10 | _ => println!("1"), 11 | } 12 | } 13 | 14 | fn main() { 15 | use assert_cli::Assert; 16 | use std::env::args; 17 | 18 | // relaunch the app to capture standard output 19 | if args().len() == 1 { 20 | Assert::command(&[&*args().next().unwrap(), "foo"]) 21 | .stdout() 22 | .is("-1\n1\n") 23 | .and() 24 | .stderr() 25 | .is("") 26 | .unwrap(); 27 | return; 28 | } 29 | 30 | test_issue_14(); 31 | } 32 | -------------------------------------------------------------------------------- /proconio/tests/read_value.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2019 statiolake 2 | // 3 | // Licensed under the Apache License, Version 2.0 or the MIT license , at your option. This file may not be copied, modified, or 6 | // distributed except according to those terms. 7 | 8 | use proconio::read_value; 9 | 10 | fn test_stdin() { 11 | let mut sum = 0; 12 | for _ in 0..read_value!(usize) { 13 | sum += read_value!(u32); 14 | } 15 | println!("{sum}"); 16 | } 17 | 18 | fn test_for(input: &str, expected_stdout: &str) { 19 | use assert_cli::Assert; 20 | use std::env::args; 21 | Assert::command(&[&*args().next().unwrap(), "foo"]) 22 | .stdin(input) 23 | .stdout() 24 | .is(expected_stdout) 25 | .and() 26 | .stderr() 27 | .is("") 28 | .unwrap(); 29 | } 30 | 31 | fn main() { 32 | use std::env::args; 33 | if args().len() == 1 { 34 | test_for("2 3 7\n", "10\n"); 35 | return; 36 | } 37 | 38 | test_stdin(); 39 | } 40 | -------------------------------------------------------------------------------- /proconio/tests/stdin.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2019 statiolake 2 | // 3 | // Licensed under the Apache License, Version 2.0 or the MIT license , at your option. This file may not be copied, modified, or 6 | // distributed except according to those terms. 7 | 8 | use proconio::{input, is_stdin_empty}; 9 | 10 | fn test_stdin() { 11 | assert!(!is_stdin_empty()); 12 | input! { 13 | n: usize, 14 | } 15 | assert!(!is_stdin_empty()); 16 | println!("{n}"); 17 | 18 | for c in 0..n { 19 | println!("start {c}"); 20 | assert!(!is_stdin_empty()); 21 | input! { 22 | i: isize, 23 | j: isize, 24 | } 25 | 26 | println!("{i} {j}"); 27 | } 28 | assert!(is_stdin_empty()); 29 | } 30 | 31 | fn test_for(input: &str, expected_stdout: &str) { 32 | use assert_cli::Assert; 33 | use std::env::args; 34 | Assert::command(&[&*args().next().unwrap(), "foo"]) 35 | .stdin(input) 36 | .stdout() 37 | .is(expected_stdout) 38 | .and() 39 | .stderr() 40 | .is("") 41 | .unwrap(); 42 | } 43 | 44 | fn main() { 45 | use std::env::args; 46 | if args().len() == 1 { 47 | test_for( 48 | "3\n1 2\n3 4\n5 6\n", 49 | "3\nstart 0\n1 2\nstart 1\n3 4\nstart 2\n5 6\n", 50 | ); 51 | return; 52 | } 53 | 54 | test_stdin(); 55 | } 56 | -------------------------------------------------------------------------------- /proconio/tests/ui.rs: -------------------------------------------------------------------------------- 1 | #[rustversion::stable(1.42.0)] 2 | #[test] 3 | fn ui() { 4 | trybuild::TestCases::new().compile_fail("./tests/ui/**/*.rs"); 5 | } 6 | -------------------------------------------------------------------------------- /proconio/tests/ui/fastout/argument-never-used.rs: -------------------------------------------------------------------------------- 1 | use proconio::fastout; 2 | 3 | #[fastout] 4 | fn main() { 5 | println!("", 42); 6 | } 7 | -------------------------------------------------------------------------------- /proconio/tests/ui/fastout/argument-never-used.stderr: -------------------------------------------------------------------------------- 1 | error: argument never used 2 | --> $DIR/argument-never-used.rs:5:18 3 | | 4 | 5 | println!("", 42); 5 | | -- ^^ argument never used 6 | | | 7 | | formatting specifier missing 8 | -------------------------------------------------------------------------------- /proconio/tests/ui/fastout/format-argument-must-be-a-string-literal.rs: -------------------------------------------------------------------------------- 1 | use proconio::fastout; 2 | 3 | #[fastout] 4 | fn main() { 5 | println!(42); 6 | 7 | let x = 42; 8 | println!(x); 9 | } 10 | -------------------------------------------------------------------------------- /proconio/tests/ui/fastout/format-argument-must-be-a-string-literal.stderr: -------------------------------------------------------------------------------- 1 | error: format argument must be a string literal 2 | --> $DIR/format-argument-must-be-a-string-literal.rs:5:14 3 | | 4 | 5 | println!(42); 5 | | ^^ 6 | | 7 | help: you might be missing a string literal to format with 8 | | 9 | 5 | println!("{}", 42); 10 | | ^^^^^ 11 | 12 | error: format argument must be a string literal 13 | --> $DIR/format-argument-must-be-a-string-literal.rs:8:14 14 | | 15 | 8 | println!(x); 16 | | ^ 17 | | 18 | help: you might be missing a string literal to format with 19 | | 20 | 8 | println!("{}", x); 21 | | ^^^^^ 22 | -------------------------------------------------------------------------------- /proconio/tests/ui/fastout/print-macros-in-closures.rs: -------------------------------------------------------------------------------- 1 | use proconio::fastout; 2 | 3 | #[fastout] 4 | fn main() { 5 | let _ = || println!("Hi"); 6 | } 7 | -------------------------------------------------------------------------------- /proconio/tests/ui/fastout/print-macros-in-closures.stderr: -------------------------------------------------------------------------------- 1 | error: Closures in a #[fastout] function cannot contain `print!` or `println!` macro 2 | 3 | note: If you want to run your entire logic in a thread having extended size of stack, you can define a new function instead. See documentation (https://docs.rs/proconio/#closures-having-print-or-println-in-fastout-function) for more details. 4 | 5 | note: This is because if you use this closure with `std::thread::spawn()` or any other functions requiring `Send` for an argument closure, the compiler emits an error about thread unsafety for our internal implementations. If you are using the closure just in a single thread, it's actually no problem, but we cannot check the trait bounds at the macro-expansion time. So for now, all closures having `print!` or `println!` is prohibited regardless of the `Send` requirements. 6 | --> $DIR/print-macros-in-closures.rs:5:16 7 | | 8 | 5 | let _ = || println!("Hi"); 9 | | ^^^^^^^ 10 | -------------------------------------------------------------------------------- /proconio/tests/ui/fastout/requires-at-least-a-format-string-argument.rs: -------------------------------------------------------------------------------- 1 | use proconio::fastout; 2 | 3 | #[fastout] 4 | fn main() { 5 | print!(); 6 | } 7 | -------------------------------------------------------------------------------- /proconio/tests/ui/fastout/requires-at-least-a-format-string-argument.stderr: -------------------------------------------------------------------------------- 1 | error: requires at least a format string argument 2 | --> $DIR/requires-at-least-a-format-string-argument.rs:5:5 3 | | 4 | 5 | print!(); 5 | | ^^^^^^^^^ in this macro invocation 6 | | 7 | = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info) 8 | --------------------------------------------------------------------------------