├── .github ├── dependabot.yml └── workflows │ └── rust.yml ├── .gitignore ├── Cargo.toml ├── LICENSE-APACHAE ├── LICENSE-MIT ├── README.md ├── src ├── any_array.rs ├── fold.rs ├── foreach.rs ├── lib.rs ├── macros.rs ├── ops.rs ├── predicate.rs ├── search.rs ├── tuple.rs ├── tupleize.rs ├── uninit.rs └── unwrap.rs └── tuplez-macros ├── .gitignore ├── Cargo.toml └── src ├── lib.rs └── parser.rs /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | # To get started with Dependabot version updates, you'll need to specify which 2 | # package ecosystems to update and where the package manifests are located. 3 | # Please see the documentation for all configuration options: 4 | # https://docs.github.com/code-security/dependabot/dependabot-version-updates/configuration-options-for-the-dependabot.yml-file 5 | 6 | version: 2 7 | updates: 8 | - package-ecosystem: "cargo" # See documentation for possible values 9 | directory: "/" # Location of package manifests 10 | schedule: 11 | interval: "weekly" 12 | -------------------------------------------------------------------------------- /.github/workflows/rust.yml: -------------------------------------------------------------------------------- 1 | name: Rust 2 | 3 | on: 4 | push: 5 | branches: [ "master" ] 6 | pull_request: 7 | branches: [ "master" ] 8 | 9 | env: 10 | CARGO_TERM_COLOR: always 11 | 12 | jobs: 13 | build: 14 | 15 | runs-on: ubuntu-latest 16 | 17 | steps: 18 | - uses: actions/checkout@v3 19 | - name: Install nightly 20 | run: rustup default nightly 21 | - name: Install miri 22 | run: rustup component add miri 23 | - name: Build 24 | run: cargo build --verbose 25 | - name: Run tests 26 | run: cargo test 27 | - name: Run tests no features 28 | run: cargo test --no-default-features 29 | - name: Run tests all features 30 | run: cargo miri test --all-features 31 | - name: Run tests on no-std 32 | run: | 33 | cargo test --no-default-features --features="full-no-std" 34 | rustup target add thumbv6m-none-eabi 35 | cargo build --target=thumbv6m-none-eabi --no-default-features --features="full-no-std" 36 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | Cargo.lock 3 | .vscode/ -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [workspace] 2 | members = ["tuplez-macros"] 3 | resolver = "2" 4 | 5 | [workspace.package] 6 | authors = ["Nichts Hsu "] 7 | license = "MIT OR Apache-2.0" 8 | readme = "README.md" 9 | edition = "2021" 10 | documentation = "https://docs.rs/tuplez" 11 | repository = "https://github.com/NichtsHsu/tuplez" 12 | keywords = ["tuple", "no-std"] 13 | 14 | [package] 15 | name = "tuplez" 16 | version = "0.14.16" 17 | description = "Tuples represented in recursive form" 18 | authors.workspace = true 19 | license.workspace = true 20 | readme.workspace = true 21 | edition.workspace = true 22 | documentation.workspace = true 23 | repository.workspace = true 24 | keywords.workspace = true 25 | categories = ["data-structures", "no-std", "no-std::no-alloc"] 26 | 27 | [features] 28 | default = ["std", "unwrap"] 29 | full-no-std = ["serde", "uninit", "unwrap"] 30 | full = ["std", "full-no-std"] 31 | full-nightly = ["full", "any_array"] 32 | any_array = [] 33 | std = ["serde?/std"] 34 | alloc = ["serde?/alloc"] 35 | uninit = [] 36 | unwrap = [] 37 | 38 | [dependencies] 39 | tuplez-macros = { path = "tuplez-macros", version = "0.7.0" } 40 | 41 | [dependencies.serde] 42 | version = "1.0" 43 | default-features = false 44 | features = ["derive"] 45 | optional = true 46 | 47 | [package.metadata.docs.rs] 48 | features = ["full"] 49 | -------------------------------------------------------------------------------- /LICENSE-APACHAE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /LICENSE-MIT: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2024 Nichts Hsu 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # tuplez 2 | 3 | This crate introduces a tuple type represented in recursive form rather than parallel form. 4 | 5 | ## Motivation 6 | 7 | The [primitive tuple types](https://doc.rust-lang.org/std/primitive.tuple.html) are represented in parallel form, like: 8 | 9 | ```text 10 | (a, b, c, d ...) 11 | ``` 12 | 13 | Since Rust doesn't support variadic generics, we cannot add methods to primitive tuples with any number of elements. 14 | 15 | Currently, most tuple crates use declarative macros to implement methods for tuples whose number of elements is less than 16 | a certain limit (usually 32). 17 | 18 | To solve this, tuplez introduces a `Tuple` type represented in recursive form, like: 19 | 20 | ```text 21 | Tuple(a, Tuple(b, Tuple(c, Tuple(d, ...)))) 22 | ``` 23 | 24 | The advantage of this representation is that you can implement methods recursively for all tuples, 25 | and there is no longer a limit on the number of tuple's elements. And, in almost all cases, the `Tuple` takes no more memory than 26 | the primitive tuples. 27 | 28 | ## Functionality 29 | 30 | * Create tuples with any number of elements. 31 | * Access elements in a tuple at any index, or by their types. 32 | * Push element to a tuple or pop element from a tuple. 33 | * Join two tuples or split a tuple into two parts. 34 | * Rich tuple operations, e.g.: reverse, left rotate, zip. 35 | * Get subsequences. 36 | * If all element types implement a `Trait` (e.g. `Eq`, `Add`), then the `Tuple` also implement that `Trait`. 37 | * Traverse all elements of a tuple, or fold a tuple. 38 | * When the number of elements of a tuple doesn't exceed 32, then it can be converted from/to a primitive tuple or a primitive array. 39 | 40 | Please check the [documentation](https://docs.rs/tuplez) for details. 41 | -------------------------------------------------------------------------------- /src/any_array.rs: -------------------------------------------------------------------------------- 1 | use crate::{ToArray, Tuple, TupleLike, Unit}; 2 | use std::mem::MaybeUninit; 3 | 4 | trait FillSlice: TupleLike { 5 | fn fill_slice(self, arr: &mut [MaybeUninit], index: usize); 6 | } 7 | 8 | impl FillSlice for Unit { 9 | fn fill_slice(self, _: &mut [MaybeUninit], _: usize) {} 10 | } 11 | 12 | impl FillSlice for Tuple 13 | where 14 | Other: FillSlice, 15 | { 16 | fn fill_slice(self, arr: &mut [MaybeUninit], index: usize) { 17 | let Tuple(first, other) = self; 18 | arr[index].write(first); 19 | other.fill_slice(arr, index + 1); 20 | } 21 | } 22 | 23 | impl ToArray for Unit { 24 | type Array = [T; 0]; 25 | type Iter<'a> = std::array::IntoIter<&'a T, 0> where Self: 'a, T: 'a; 26 | type IterMut<'a> = std::array::IntoIter<&'a mut T, 0> where Self: 'a, T: 'a; 27 | 28 | fn to_array(self) -> Self::Array { 29 | Default::default() 30 | } 31 | 32 | fn iter<'a>(&'a self) -> Self::Iter<'a> 33 | where 34 | Self: 'a, 35 | T: 'a, 36 | { 37 | self.as_ref().to_array().into_iter() 38 | } 39 | 40 | fn iter_mut<'a>(&'a mut self) -> Self::IterMut<'a> 41 | where 42 | Self: 'a, 43 | T: 'a, 44 | { 45 | self.as_mut().to_array().into_iter() 46 | } 47 | } 48 | 49 | impl ToArray for Tuple 50 | where 51 | Self: FillSlice, 52 | [First; Self::LEN]:, 53 | { 54 | type Array = [First; Self::LEN]; 55 | 56 | type Iter<'a> = << as TupleLike>::AsRefOutput<'a> as 57 | ToArray<&'a First>>::Array as IntoIterator>::IntoIter 58 | where 59 | Self::AsRefOutput<'a>: ToArray<&'a First>, 60 | Self: 'a, 61 | First: 'a; 62 | 63 | type IterMut<'a> = << as TupleLike>::AsMutOutput<'a> as 64 | ToArray<&'a mut First>>::Array as IntoIterator>::IntoIter 65 | where 66 | Self::AsMutOutput<'a>: ToArray<&'a mut First>, 67 | Self: 'a, 68 | First: 'a; 69 | 70 | fn to_array(self) -> Self::Array { 71 | let mut arr: [MaybeUninit; Self::LEN] = MaybeUninit::uninit_array(); 72 | self.fill_slice(&mut arr, 0); 73 | unsafe { MaybeUninit::array_assume_init(arr) } 74 | } 75 | 76 | fn iter<'a>(&'a self) -> Self::Iter<'a> 77 | where 78 | Self::AsRefOutput<'a>: ToArray<&'a First>, 79 | Self: 'a, 80 | First: 'a, 81 | { 82 | self.as_ref().to_array().into_iter() 83 | } 84 | 85 | fn iter_mut<'a>(&'a mut self) -> Self::IterMut<'a> 86 | where 87 | Self::AsMutOutput<'a>: ToArray<&'a mut First>, 88 | Self: 'a, 89 | First: 'a, 90 | { 91 | self.as_mut().to_array().into_iter() 92 | } 93 | } 94 | 95 | trait FromSlice: TupleLike { 96 | fn from_slice(arr: &mut [MaybeUninit], index: usize) -> Self; 97 | } 98 | 99 | impl FromSlice for Unit { 100 | fn from_slice(_: &mut [MaybeUninit], _: usize) -> Self { 101 | Unit 102 | } 103 | } 104 | 105 | impl FromSlice for Tuple 106 | where 107 | Other: FromSlice, 108 | { 109 | fn from_slice(arr: &mut [MaybeUninit], index: usize) -> Self { 110 | let v = std::mem::replace(&mut arr[index], MaybeUninit::uninit()); 111 | Tuple( 112 | unsafe { v.assume_init() }, 113 | Other::from_slice(arr, index + 1), 114 | ) 115 | } 116 | } 117 | 118 | impl From<[T; 0]> for Unit { 119 | fn from(_: [T; 0]) -> Self { 120 | Unit 121 | } 122 | } 123 | 124 | impl From<[First; Self::LEN]> for Tuple 125 | where 126 | Self: FromSlice, 127 | { 128 | fn from(value: [First; Self::LEN]) -> Self { 129 | let mut arr = MaybeUninit::new(value).transpose(); 130 | Self::from_slice(&mut arr, 0) 131 | } 132 | } 133 | -------------------------------------------------------------------------------- /src/fold.rs: -------------------------------------------------------------------------------- 1 | //! Provides the ability to fold tuples. 2 | //! 3 | //! The documentation page of [`Folder`] has many examples available. 4 | 5 | use crate::{Tuple, TupleLike, Unit}; 6 | 7 | /// Define folders that fold an element of the tuple and specify another folder to be used to 8 | /// fold the next element of the tuple. 9 | /// 10 | /// To fold a tuple with type [`Tuple`](crate::Tuple), you need to construct a custom folder type, 11 | /// which implements [`Folder`], and its [`NextFolder`](Folder::NextFolder) 12 | /// implements [`Folder>::Output>`](Folder), and so on. 13 | /// Pass your folder to tuple's [`fold()`](TupleLike::fold()) method, then the tuple will call 14 | /// folder's [`fold()`](Folder::fold()) method and move its first element in, and then the tuple 15 | /// move its second element in its [`NextFolder`](Folder::NextFolder)'s [`fold()`](Folder::fold()) method, 16 | /// and so on. 17 | /// 18 | /// NOTE: Folding a tuple will consume it. If this is not what you want, call [`as_ref()`](TupleLike::as_ref()) 19 | /// or [`as_mut()`](TupleLike::as_mut()) to create a new tuple that references its all members before folding. 20 | /// 21 | /// # Quickly build a folder by macros 22 | /// 23 | /// Here are two ways you can quickly build a folder. 24 | /// 25 | /// ## Fold tuples by element types 26 | /// 27 | /// The [`folder!`](crate::folder!) macro helps you build a folder that folds tuples according to their element types. 28 | /// 29 | /// For example: 30 | /// 31 | /// ``` 32 | /// use tuplez::{folder, tuple, TupleLike}; 33 | /// 34 | /// let tup = tuple!(Some(1), "2", Some(3.0)); 35 | /// let result = tup.fold( 36 | /// folder! { String; // Type of `acc` of all closures must be the same and annotated at the front 37 | /// |acc, x: &str| { acc + &x.to_string() } 38 | /// |acc, x: Option| { acc + &x.unwrap().to_string() } 39 | /// }, 40 | /// String::new(), 41 | /// ); 42 | /// assert_eq!(result, "123".to_string()); 43 | /// ``` 44 | /// 45 | /// ## Fold tuples in order of their elements 46 | /// 47 | /// You can create a new tuple with the same number of elements, whose elements are all callable objects that accepts the accumulation value 48 | /// and an element and returns new accumulation value ([`FnOnce(Acc, T) -> Acc`](std::ops::FnOnce)), then, you can use that tuple as a folder. 49 | /// 50 | /// For example: 51 | /// 52 | /// ``` 53 | /// use tuplez::{tuple, TupleLike}; 54 | /// 55 | /// let tup = tuple!(1, "2", 3.0); 56 | /// let result = tup.fold( 57 | /// tuple!( 58 | /// |acc, x| (acc + x) as f64, 59 | /// |acc: f64, x: &str| acc.to_string() + x, 60 | /// |acc: String, x| acc.parse::().unwrap() + x as i32, 61 | /// ), // Type of `acc` of each closure is the return type of the previous closure. 62 | /// 0, 63 | /// ); 64 | /// assert_eq!(result, 15); 65 | /// ``` 66 | /// 67 | /// # Custom folder 68 | /// 69 | /// If you are not satisfied with the above three methods, you can customize a folder. 70 | /// 71 | /// Here is an example, very simple but sufficient to show how to use: 72 | /// 73 | /// ``` 74 | /// use std::collections::VecDeque; 75 | /// use tuplez::{fold::Folder, tuple, TupleLike}; 76 | /// 77 | /// struct MyFolder(VecDeque); 78 | /// 79 | /// impl Folder for MyFolder { 80 | /// type Output = String; 81 | /// type NextFolder = Self; 82 | /// 83 | /// fn fold(mut self, acc: String, value: T) -> (Self::Output, Self::NextFolder) { 84 | /// ( 85 | /// if self.0.len() == 1 { 86 | /// acc + &format!("{}[{}]", value, self.0.pop_front().unwrap()) 87 | /// } else { 88 | /// acc + &format!("{}[{}],", value, self.0.pop_front().unwrap()) 89 | /// }, 90 | /// self, 91 | /// ) 92 | /// } 93 | /// } 94 | /// 95 | /// let tup = tuple!(3.14, "hello", 25); 96 | /// let result = tup.fold(MyFolder(VecDeque::from(vec![1, 2, 3])), String::new()); 97 | /// assert_eq!(result, "3.14[1],hello[2],25[3]"); 98 | /// ``` 99 | pub trait Folder { 100 | /// Output type of folding. 101 | type Output; 102 | 103 | /// Type of next folder to be use. 104 | type NextFolder; 105 | 106 | /// Fold a value, return the output value and next folder. 107 | fn fold(self, acc: Acc, value: T) -> (Self::Output, Self::NextFolder); 108 | } 109 | 110 | /// Fold the tuple. 111 | /// 112 | /// # The folder `F` 113 | /// 114 | /// For folding [`Tuple`](crate::Tuple), you need to build a folder, 115 | /// which needs to implement [`Folder`], and the [`NextFolder`](Folder::NextFolder) 116 | /// needs to implement [`Folder>::Output>`](Folder), and so on. 117 | /// 118 | /// See the documentation page of [`Folder`] for details. 119 | pub trait Foldable: TupleLike { 120 | /// The type of the output generated by folding the tuple. 121 | type Output; 122 | 123 | /// Fold the tuple. 124 | /// 125 | /// Check out [`Folder`]'s documentation page to learn how to build 126 | /// a folder that can be passed to [`fold()`](Foldable::fold()). 127 | /// 128 | /// NOTE: Fold a tuple will consume it. If this is not what you want, call [`as_ref()`](TupleLike::as_ref()) 129 | /// or [`as_mut()`](TupleLike::as_mut()) to create a new tuple that references its all members before folding. 130 | /// 131 | /// Hint: The [`TupleLike`] trait provides the [`fold()`](TupleLike::fold()) method as the wrapper 132 | /// for this [`fold()`](Foldable::fold()) method. 133 | /// 134 | /// # Example 135 | /// 136 | /// ``` 137 | /// use tuplez::{folder, tuple, TupleLike}; 138 | /// 139 | /// let tup = tuple!(Some(1), "2", Some(3.0)); 140 | /// let result = tup.fold( 141 | /// folder! { String; // Type of `acc` of all closures must be the same and annotated at the front 142 | /// |acc, x: &str| { acc + &x.to_string() } 143 | /// |acc, x: Option| { acc + &x.unwrap().to_string() } 144 | /// }, 145 | /// String::new(), 146 | /// ); 147 | /// assert_eq!(result, "123".to_string()); 148 | /// ``` 149 | fn fold(self, f: F, acc: Acc) -> Self::Output; 150 | } 151 | 152 | impl Folder for Tuple 153 | where 154 | F: FnOnce(Acc, First) -> Out, 155 | { 156 | type Output = Out; 157 | type NextFolder = FOthers; 158 | 159 | fn fold(self, acc: Acc, value: First) -> (Self::Output, Self::NextFolder) { 160 | ((self.0)(acc, value), self.1) 161 | } 162 | } 163 | 164 | impl Foldable for Unit { 165 | type Output = Acc; 166 | fn fold(self, _: F, acc: Acc) -> Self::Output { 167 | acc 168 | } 169 | } 170 | 171 | impl Foldable for Tuple 172 | where 173 | F: Folder, 174 | Other: Foldable, 175 | { 176 | type Output = >::Output; 177 | fn fold(self, f: F, acc: Acc) -> Self::Output { 178 | let (acc, f) = f.fold(acc, self.0); 179 | Foldable::::fold(self.1, f, acc) 180 | } 181 | } 182 | -------------------------------------------------------------------------------- /src/foreach.rs: -------------------------------------------------------------------------------- 1 | //! Provides the ability to traverse tuples. 2 | //! 3 | //! Check the documentation page of [`Mapper`] for details. 4 | use crate::{Tuple, TupleLike, Unit}; 5 | 6 | /// Define mappers for traversing the tuple. 7 | /// 8 | /// To traverse a tuple with type [`Tuple`](crate::Tuple), you need to construct a custom mapper type, 9 | /// which implements [`Mapper`], [`Mapper`] ... [`Mapper`]. 10 | /// Pass your mapper to tuple's [`foreach()`](TupleLike::foreach()) method, then the tuple will call 11 | /// mapper's [`map()`](Mapper::map()) method in order of its elements and move the elements in. 12 | /// 13 | /// NOTE: Traversing a tuple will consume it. If this is not what you want, call [`as_ref()`](TupleLike::as_ref()) 14 | /// or [`as_mut()`](TupleLike::as_mut()) to create a new tuple that references its all members before traversing. 15 | /// 16 | /// Tip: [`Mapper`] map elements by their types. If you are looking for a way to map elements by their order, 17 | /// then what you are looking for is to 18 | /// [pass a tuple containing callable objects into `fold()` method](Tuple#fold-tuples-in-order-of-their-elements-but-collecting-results-in-a-tuple). 19 | /// 20 | /// # Quickly build a mapper by macros 21 | /// 22 | /// Here are two ways you can quickly build a folder. 23 | /// 24 | /// ## Traverse tuples by element types 25 | /// 26 | /// The [`mapper!`](crate::mapper!) macro helps you build a mapper that traverses tuples according to their element types. 27 | /// 28 | /// For example: 29 | /// 30 | /// ``` 31 | /// use tuplez::{mapper, tuple, TupleLike}; 32 | /// 33 | /// let tup = tuple!(1, "hello", 3.14).foreach(mapper! { 34 | /// |x: i32| -> i64 { x as i64 } 35 | /// |x: f32| -> String { x.to_string() } 36 | /// <'a> |x: &'a str| -> &'a [u8] { x.as_bytes() } 37 | /// }); 38 | /// assert_eq!(tup, tuple!(1i64, b"hello" as &[u8], "3.14".to_string())); 39 | /// ``` 40 | /// 41 | /// ## Traverse tuples in order of their elements 42 | /// 43 | /// You can create a new tuple with the same number of elements, whose elements are all callable objects that accepts an element 44 | /// and returns another value ([`FnOnce(T) -> U`](std::ops::FnOnce)), then, you can use that tuple as a mapper. 45 | /// 46 | /// ``` 47 | /// use tuplez::{tuple, TupleLike}; 48 | /// 49 | /// let tup = tuple!(1, 2, 3); 50 | /// let result = tup.foreach( 51 | /// tuple!( 52 | /// |x| x as f32, 53 | /// |x: i32| x.to_string(), 54 | /// |x: i32| Some(x), 55 | /// ) 56 | /// ); 57 | /// assert_eq!(result, tuple!(1.0, "2".to_string(), Some(3))); 58 | /// ``` 59 | /// 60 | /// # Custom mapper 61 | /// 62 | /// For more complex cases that cannot be covered by the [`mapper!`](crate::mapper!) macro, 63 | /// for example, you want to save some results into context variables, 64 | /// you need to implement [`Mapper`] for your mapper for all element type `Ti`s in tuples. 65 | /// Generic can be used. 66 | /// 67 | /// For example: 68 | /// 69 | /// ``` 70 | /// use tuplez::{foreach::Mapper, tuple, TupleLike}; 71 | /// 72 | /// struct MyElement(i32); 73 | /// 74 | /// struct Collector<'a>(&'a mut Vec); 75 | /// 76 | /// impl Mapper<&T> for Collector<'_> { 77 | /// type Output = (); 78 | /// type NextMapper = Self; 79 | /// fn map(self, value: &T) -> (Self::Output, Self::NextMapper) { 80 | /// ( 81 | /// self.0.push(format!( 82 | /// "{} : {}", 83 | /// std::any::type_name::(), 84 | /// value.to_string() 85 | /// )), 86 | /// self, 87 | /// ) 88 | /// } 89 | /// } 90 | /// 91 | /// impl Mapper<&MyElement> for Collector<'_> { 92 | /// type Output = (); 93 | /// type NextMapper = Self; 94 | /// fn map(self, value: &MyElement) -> (Self::Output, Self::NextMapper) { 95 | /// (self.0.push(format!("MyElement : {}", value.0)), self) 96 | /// } 97 | /// } 98 | /// 99 | /// let mut buffers = vec![]; 100 | /// let collector = Collector(&mut buffers); 101 | /// tuple!(1, "hello", MyElement(14)) 102 | /// .as_ref() 103 | /// .foreach(collector); 104 | /// assert_eq!( 105 | /// buffers, 106 | /// vec![ 107 | /// "i32 : 1".to_string(), 108 | /// "&str : hello".to_string(), 109 | /// "MyElement : 14".to_string() 110 | /// ] 111 | /// ); 112 | /// ``` 113 | pub trait Mapper { 114 | /// Output type of mapping. 115 | type Output; 116 | 117 | /// Type of next mapper to be use. 118 | type NextMapper; 119 | 120 | /// Map an element to another value. 121 | fn map(self, value: T) -> (Self::Output, Self::NextMapper); 122 | } 123 | 124 | /// Traverse the tuple. 125 | /// 126 | /// # The mapper `F` 127 | /// 128 | /// For traversing [`Tuple`](crate::Tuple), you need to build a mapper, 129 | /// which needs to implement [`Mapper`], [`Mapper`] ... [`Mapper`]. 130 | /// 131 | /// See the documentation page of [`Mapper`] for details. 132 | pub trait Foreach: TupleLike { 133 | /// The type of tuple generated by traversing the tuple. 134 | type Output: TupleLike; 135 | 136 | /// Traverse the tuple, and collect the output of traversal into a new tuple. 137 | /// 138 | /// NOTE: Traversing a tuple will consume it. If this is not what you want, call [`as_ref()`](TupleLike::as_ref()) 139 | /// or [`as_mut()`](TupleLike::as_mut()) to create a new tuple that references its all members before traversing. 140 | /// 141 | /// Hint: The [`TupleLike`] trait provides the [`foreach()`](TupleLike::foreach()) method as the wrapper 142 | /// for this [`foreach()`](Foreach::foreach()) method. 143 | /// 144 | /// # Example 145 | /// 146 | /// ``` 147 | /// use tuplez::{mapper, tuple, TupleLike}; 148 | /// 149 | /// let tup = tuple!(1, "hello", 3.14).foreach(mapper! { 150 | /// |x: i32| -> i64 { x as i64 } 151 | /// |x: f32| -> String { x.to_string() } 152 | /// <'a> |x: &'a str| -> &'a [u8] { x.as_bytes() } 153 | /// }); 154 | /// assert_eq!(tup, tuple!(1i64, b"hello" as &[u8], "3.14".to_string())); 155 | /// ``` 156 | fn foreach(self, f: F) -> Self::Output; 157 | } 158 | 159 | impl Mapper for Tuple 160 | where 161 | F: FnOnce(First) -> Out, 162 | FOthers: TupleLike, 163 | { 164 | type Output = Out; 165 | type NextMapper = FOthers; 166 | 167 | fn map(self, value: First) -> (Self::Output, Self::NextMapper) { 168 | ((self.0)(value), self.1) 169 | } 170 | } 171 | 172 | impl Foreach for Unit { 173 | type Output = Unit; 174 | fn foreach(self, _: F) -> Self::Output { 175 | Unit 176 | } 177 | } 178 | 179 | impl Foreach for Tuple 180 | where 181 | F: Mapper, 182 | Other: Foreach, 183 | { 184 | type Output = Tuple; 185 | fn foreach(self, f: F) -> Self::Output { 186 | let (out, f) = f.map(self.0); 187 | Tuple(out, Foreach::foreach(self.1, f)) 188 | } 189 | } 190 | -------------------------------------------------------------------------------- /src/lib.rs: -------------------------------------------------------------------------------- 1 | #![cfg_attr(feature = "any_array", allow(incomplete_features))] 2 | #![cfg_attr(feature = "any_array", feature(generic_const_exprs))] 3 | #![cfg_attr(feature = "any_array", feature(maybe_uninit_uninit_array))] 4 | #![cfg_attr(feature = "any_array", feature(maybe_uninit_array_assume_init))] 5 | #![cfg_attr(feature = "any_array", feature(maybe_uninit_uninit_array_transpose))] 6 | #![cfg_attr(docsrs, feature(doc_cfg))] 7 | #![deny(missing_docs)] 8 | #![cfg_attr(not(feature = "std"), no_std)] 9 | 10 | //! Tuples represented in recursive form rather than parallel form. 11 | //! 12 | //! # Motivation 13 | //! 14 | //! The [primitive tuple types](https://doc.rust-lang.org/std/primitive.tuple.html) are represented in parallel form, like: 15 | //! 16 | //! ```text 17 | //! (a, b, c, d ...) 18 | //! ``` 19 | //! 20 | //! Since Rust doesn't support variadic generics, we cannot add methods to primitive tuples with any number of elements. 21 | //! 22 | //! Currently, most tuple crates use declarative macros to implement methods for tuples whose number of elements is less than 23 | //! a certain limit (usually 32). 24 | //! 25 | //! To solve this, tuplez introduces a [`Tuple`] type represented in recursive form, like: 26 | //! 27 | //! ```text 28 | //! Tuple(a, Tuple(b, Tuple(c, Tuple(d, ...)))) 29 | //! ``` 30 | //! 31 | //! The advantage of this representation is that 32 | //! [you can implement methods recursively for all tuples](Tuple#trait-implementations-on-tuple), 33 | //! and there is no longer a limit on the number of tuple's elements. And, in almost all cases, 34 | //! the [`Tuple`] takes no more memory than the primitive tuples. 35 | //! 36 | //! # Functionality 37 | //! 38 | //! * [Create tuples](tuple!) with any number of elements. 39 | //! * [Access elements](get!) in a tuple at any index, or by their types. 40 | //! * [Push element](TupleLike::push()) to a tuple or [pop element](TupleLike::pop()) from a tuple. 41 | //! * [Join](TupleLike::join()) two tuples or [split](split_at!) a tuple into two parts. 42 | //! * [Rich tuple operations](TupleLike), e.g.: [reverse](TupleLike::rev()), 43 | //! [left rotate](TupleLike::rot_l()), [zip](TupleLike::zip()). 44 | //! * [Get subsequences](Tuple#get-subsequences). 45 | //! * If all element types implement a `Trait` (e.g. `Eq`, `Add`), then the [`Tuple`] also implement that `Trait`. 46 | //! [See which traits are supported and learn how to implement your custom traits for `Tuple`](Tuple#trait-implementations-on-tuple). 47 | //! * [Traverse all elements](Tuple#traverse-tuples) of a tuple, or [fold](Tuple#fold-tuples) a tuple. 48 | //! * When the number of elements of a tuple doesn't exceed 32, then it can be converted from/to 49 | //! [a primitive tuple](Tuple#convert-fromto-primitive-tuples) 50 | //! or [a primitive array](Tuple#convert-fromto-primitive-arrays). 51 | //! 52 | //! # Optional features 53 | //! 54 | //! * `unwrap` : (*by default*) Allows converting a tuple whose elements are all wrappers 55 | //! into a tuple of the values those wrappers contain. 56 | //! * `uninit`: Add APIs for tuples consisting of [`MaybeUninit`](std::mem::MaybeUninit) elements. 57 | //! * `serde`: Derive `Serialize` and `Deserialize` for tuples. 58 | //! * `std`: (*by default*) Use standard library. It also enables `std` feature of [serde](https://crates.io/crates/serde). 59 | //! * `alloc`: Use standard `alloc` library. It also enables `alloc` feature of [serde](https://crates.io/crates/serde). 60 | //! This feature is usually used when `std` is disabled. 61 | //! * `any_array`: (*nightly*) Use Rust's unstable feature to implement conversion 62 | //! from/to primitive arrays on tuples with any number of elements. 63 | //! This feature requires compiling with rustc released to nightly channel. 64 | //! 65 | //! Bundles: 66 | //! 67 | //! * `default`: Enable default features, which are: `std`, `unwrap`. 68 | //! * `full-no-std`: Enable all features available on stable Rust without `std`, which are: `serde`, `uninit` and `unwrap`. 69 | //! Note that `default-features = false` is necessary. 70 | //! * `full`: Enable all features available on stable Rust, which are: `serde`, `std`, `uninit` and `unwrap`. 71 | //! * `full-nightly`: Enable all features (requires nightly Rust). 72 | //! 73 | //! # Examples 74 | //! 75 | //! ``` 76 | //! # #![cfg_attr(feature = "any_array", feature(generic_const_exprs))] 77 | //! # 78 | //! use tuplez::*; 79 | //! 80 | //! let tup = tuple!(1, "hello".to_string(), 3.14); 81 | //! let tup2 = Tuple::from((2, " world", -3.14)); 82 | //! let tup3 = tup + tup2; 83 | //! assert_eq!(tup3, tuple!(3, "hello world".to_string(), 0.0)); 84 | //! 85 | //! let tup4 = tup3.push(Some([1, 2, 3])); 86 | //! let (tup5, popped) = tup4.pop_front(); 87 | //! assert_eq!( 88 | //! tup5, 89 | //! tuple!("hello world".to_string(), 0.0, Some([1, 2, 3])) 90 | //! ); 91 | //! assert_eq!(popped, 3); 92 | //! 93 | //! let tup6 = tup5.rev(); 94 | //! assert_eq!( 95 | //! tup6, 96 | //! tuple!(Some([1, 2, 3]), 0.0, "hello world".to_string()) 97 | //! ); 98 | //! let tup7 = tup6.rot_l(); 99 | //! assert_eq!( 100 | //! tup7, 101 | //! tuple!(0.0, "hello world".to_string(), Some([1, 2, 3])) 102 | //! ); 103 | //! 104 | //! let tup8 = tup7.foreach(mapper! { 105 | //! |x: f64| -> String { x.to_string() } 106 | //! |x: Option<[i32; 3]>| -> String { format!("{:?}", x.unwrap()) } 107 | //! |x: String| { x } 108 | //! }); 109 | //! let arr = tup8.to_array(); 110 | //! assert_eq!( 111 | //! arr, 112 | //! [ 113 | //! "0".to_string(), 114 | //! "hello world".to_string(), 115 | //! "[1, 2, 3]".to_string() 116 | //! ] 117 | //! ); 118 | //! 119 | //! let tup9 = tuple!(1, "2", 3.0); 120 | //! let result = tup9.fold( 121 | //! tuple!( 122 | //! |acc, x| (acc + x) as f64, 123 | //! |acc: f64, x: &str| acc.to_string() + x, 124 | //! |acc: String, x| acc.parse::().unwrap() + x as i32, 125 | //! ), 126 | //! 0, 127 | //! ); 128 | //! assert_eq!(result, 15); 129 | //! ``` 130 | //! 131 | //! Please check [`Tuple`]'s documentation page for detailed usage. 132 | 133 | extern crate self as tuplez; 134 | 135 | #[cfg(not(feature = "std"))] 136 | extern crate core as std; 137 | 138 | #[cfg(all(not(feature = "std"), feature = "alloc"))] 139 | extern crate alloc; 140 | 141 | pub mod fold; 142 | pub mod foreach; 143 | mod macros; 144 | pub mod ops; 145 | pub mod predicate; 146 | pub mod search; 147 | mod tuple; 148 | mod tupleize; 149 | 150 | #[cfg(feature = "uninit")] 151 | #[cfg_attr(docsrs, doc(cfg(feature = "uninit")))] 152 | pub mod uninit; 153 | 154 | #[cfg(feature = "any_array")] 155 | mod any_array; 156 | 157 | #[cfg(feature = "unwrap")] 158 | #[cfg_attr(docsrs, doc(cfg(feature = "unwrap")))] 159 | pub mod unwrap; 160 | 161 | pub use tuple::*; 162 | 163 | pub use tupleize::Tupleize; 164 | 165 | // Used for re-exporting. 166 | #[doc(hidden)] 167 | pub use tuplez_macros::{ 168 | folder as folder_inner, mapper as mapper_inner, split_at as split_at_inner, take as take_inner, 169 | tuple as tuple_inner, tuple_pat as tuple_pat_inner, tuple_t as tuple_t_inner, 170 | unary_pred as unary_pred_inner, 171 | }; 172 | 173 | /// Get the element at a specific index of the tuple. 174 | /// 175 | /// The [`get_ref()`](TupleLike::get_ref()) and [`get_mut()`](TupleLike::get_mut()) 176 | /// provide another way to get elements by their type. 177 | /// 178 | /// # Syntax 179 | /// 180 | /// `get!(Expr; Index)` 181 | /// 182 | /// **The index must be an integer literal** since procedural macros do not yet support evaluating constants. 183 | /// 184 | /// # Explanation 185 | /// 186 | /// This macro will be expanded to standard member access syntax: 187 | /// 188 | /// ```text 189 | /// get!(tup; 0) => tup.0 190 | /// get!(tup; 1) => tup.1.0 191 | /// get!(tup; 2) => tup.1.1.0 192 | /// ``` 193 | /// 194 | /// Expressions are automatically quoted, so don't worry: 195 | /// 196 | /// ```text 197 | /// get!(tup1 + tup2; 3) => (tup1 + tup2).1.1.1.0 198 | /// ``` 199 | /// 200 | /// You can use `&` and `&mut` directly on the output of [`get!`], like: 201 | /// 202 | /// ``` 203 | /// use tuplez::{get, tuple}; 204 | /// 205 | /// fn add(x: &i32, y: &i32) -> i32 { x + y } 206 | /// 207 | /// fn add_one(x: &mut i32) { *x += 1; } 208 | /// 209 | /// let mut tup = tuple!(1, "hello", 3.14); 210 | /// 211 | /// let x = add(&get!(tup; 0), &2); // Immutably reference the first element of `tup` 212 | /// assert_eq!(tup, tuple!(1, "hello", 3.14)); // Then `tup` remains unchanged 213 | /// assert_eq!(x, 3); 214 | /// 215 | /// add_one(&mut get!(tup; 0)); // Mutably reference the first element of `tup` 216 | /// assert_eq!(tup, tuple!(2, "hello", 3.14)); // Then `tup` changes 217 | /// 218 | /// get!(tup; 1) = "world"; // Direct access the second element of `tup` 219 | /// assert_eq!(tup, tuple!(2, "world", 3.14)); 220 | /// ``` 221 | /// 222 | /// It's not a problem for nested tuples either: 223 | /// 224 | /// ``` 225 | /// use tuplez::{get, tuple}; 226 | /// 227 | /// fn push_world(s: &mut String) { 228 | /// s.push_str(" world"); 229 | /// } 230 | /// 231 | /// let mut tup = tuple!(1, tuple!("hello".to_string(), 3.14)); 232 | /// push_world(&mut get!(get!(tup; 1); 0)); 233 | /// assert_eq!(tup, tuple!(1, tuple!("hello world".to_string(), 3.14))); 234 | /// ``` 235 | pub use tuplez_macros::get; 236 | 237 | /// Pick some elements from a tuple. 238 | /// 239 | /// # Syntax 240 | /// 241 | /// ```text 242 | /// IndicesGroup = Index [ - Index ] 243 | /// 244 | /// pick!(Expr; IndicesGroup1 [, IndicesGroup2, ...] ) 245 | /// ``` 246 | /// 247 | /// *`[` and `]` only indicate the optional content but not that they need to be input.* 248 | /// 249 | /// *Similarly, `...` indicates several repeated segments, rather than inputting `...`.* 250 | /// 251 | /// **The index must be an integer literal** since procedural macros do not yet support evaluating constants. 252 | /// 253 | /// # Explanation 254 | /// 255 | /// The `pick!` macro allows you to pick some elements you want from a tuple to a new tuple, 256 | /// and the unpicked elements will be put into a new tuple. 257 | /// 258 | /// ``` 259 | /// use tuplez::{pick, tuple}; 260 | /// 261 | /// let tup = tuple!(1, "hello", 3.14, [1, 2, 3], Some(9.8), 'c'); 262 | /// let (picked, unpicked) = pick!(tup; 3, 1, 5); 263 | /// assert_eq!(picked, tuple!([1, 2, 3], "hello", 'c')); 264 | /// assert_eq!(unpicked, tuple!(1, 3.14, Some(9.8))); 265 | /// ``` 266 | /// 267 | /// You can abbreviate the continuous part as `start - end`: 268 | /// 269 | /// ``` 270 | /// use tuplez::{pick, tuple}; 271 | /// 272 | /// let tup = tuple!(1, "hello", 3.14, [1, 2, 3], Some(9.8), 'c'); 273 | /// let (picked, unpicked) = pick!(tup; 4, 1-3); 274 | /// assert_eq!(picked, tuple!(Some(9.8), "hello", 3.14, [1, 2, 3])); 275 | /// assert_eq!(unpicked, tuple!(1, 'c')); 276 | /// ``` 277 | /// 278 | /// Of course, reverse ranges are also supported: 279 | /// 280 | /// ``` 281 | /// use tuplez::{pick, tuple}; 282 | /// 283 | /// let tup = tuple!(1, "hello", 3.14, [1, 2, 3], Some(9.8), 'c'); 284 | /// let (picked, unpicked) = pick!(tup; 4, 3-1); // `3-1` is reverse range 285 | /// assert_eq!(picked, tuple!(Some(9.8), [1, 2, 3], 3.14, "hello")); 286 | /// assert_eq!(unpicked, tuple!(1, 'c')); 287 | /// ``` 288 | /// 289 | /// If Rust's move checker allows it, then you can pick the same element multiple times: 290 | /// 291 | /// ``` 292 | /// use tuplez::{pick, tuple}; 293 | /// 294 | /// let tup = tuple!(1, "hello", 3.14, [1, 2, 3], Some(9.8), 'c'); 295 | /// let (picked, unpicked) = pick!(tup; 1, 1, 1, 5, 5); 296 | /// assert_eq!(picked, tuple!("hello", "hello", "hello", 'c', 'c')); 297 | /// assert_eq!(unpicked, tuple!(1, 3.14, [1, 2, 3], Some(9.8))); 298 | /// ``` 299 | /// 300 | /// Another common use is when you want to pick references to some elements of the original tuple: 301 | /// 302 | /// ``` 303 | /// use tuplez::{get, pick, tuple, TupleLike}; 304 | /// 305 | /// let mut tup = tuple!(1, "hello", 3.14, [1, 2, 3], Some(9.8), 'c'); 306 | /// let (picked, _) = pick!(tup.as_mut(); 3, 0); 307 | /// get!(picked; 0).rotate_left(1); 308 | /// *get!(picked; 1) += 100; 309 | /// assert_eq!(tup, tuple!(101, "hello", 3.14, [2, 3, 1], Some(9.8), 'c')); 310 | /// ``` 311 | /// 312 | /// NOTE: Unlike [`take!`], even if you [`pick!`] only one element, you still get a tuple. 313 | pub use tuplez_macros::pick; 314 | 315 | /// Swap two parts of a tuple. 316 | /// 317 | /// # Syntax 318 | /// 319 | /// ```text 320 | /// IndicesGroup = Index [ - Index ] 321 | /// 322 | /// swap_at!(Expr; IndicesGroup1 , IndicesGroup2 ) 323 | /// ``` 324 | /// 325 | /// *`[` and `]` only indicate the optional content but not that they need to be input.* 326 | /// 327 | /// **The index must be an integer literal** since procedural macros do not yet support evaluating constants. 328 | /// 329 | /// # Explanation 330 | /// 331 | /// You can swap two elements of a tuple, then generating a new tuple: 332 | /// 333 | /// ``` 334 | /// use tuplez::{swap_at, tuple}; 335 | /// 336 | /// let tup = tuple!(1, "2", 3.14, [1, 2, 3], Some(9.8), 'c', 14); 337 | /// let tup2 = swap_at!(tup; 0, 4); 338 | /// assert_eq!(tup2, tuple!(Some(9.8), "2", 3.14, [1, 2, 3], 1, 'c', 14)); 339 | /// ``` 340 | /// 341 | /// You can also specify a continuous range of elements via `start - end`, 342 | /// but the number of elements on both sides must be equal: 343 | /// 344 | /// ``` 345 | /// use tuplez::{swap_at, tuple}; 346 | /// 347 | /// let tup = tuple!(1, "2", 3.14, [1, 2, 3], Some(9.8), 'c', 14); 348 | /// let tup2 = swap_at!(tup; 0-2, 3-5); 349 | /// assert_eq!(tup2, tuple!([1, 2, 3], Some(9.8), 'c', 1, "2", 3.14, 14)); 350 | /// ``` 351 | /// 352 | /// Of course, reverse ranges are also supported: 353 | /// 354 | /// ``` 355 | /// use tuplez::{swap_at, tuple}; 356 | /// 357 | /// let tup = tuple!(1, "2", 3.14, [1, 2, 3], Some(9.8), 'c', 14); 358 | /// let tup2 = swap_at!(tup; 0-2, 5-3); 359 | /// assert_eq!(tup2, tuple!('c', Some(9.8), [1, 2, 3], 3.14, "2", 1, 14)); 360 | /// ``` 361 | pub use tuplez_macros::swap_at; 362 | 363 | /// Pass the elements of a tuple as arguments to a function or method. 364 | /// 365 | /// # Syntax 366 | /// 367 | /// ```text 368 | /// ArgsGroup = [ & [mut] ] Index [ - Index ] 369 | /// 370 | /// apply!( Expr => Func ( [ArgsGroup1, ArgsGroup2, ...] ) ) 371 | /// ``` 372 | /// 373 | /// *`[` and `]` only indicate the optional content but not that they need to be input.* 374 | /// 375 | /// *Similarly, `...` indicates several repeated segments, rather than inputting `...`.* 376 | /// 377 | /// **The index must be an integer literal** since procedural macros do not yet support evaluating constants. 378 | /// 379 | /// # Explanation 380 | /// 381 | /// You can pass the elements of the tuple into the function or method in the order you want: 382 | /// 383 | /// ``` 384 | /// use tuplez::{tuple, apply}; 385 | /// 386 | /// fn test(_: i32, _: f64, _: &str) {} 387 | /// 388 | /// let tup = tuple!(3.4, 2, "hello", [1, 2, 3], 8); 389 | /// apply!(tup => test(4, 0, 2)); // Expand to `test(8, 3.4, "hello")` 390 | /// ``` 391 | /// 392 | /// Parts in the same order can be omitted in the form `start - end`: 393 | /// 394 | /// ``` 395 | /// use tuplez::{tuple, apply}; 396 | /// 397 | /// fn test(_: i32, _: f64, _: &str, _: [i32; 3]) {} 398 | /// 399 | /// let tup = tuple!([1, 2, 3], 2, 3.4, "hello", 9); 400 | /// apply!(tup => test(1-3, 0)); // `1-3` expands to `1, 2, 3` 401 | /// ``` 402 | /// 403 | /// And reverse ranges are also supported: 404 | /// 405 | /// ``` 406 | /// use tuplez::{tuple, apply}; 407 | /// 408 | /// fn test(_: &str, _: f64, _: i32, _: [i32; 3]) {} 409 | /// 410 | /// let tup = tuple!([1, 2, 3], 2, 3.4, "hello", 9); 411 | /// apply!(tup => test(3-1, 0)); // `3-1` expands to `3, 2, 1` 412 | /// ``` 413 | /// 414 | /// You can add `&` or `&mut` to elements to borrow them. Here is a slightly more complex example: 415 | /// 416 | /// ``` 417 | /// use tuplez::{tuple, apply}; 418 | /// 419 | /// struct DoIt(T); 420 | /// impl DoIt { 421 | /// fn do_sth(&self, _: String, _: f64, _: &str, _: &mut i32, _: &mut [T; 3], _: &i32) {} 422 | /// } 423 | /// 424 | /// let tup = tuple!( 425 | /// 1, 426 | /// [5, 2, 4], 427 | /// 9.8, 428 | /// "world".to_string(), 429 | /// 3.14, 430 | /// "hello", 431 | /// 7, 432 | /// "zzz" 433 | /// ); 434 | /// apply!(tup => DoIt::(7).do_sth(3-5, &mut 0-1, &6)); 435 | /// ``` 436 | /// 437 | /// NOTE: [`apply!`] consumes the tuple, even if you add `&` or `&mut` to each elements. 438 | /// Sometimes you can avoid this by adding a `&` or `&mut` before the tuple: 439 | /// 440 | /// ``` 441 | /// use tuplez::{tuple, apply}; 442 | /// 443 | /// fn push(v: &mut Vec, x: i32) { 444 | /// v.push(x) 445 | /// } 446 | /// 447 | /// let mut tup = tuple!(vec![1, 2], 3); 448 | /// apply!(&mut tup => push(&mut 0, 1)); 449 | /// assert_eq!(tup, tuple!(vec![1, 2, 3], 3)); 450 | /// ``` 451 | /// 452 | /// It is worth mentioning that the input tuple can be any expression. 453 | /// The `&tup` and the `&mut tup` are just two of the many possible inputs. 454 | /// 455 | /// You can use the same element multiple times as long as Rust's move checker and borrow checker allow it: 456 | /// 457 | /// ``` 458 | /// use tuplez::{tuple, apply}; 459 | /// 460 | /// fn test(_: i32, _: i32, _: i32, _: &i32, _: &i32, _: &mut i32) {} 461 | /// 462 | /// let tup = tuple!(1, 2, 3); 463 | /// apply!(tup => test(0-2, &1-2, &mut 0)); 464 | /// ``` 465 | pub use tuplez_macros::apply; 466 | 467 | /// Derive [`Tupleize`] on struct. 468 | pub use tuplez_macros::Tupleize; 469 | -------------------------------------------------------------------------------- /src/macros.rs: -------------------------------------------------------------------------------- 1 | macro_rules! __tuple_unary_ops_impl { 2 | ($($tr:ident :: $f:ident ()),* $(,)?) => { 3 | $(__tuple_unary_ops_impl!{ @impl $tr $f })* 4 | }; 5 | (@impl $tr:ident $f:ident) => { 6 | impl $tr for Unit { 7 | type Output = Unit; 8 | 9 | fn $f(self) -> Self::Output { 10 | self 11 | } 12 | } 13 | 14 | impl $tr for &Unit { 15 | type Output = Unit; 16 | 17 | fn $f(self) -> Self::Output { 18 | Unit 19 | } 20 | } 21 | 22 | impl $tr for Tuple 23 | where 24 | First: $tr, 25 | Other: $tr + TupleLike, 26 | { 27 | type Output = Tuple; 28 | 29 | fn $f(self) -> Self::Output { 30 | Tuple($tr::$f(self.0), $tr::$f(self.1)) 31 | } 32 | } 33 | 34 | impl<'a, First, Other> $tr for &'a Tuple 35 | where 36 | &'a First: $tr, 37 | &'a Other: $tr, 38 | Other: TupleLike, 39 | { 40 | type Output = Tuple<<&'a First as $tr>::Output, <&'a Other as $tr>::Output>; 41 | 42 | fn $f(self) -> Self::Output { 43 | Tuple($tr::$f(&self.0), $tr::$f(&self.1)) 44 | } 45 | } 46 | } 47 | } 48 | 49 | macro_rules! __tuple_binary_ops_impl { 50 | ($($tr:ident :: $f:ident ()),* $(,)?) => { 51 | $(__tuple_binary_ops_impl!{ @impl $tr $f })* 52 | }; 53 | (@impl $tr:ident $f:ident) => { 54 | impl $tr for Unit { 55 | type Output = T; 56 | fn $f(self, rhs: T) -> Self::Output { 57 | rhs 58 | } 59 | } 60 | 61 | impl $tr for &Unit { 62 | type Output = T; 63 | fn $f(self, rhs: T) -> Self::Output { 64 | rhs 65 | } 66 | } 67 | 68 | impl $tr for Tuple 69 | where 70 | Other: TupleLike 71 | { 72 | type Output = Self; 73 | fn $f(self, _: Unit) -> Self::Output { 74 | self 75 | } 76 | } 77 | 78 | impl $tr<&Unit> for Tuple 79 | where 80 | Other: TupleLike 81 | { 82 | type Output = Self; 83 | fn $f(self, _: &Unit) -> Self::Output { 84 | self 85 | } 86 | } 87 | 88 | impl $tr for &Tuple 89 | where 90 | Tuple: Clone, 91 | Other: TupleLike 92 | { 93 | type Output = Tuple; 94 | fn $f(self, _: Unit) -> Self::Output { 95 | Clone::clone(self) 96 | } 97 | } 98 | 99 | impl $tr<&Unit> for &Tuple 100 | where 101 | Tuple: Clone, 102 | Other: TupleLike 103 | { 104 | type Output = Tuple; 105 | fn $f(self, _: &Unit) -> Self::Output { 106 | Clone::clone(self) 107 | } 108 | } 109 | 110 | impl $tr> for Tuple 111 | where 112 | First1: $tr, 113 | Other1: $tr + TupleLike, 114 | Other2: TupleLike, 115 | { 116 | type Output = Tuple; 117 | fn $f(self, rhs: Tuple) -> Self::Output { 118 | Tuple($tr::$f(self.0, rhs.0), $tr::$f(self.1, rhs.1)) 119 | } 120 | } 121 | 122 | impl<'a, First1, Other1, First2, Other2> $tr<&'a Tuple> for Tuple 123 | where 124 | First1: $tr<&'a First2>, 125 | Other1: $tr<&'a Other2> + TupleLike, 126 | Other2: TupleLike, 127 | { 128 | type Output = Tuple; 129 | fn $f(self, rhs: &'a Tuple) -> Self::Output { 130 | Tuple($tr::$f(self.0, &rhs.0), $tr::$f(self.1, &rhs.1)) 131 | } 132 | } 133 | 134 | impl<'a, First1, Other1, First2, Other2> $tr> for &'a Tuple 135 | where 136 | &'a First1: $tr, 137 | &'a Other1: $tr, 138 | Other1: TupleLike, 139 | Other2: TupleLike, 140 | { 141 | type Output = Tuple<<&'a First1 as $tr>::Output, <&'a Other1 as $tr>::Output>; 142 | fn $f(self, rhs: Tuple) -> Self::Output { 143 | Tuple($tr::$f(&self.0, rhs.0), $tr::$f(&self.1, rhs.1)) 144 | } 145 | } 146 | 147 | impl<'a, 'b, First1, Other1, First2, Other2> $tr<&'a Tuple> 148 | for &'b Tuple 149 | where 150 | &'b First1: $tr<&'a First2>, 151 | &'b Other1: $tr<&'a Other2>, 152 | Other1: TupleLike, 153 | Other2: TupleLike, 154 | { 155 | type Output = 156 | Tuple<<&'b First1 as $tr<&'a First2>>::Output, <&'b Other1 as $tr<&'a Other2>>::Output>; 157 | fn $f(self, rhs: &'a Tuple) -> Self::Output { 158 | Tuple($tr::$f(&self.0, &rhs.0), $tr::$f(&self.1, &rhs.1)) 159 | } 160 | } 161 | } 162 | } 163 | 164 | macro_rules! __tuple_assignment_ops_impl { 165 | ($($tr:ident :: $f:ident ()),* $(,)?) => { 166 | $(__tuple_assignment_ops_impl!{ @impl $tr $f })* 167 | }; 168 | (@impl $tr:ident $f:ident) => { 169 | impl $tr for Unit { 170 | fn $f(&mut self, _: Unit) {} 171 | } 172 | 173 | impl $tr<&Unit> for Unit { 174 | fn $f(&mut self, _: &Unit) {} 175 | } 176 | 177 | impl $tr> for Tuple 178 | where 179 | First1: $tr + TupleLike, 180 | Other1: $tr + TupleLike, 181 | { 182 | fn $f(&mut self, rhs: Tuple) { 183 | self.0.$f(rhs.0); 184 | self.1.$f(rhs.1); 185 | } 186 | } 187 | 188 | impl<'a, First1, Other1, First2, Other2> $tr<&'a Tuple> 189 | for Tuple 190 | where 191 | First1: $tr<&'a First2> + TupleLike, 192 | Other1: $tr<&'a Other2> + TupleLike, 193 | { 194 | fn $f(&mut self, rhs: &'a Tuple) { 195 | self.0.$f(&rhs.0); 196 | self.1.$f(&rhs.1); 197 | } 198 | } 199 | } 200 | } 201 | 202 | pub(crate) use __tuple_assignment_ops_impl; 203 | pub(crate) use __tuple_binary_ops_impl; 204 | pub(crate) use __tuple_unary_ops_impl; 205 | 206 | /// Generate a tuple from a list of expressions. 207 | /// 208 | /// # Syntax 209 | /// 210 | /// `tuple!( [ Expr1 [; Count], Expr2 [; Count], ... ] )` 211 | /// 212 | /// *`[` and `]` only indicate the optional content but not that they need to be input.* 213 | /// 214 | /// *Similarly, `...` indicates several repeated segments, rather than inputting `...`.* 215 | /// 216 | /// # Examples 217 | /// 218 | /// ``` 219 | /// use tuplez::{tuple, Unit}; 220 | /// 221 | /// let tup = tuple!(1, "hello", 3.14); 222 | /// let tup2 = tuple!("world", 2;3, 9.8); // Repeat `2` three times 223 | /// assert_eq!(tup2, tuple!("world", 2, 2, 2, 9.8)); 224 | /// 225 | /// let unit = tuple!(); 226 | /// assert_eq!(unit, Unit); 227 | /// ``` 228 | /// 229 | /// Remember that the [`tuple!`](crate::tuple!) macro does not directly evaluate expressions, so: 230 | /// 231 | /// ``` 232 | /// use tuplez::tuple; 233 | /// 234 | /// let mut x = 0; 235 | /// assert_eq!(tuple!({x += 1; x}; 3), tuple!(1, 2, 3)); 236 | /// ``` 237 | #[macro_export] 238 | macro_rules! tuple { 239 | ($($t:tt)*) => { 240 | $crate::tuple_inner!($crate; $($t)*) 241 | }; 242 | } 243 | 244 | /// Generate the complete type signature for tuples. 245 | /// 246 | /// # Syntax 247 | /// 248 | /// `tuple_t!([T0 [; Count], T1 [; Count], ... ])` 249 | /// 250 | /// *`[` and `]` only indicate the optional content but not that they need to be input.* 251 | /// 252 | /// *Similarly, `...` indicates several repeated segments, rather than inputting `...`.* 253 | /// 254 | /// # Examples 255 | /// 256 | /// ``` 257 | /// use tuplez::{tuple, tuple_t}; 258 | /// 259 | /// let tup = ::default(); 260 | /// assert_eq!(tup, tuple!(0, 0.0, String::new())); 261 | /// 262 | /// let unit: tuple_t!() = From::from(()); 263 | /// assert_eq!(unit, tuple!()); 264 | /// 265 | /// let tup2: tuple_t!(i32, f64;3, i32) = tuple!(1, 2.0, 3.0, 4.0, 5); 266 | /// 267 | /// fn use_tuple(tup: tuple_t!(i32, &dyn std::fmt::Debug, tuple_t!(String, String))) { 268 | /// todo!() 269 | /// } 270 | /// ``` 271 | #[macro_export] 272 | macro_rules! tuple_t { 273 | ($($t:tt)*) => { 274 | $crate::tuple_t_inner!($crate; $($t)*) 275 | }; 276 | } 277 | 278 | /// Generate patterns for tuples. 279 | /// 280 | /// # Syntax 281 | /// 282 | /// `tuple_pat!([#] [Pat0 [; Count], Pat1 [; Count], ... ])` 283 | /// 284 | /// *`[` and `]` only indicate the optional content but not that they need to be input.* 285 | /// 286 | /// *Similarly, `...` indicates several repeated segments, rather than inputting `...`.* 287 | /// 288 | /// # Examples 289 | /// 290 | /// When the number of patterns you provide is less than the number of elements of the tuple, 291 | /// the following elements will not be matched. For example: 292 | /// 293 | /// ``` 294 | /// use tuplez::{tuple, tuple_pat}; 295 | /// 296 | /// let tup = tuple!(3.14, "hello", 1, [9.8]); 297 | /// let tuple_pat!(a, b, c) = tup; 298 | /// assert_eq!(a, 3.14); 299 | /// assert_eq!(b, "hello"); 300 | /// assert_eq!(c, 1); 301 | /// ``` 302 | /// 303 | /// If you want the last pattern to match all remaining elements, you can add a `#` mark: 304 | /// 305 | /// ``` 306 | /// use tuplez::{tuple, tuple_pat}; 307 | /// 308 | /// let tup = tuple!(3.14, "hello", 1, [9.8]); 309 | /// let tuple_pat!(# a, b, c) = tup; 310 | /// assert_eq!(a, 3.14); 311 | /// assert_eq!(b, "hello"); 312 | /// assert_eq!(c, tuple!(1, [9.8])); 313 | /// ``` 314 | /// 315 | /// But this has a bad side effect, even though the number of patterns is equal to the number of elements of the tuple, 316 | /// the last pattern still matches a tuple containing only one element: 317 | /// 318 | /// ``` 319 | /// use tuplez::{tuple, tuple_pat}; 320 | /// 321 | /// let tup = tuple!(3.14, "hello", 1, [9.8]); 322 | /// let tuple_pat!(# a, b, c, d) = tup; 323 | /// assert_eq!(a, 3.14); 324 | /// assert_eq!(b, "hello"); 325 | /// assert_eq!(c, 1); 326 | /// assert_eq!(d, tuple!([9.8])); // Not `[9.8]` 327 | /// ``` 328 | /// 329 | /// In this case, just remove the `#` mark. Or, you can also add an extra `_` pattern to unpack the last tuple: 330 | /// 331 | /// ``` 332 | /// use tuplez::{tuple, tuple_pat}; 333 | /// 334 | /// let tup = tuple!(3.14, "hello", 1, [9.8]); 335 | /// let tuple_pat!(# a, b, c, d, _) = tup; 336 | /// assert_eq!(a, 3.14); 337 | /// assert_eq!(b, "hello"); 338 | /// assert_eq!(c, 1); 339 | /// assert_eq!(d, [9.8]); 340 | /// ``` 341 | #[macro_export] 342 | macro_rules! tuple_pat { 343 | ($($t:tt)*) => { 344 | $crate::tuple_pat_inner!($crate; $($t)*) 345 | }; 346 | } 347 | 348 | /// Take the element at a specific index of the tuple and get the remainder. 349 | /// 350 | /// When the type of element is provided instead of its index, this macro expands to 351 | /// [`take()`](crate::TupleLike::take()). 352 | /// 353 | /// The [`pop()`](crate::TupleLike::pop()) and [`pop_front()`](crate::TupleLike::pop_front()) methods 354 | /// also provide ways to pop elements from the front or back of the tuple. 355 | /// 356 | /// # Syntax 357 | /// 358 | /// 1. `take!(Expr; Index)` 359 | /// 360 | /// **The index must be an integer literal** since procedural macros do not yet support evaluating constants. 361 | /// 362 | /// 2. `take!(Expr; Type)` 363 | /// 364 | /// There is currently a restriction: only one element in the tuple can be of the type being searched. 365 | /// 366 | /// # Examples 367 | /// 368 | /// Use indices: 369 | /// 370 | /// ``` 371 | /// use tuplez::{take, tuple}; 372 | /// 373 | /// let tup = tuple!(1, "hello", 3.14, [1, 2, 3]); 374 | /// let (element, remainder) = take!(tup; 2); 375 | /// assert_eq!(element, 3.14); 376 | /// assert_eq!(remainder, tuple!(1, "hello", [1, 2, 3])); 377 | /// 378 | /// let tup = tuple!(1); 379 | /// let (element, remainder) = take!(tup; 0); 380 | /// assert_eq!(element, 1); 381 | /// assert_eq!(remainder, tuple!()); 382 | /// ``` 383 | /// 384 | /// Use types: 385 | /// 386 | /// ``` 387 | /// use tuplez::{take, tuple}; 388 | /// 389 | /// let tup = tuple!(1, "hello", 3.14, [1, 2, 3]); 390 | /// let (element, remainder) = take!(tup; &str); 391 | /// assert_eq!(element, "hello"); 392 | /// assert_eq!(remainder, tuple!(1, 3.14, [1, 2, 3])); 393 | /// 394 | /// let tup = tuple!(1); 395 | /// let (element, remainder) = take!(tup; i32); 396 | /// assert_eq!(element, 1); 397 | /// assert_eq!(remainder, tuple!()); 398 | /// ``` 399 | #[macro_export] 400 | macro_rules! take { 401 | ($($t:tt)*) => { 402 | $crate::take_inner!($crate; $($t)*) 403 | }; 404 | } 405 | 406 | /// Split the tuple into two tuples at a specific index. 407 | /// 408 | /// # Syntax 409 | /// 410 | /// `split_at!(Expr; Index)` 411 | /// 412 | /// **The index must be an integer literal** since procedural macros do not yet support evaluating constants. 413 | /// 414 | /// # Examples 415 | /// 416 | /// ``` 417 | /// use tuplez::{split_at, tuple}; 418 | /// 419 | /// let tup = tuple!(1, "hello", 3.14, [1, 2, 3]); 420 | /// 421 | /// let (left, right) = split_at!(tup; 2); 422 | /// assert_eq!(left, tuple!(1, "hello")); 423 | /// assert_eq!(right, tuple!(3.14, [1, 2, 3])); 424 | /// 425 | /// let (left, right) = split_at!(tup; 0); 426 | /// assert_eq!(left, tuple!()); 427 | /// assert_eq!(right, tup); 428 | /// 429 | /// let (left, right) = split_at!(tup; 4); 430 | /// assert_eq!(left, tup); 431 | /// assert_eq!(right, tuple!()); 432 | /// ``` 433 | #[macro_export] 434 | macro_rules! split_at { 435 | ($($t:tt)*) => { 436 | $crate::split_at_inner!($crate; $($t)*) 437 | }; 438 | } 439 | 440 | /// Provides a simple way to build a mapper that implements [`Mapper`](crate::foreach::Mapper). 441 | /// 442 | /// # Syntax 443 | /// 444 | /// ```text 445 | /// Generic = [Lifetime1, Lifetime2, ...] [Type1 [: Bound1], Type2 [: Bound2], ...] 446 | /// Rule = [ < Generic > ] | Variable : InputType | [-> OutputType] { Body } [,] [;] 447 | /// 448 | /// mapper!( [Rule1 Rule2 ... ] ) 449 | /// ``` 450 | /// 451 | /// *`[` and `]` only indicate the optional content but not that they need to be input.* 452 | /// 453 | /// *Similarly, `...` indicates several repeated segments, rather than inputting `...`.* 454 | /// 455 | /// # Explanation 456 | /// 457 | /// A mapping rule is much like a closure, except that it must annotate the argument type and the return type: 458 | /// 459 | /// ```text 460 | /// |x: i32| -> i64 { x as i64 } 461 | /// ``` 462 | /// 463 | /// Note that it's just like but not really a closure, so you can't capture context variables. 464 | /// 465 | /// Also supports adding `mut`: 466 | /// 467 | /// ```text 468 | /// |mut x: i32| -> i64 { x += 1; x as i64 } 469 | /// ``` 470 | /// 471 | /// If the return value requires a lifetime, you need to explicitly introduce the lifetime annotation, since Rust binds the lifetime 472 | /// of return value to the mapper instead of the element by default: 473 | /// 474 | /// ```text 475 | /// <'a> |x: &'a str| -> &'a [u8] { x.as_bytes() } 476 | /// ``` 477 | /// 478 | /// You can omit the return type when the return type is the same as the element type. 479 | /// Note: Do not misunderstand that the return type is automatically inferred or is a `()`. 480 | /// 481 | /// ```text 482 | /// |x: i32| { x + 1 } 483 | /// ``` 484 | /// 485 | /// You can also introduce generic types like this: 486 | /// 487 | /// ```text 488 | /// |x: Option| -> T { x.unwrap() } 489 | /// ``` 490 | /// 491 | /// Many times, you may also need to add bounds to the generic type: 492 | /// 493 | /// ```text 494 | /// |x: Option| -> String { x.unwrap().to_string() } 495 | /// ``` 496 | /// 497 | /// Construct mapping rules for all element types in the tuple, 498 | /// and then combine them in the [`mapper!`](crate::mapper!) macro to traverse the tuple: 499 | /// 500 | /// ``` 501 | /// use tuplez::{mapper, tuple, TupleLike}; 502 | /// 503 | /// let tup = tuple!(1, "hello", Some(3.14)).foreach(mapper! { 504 | /// |mut x: i32| -> i64 { x += 1; x as i64 } 505 | /// |x: Option| -> String { x.unwrap().to_string() } 506 | /// <'a> |x: &'a str| -> &'a [u8] { x.as_bytes() } 507 | /// }); 508 | /// assert_eq!(tup, tuple!(2i64, b"hello" as &[u8], "3.14".to_string())); 509 | /// ``` 510 | /// 511 | /// It is allowed to add commas or semicolons as separators between rules. Sometimes this may look better. 512 | /// 513 | /// Tip: If you don't want to consume the tuple, call its [`as_ref()`](crate::TupleLike::as_ref()) before traversing. 514 | /// Likewise, if you want to modify elements of tuple, call its [`as_mut()`](crate::TupleLike::as_mut()) before traversing. 515 | /// 516 | /// ``` 517 | /// use tuplez::{mapper, tuple, TupleLike}; 518 | /// 519 | /// let mut tup = tuple!(1, "hello", Some(3.14)); 520 | /// let tup2 = tup.as_ref().foreach(mapper! { 521 | /// |x: &i32| -> i32 { *x + 1 } 522 | /// |x: &Option| -> String { x.as_ref().unwrap().to_string() } 523 | /// <'a> |x: &&'a str| -> &'a [u8] { x.as_bytes() } 524 | /// }); 525 | /// assert_eq!(tup2, tuple!(2, b"hello" as &[u8], "3.14".to_string())); 526 | /// assert_eq!(tup, tuple!(1, "hello", Some(3.14))); // And the original tuple is not consumed 527 | /// 528 | /// _ = tup.as_mut().foreach(mapper! { 529 | /// |x: &mut i32| -> () { *x += 1; } 530 | /// |x: &mut Option| -> () { x.take(); } 531 | /// |x: &mut &str| -> () { *x = "world" } 532 | /// }); 533 | /// assert_eq!(tup, tuple!(2, "world", None)); 534 | /// ``` 535 | #[macro_export] 536 | macro_rules! mapper { 537 | ($($t:tt)*) => { 538 | $crate::mapper_inner!($crate; $($t)*) 539 | }; 540 | } 541 | 542 | /// Provides a simple way to build a folder that implements [`Folder`](crate::fold::Folder). 543 | /// 544 | /// # Syntax 545 | /// 546 | /// ```text 547 | /// Generic = [Lifetime1, Lifetime2, ...] [Type1 [: Bound1], Type2 [: Bound2], ...] 548 | /// Rule = [ < Generic > ] | Variable1, Variable2 : InputType | { Body } [,] [;] 549 | /// 550 | /// folder!( OutputType; [Rule1 Rule2 ... ] ) 551 | /// ``` 552 | /// 553 | /// *`[` and `]` only indicate the optional content but not that they need to be input.* 554 | /// 555 | /// *Similarly, `...` indicates several repeated segments, rather than inputting `...`.* 556 | /// 557 | /// # Explanation 558 | /// 559 | /// A folding rule is much like a closure, except that it must annotate the element type: 560 | /// 561 | /// ```text 562 | /// |acc, x: i32| { acc + x } 563 | /// ``` 564 | /// 565 | /// Note that it's just like but not really a closure, so you can't capture context variables. 566 | /// 567 | /// You'd better not annotate types for the accumulation value and return value, 568 | /// because they must to be annotated uniformly. Of course you can do that, 569 | /// but there would be no advantage other than potential compilation errors. 570 | /// 571 | /// Also supports adding `mut`: 572 | /// 573 | /// ```text 574 | /// |mut acc, mut x: i32| -> i64 { acc += 1; x += 1; acc + x } 575 | /// ``` 576 | /// 577 | /// You can also introduce generic types like this: 578 | /// 579 | /// ```text 580 | /// |x: Option| { x.unwrap().to_string() } 581 | /// ``` 582 | /// 583 | /// You need to determine the type of the accumulation value, for example, `i32`. 584 | /// Then, construct folding rules for all element types in the tuple, 585 | /// and then combine them in the [`folder!`](crate::folder!) macro to fold the tuple: 586 | /// 587 | /// ``` 588 | /// use std::convert::AsRef; 589 | /// use tuplez::{folder, tuple, TupleLike}; 590 | /// 591 | /// let tup = tuple!(1, "2", 3.0); 592 | /// let result = tup.fold( 593 | /// folder! {i32; // Annotate the accumulation value type 594 | /// |acc, x: i32| { acc + x } 595 | /// |acc, x: f32| { acc + (x as i32) } 596 | /// // `str` is a DST, so `?Sized` bound is required. 597 | /// + ?Sized> |acc, x: &T| { acc + x.as_ref().parse::().unwrap() } 598 | /// }, 599 | /// 0 600 | /// ); 601 | /// assert_eq!(result, 6); 602 | /// ``` 603 | /// 604 | /// It is allowed to add commas or semicolons as separators between rules. Sometimes this may look better. 605 | #[macro_export] 606 | macro_rules! folder { 607 | ($($t:tt)*) => { 608 | $crate::folder_inner!($crate; $($t)*) 609 | }; 610 | } 611 | 612 | /// Provides a simple way to build a unary predicate that implements [`UnaryPredicate`](crate::predicate::UnaryPredicate). 613 | /// 614 | /// # Syntax 615 | /// 616 | /// ```text 617 | /// Generic = [Lifetime1, Lifetime2, ...] [Type1 [: Bound1], Type2 [: Bound2], ...] 618 | /// Rule = [ < Generic > ] | Variable : InputType | { Body } [,] [;] 619 | /// 620 | /// unary_pred!( [Rule1 Rule2 ... ] ) 621 | /// ``` 622 | /// 623 | /// # Explanation 624 | /// 625 | /// A unary predicate rule is much like a closure, except that it must annotate the element type, 626 | /// and what you actually get is the immutable reference to the element rather than itself. 627 | /// 628 | /// ```text 629 | /// |x: i32| { *x > 10 } // The actual type of `x` is `&i32` not `i32` 630 | /// ``` 631 | /// 632 | /// Note that it's just like but not really a closure, so you can't capture context variables. 633 | /// 634 | /// You'd better not annotate types for the return value of rules, 635 | /// because they must return a `bool` value. Of course you can do that, 636 | /// but there would be no advantage other than potential compilation errors. 637 | /// 638 | /// You can also introduce generic types like this: 639 | /// 640 | /// ```text 641 | /// bool> |f: T| { f(1) } 642 | /// ``` 643 | /// 644 | /// Construct unary predicate rules for all element types in the tuple, 645 | /// and then combine them in the [`unary_pred!`](crate::unary_pred!) macro to test the tuple: 646 | /// 647 | /// ``` 648 | /// use tuplez::{tuple, TupleLike, unary_pred}; 649 | /// 650 | /// let tup = tuple!(1, "2", |x: i32| x >= 0); 651 | /// let result = tup.all( 652 | /// unary_pred! { 653 | /// |x: i32| { *x >= 0 } 654 | /// |x: &str| { !x.is_empty() } 655 | /// bool> |f: T| { f(1) } 656 | /// } 657 | /// ); 658 | /// assert_eq!(result, true); 659 | /// ``` 660 | /// 661 | /// It is allowed to add commas or semicolons as separators between rules. Sometimes this may look better. 662 | /// 663 | /// # As a [`Mapper`](crate::foreach::Mapper) 664 | /// 665 | /// In fact, this macro does not directly implement [`UnaryPredicate`](crate::predicate::UnaryPredicate) for the 666 | /// underlying type. Instead, it implements [`Mapper<&T, Output=bool>`](crate::foreach::Mapper). 667 | /// 668 | /// Therefore, you can definitely use it as a [`Mapper`](crate::foreach::Mapper) like this: 669 | /// 670 | /// ``` 671 | /// use tuplez::{tuple, TupleLike, unary_pred}; 672 | /// 673 | /// let tup = tuple!(Some(1), "", |x: i32| x == 0); 674 | /// let result = tup.as_ref().foreach( 675 | /// unary_pred! { 676 | /// |x: Option| { x.is_some() } 677 | /// |x: &str| { !x.is_empty() } 678 | /// bool> |f: T| { f(1) } 679 | /// } 680 | /// ); 681 | /// 682 | /// assert_eq!(result, tuple!(true, false, false)); 683 | /// ``` 684 | #[macro_export] 685 | macro_rules! unary_pred { 686 | ($($t:tt)*) => { 687 | $crate::unary_pred_inner!($crate; $($t)*) 688 | }; 689 | } 690 | -------------------------------------------------------------------------------- /src/predicate.rs: -------------------------------------------------------------------------------- 1 | //! Provides the ability to test tuples. 2 | 3 | use crate::{foreach::Mapper, Tuple, TupleLike, Unit}; 4 | 5 | /// Define a unary predicate that accepts immutable reference of a value and produces a `bool` result. 6 | /// 7 | /// Call [`any()`](TupleLike::any()) and [`all()`](TupleLike::all()) on a tuple requires a unary predicate 8 | /// that implements [`UnaryPredicate`]. 9 | /// 10 | /// Note that the predicate always receives an immutable reference to the element of the tuple. 11 | /// 12 | /// # Quickly build a unary predicate by macros 13 | /// 14 | /// Here are two ways you can quickly build a folder. 15 | /// 16 | /// ## Test tuples by element types 17 | /// 18 | /// The [`unary_pred!`](crate::unary_pred!) macro helps you build a unary predicate that test tuples according to their element types. 19 | /// 20 | /// For example: 21 | /// 22 | /// ``` 23 | /// use tuplez::{tuple, TupleLike, unary_pred}; 24 | /// 25 | /// let tup = tuple!(1, "2", |x: i32| x >= 0); 26 | /// let result = tup.all( 27 | /// unary_pred! { 28 | /// |x: i32| { *x >= 0 } 29 | /// |x: &str| { !x.is_empty() } 30 | /// bool> |f: T| { f(1) } 31 | /// } 32 | /// ); 33 | /// assert_eq!(result, true); 34 | /// ``` 35 | /// 36 | /// ## Test tuples in order of their elements 37 | /// 38 | /// You can create a new tuple with the same number of elements, whose elements are all callable objects that accepts 39 | /// an immutable reference to an element and returns a `bool` value ([`FnOnce(&T) -> bool`](std::ops::FnOnce)), 40 | /// then, you can use that tuple as a unary predicate. 41 | /// 42 | /// For example: 43 | /// 44 | /// ``` 45 | /// use tuplez::{tuple, TupleLike}; 46 | /// 47 | /// let tup = tuple!(1, 2, "3"); 48 | /// let result = tup.any( 49 | /// tuple!( 50 | /// |x: &i32| *x < 0, 51 | /// |x: &i32| *x > 100, 52 | /// |x: &&str| *x == "1", 53 | /// ) 54 | /// ); 55 | /// assert_eq!(result, false); 56 | /// ``` 57 | /// 58 | /// # Custom unary predicate 59 | /// 60 | /// NOTE: In general, a unary predicate is equivalent to a mapper that accepts immutable references 61 | /// to elements and returns a `bool` value. Therefore, instead of [`UnaryPredicate`], 62 | /// you should implement [`Mapper<&T, Output=bool>`](Mapper) for your custom type, and use it as a unary predicate. 63 | /// In fact, this is what the [`unary_pred!`](crate::unary_pred!) macro does. 64 | /// 65 | /// Here is an example: 66 | /// 67 | /// ``` 68 | /// use std::ops::Range; 69 | /// use tuplez::{foreach::Mapper, tuple, TupleLike}; 70 | /// 71 | /// #[derive(Clone)] 72 | /// struct Basis(Range); 73 | /// 74 | /// impl Mapper<&i32> for Basis { 75 | /// type Output = bool; 76 | /// type NextMapper = Self; 77 | /// fn map(self, value: &i32) -> (Self::Output, Self::NextMapper) { 78 | /// (self.0.contains(value), self) 79 | /// } 80 | /// } 81 | /// 82 | /// impl Mapper<&&str> for Basis { 83 | /// type Output = bool; 84 | /// type NextMapper = Self; 85 | /// fn map(self, value: &&str) -> (Self::Output, Self::NextMapper) { 86 | /// ( 87 | /// value.parse::().is_ok_and(|s| self.0.contains(&s)), 88 | /// self, 89 | /// ) 90 | /// } 91 | /// } 92 | /// 93 | /// let basis = Basis(0..5); // Let us assume that `basis` is known only at runtime 94 | /// 95 | /// let tup = tuple!(1, 2, "3"); 96 | /// let result = tup.all(basis.clone()); 97 | /// assert_eq!(result, true); 98 | /// 99 | /// let tup = tuple!(-1, 8, "10"); 100 | /// let result = tup.any(basis.clone()); 101 | /// assert_eq!(result, false); 102 | /// ``` 103 | pub trait UnaryPredicate<'a, T: 'a> { 104 | /// Type of next unary predicate to be use. 105 | type NextUnaryPredicate; 106 | 107 | /// Test a value with its immutable reference 108 | fn test(self, testee: &'a T) -> (bool, Self::NextUnaryPredicate); 109 | } 110 | 111 | impl<'a, T, F> UnaryPredicate<'a, T> for F 112 | where 113 | T: 'a, 114 | F: Mapper<&'a T, Output = bool>, 115 | { 116 | type NextUnaryPredicate = >::NextMapper; 117 | fn test(self, testee: &'a T) -> (bool, Self::NextUnaryPredicate) { 118 | self.map(testee) 119 | } 120 | } 121 | 122 | /// Tests if any element of the tuple matches a predicate. 123 | /// 124 | /// # The unary predicate `Pred` 125 | /// 126 | /// For testing [`Tuple`](crate::Tuple), you need to build a unary predicate, 127 | /// which needs to implement [`UnaryPredicate`], and the [`NextUnaryPredicate`](UnaryPredicate::NextUnaryPredicate) 128 | /// needs to implement [`UnaryPredicate`], and so on. 129 | /// 130 | /// See the documentation page of [`UnaryPredicate`] for details. 131 | pub trait TestAny: TupleLike { 132 | /// Tests if any element of the tuple matches a predicate. 133 | /// 134 | /// Check out [`UnaryPredicate`]'s documentation page to learn how to build 135 | /// a unary predicate that can be passed to [`any()`](TestAny::any()). 136 | /// 137 | /// [`any()`](TestAny::any()) is short-circuiting; in other words, it will stop processing as soon as it finds a `true`, 138 | /// given that no matter what else happens, the result will also be `true`. 139 | /// 140 | /// An empty tuple returns `false`. 141 | /// 142 | /// Hint: The [`TupleLike`] trait provides the [`any()`](TupleLike::any()) method as the wrapper 143 | /// for this [`any()`](TestAny::any()) method. 144 | /// 145 | /// # Example 146 | /// 147 | /// ``` 148 | /// use tuplez::{tuple, TupleLike, unary_pred}; 149 | /// 150 | /// let predicate = unary_pred! { 151 | /// |x: i32| { (0..10).contains(x) }, 152 | /// |x: &str| { x.parse::().is_ok() }, 153 | /// }; 154 | /// 155 | /// let tup = tuple!(100, 2, "world"); 156 | /// let result = tup.any(predicate); 157 | /// assert_eq!(result, true); 158 | /// 159 | /// let tup = tuple!(-1, 96, "hello"); 160 | /// let result = tup.any(predicate); 161 | /// assert_eq!(result, false); 162 | /// ``` 163 | fn any(&self, predicate: Pred) -> bool; 164 | } 165 | 166 | impl TestAny for Unit { 167 | fn any(&self, _: Pred) -> bool { 168 | false 169 | } 170 | } 171 | 172 | impl TestAny for Tuple 173 | where 174 | for<'a> Pred: UnaryPredicate<'a, First>, 175 | for<'a> Other: TestAny<>::NextUnaryPredicate>, 176 | { 177 | fn any(&self, predicate: Pred) -> bool { 178 | let (res, next) = predicate.test(&self.0); 179 | res || TestAny::any(&self.1, next) 180 | } 181 | } 182 | 183 | /// Tests if every element of the tuple matches a predicate. 184 | /// 185 | /// # The unary predicate `Pred` 186 | /// 187 | /// For testing [`Tuple`](crate::Tuple), you need to build a unary predicate, 188 | /// which needs to implement [`UnaryPredicate`], and the [`NextUnaryPredicate`](UnaryPredicate::NextUnaryPredicate) 189 | /// needs to implement [`UnaryPredicate`], and so on. 190 | /// 191 | /// See the documentation page of [`UnaryPredicate`] for details. 192 | pub trait TestAll: TupleLike { 193 | /// Tests if every element of the tuple matches a predicate. 194 | /// 195 | /// Check out [`UnaryPredicate`]'s documentation page to learn how to build 196 | /// a unary predicate that can be passed to [`all()`](TestAll::all()). 197 | /// 198 | /// [`all()`](TestAll::all()) is short-circuiting; in other words, it will stop processing as soon as it finds a `false`, 199 | /// given that no matter what else happens, the result will also be `false`. 200 | /// 201 | /// An empty tuple returns `true`. 202 | /// 203 | /// Hint: The [`TupleLike`] trait provides the [`all()`](TupleLike::all()) method as the wrapper 204 | /// for this [`all()`](TestAll::all()) method. 205 | /// 206 | /// # Example 207 | /// 208 | /// ``` 209 | /// use tuplez::{tuple, TupleLike, unary_pred}; 210 | /// 211 | /// let predicate = unary_pred! { 212 | /// |x: i32| { (0..10).contains(x) }, 213 | /// |x: &str| { x.parse::().is_ok() }, 214 | /// }; 215 | /// 216 | /// let tup = tuple!(1, 2, "3"); 217 | /// let result = tup.all(predicate); 218 | /// assert_eq!(result, true); 219 | /// 220 | /// let tup = tuple!(7, 8, "hello"); 221 | /// let result = tup.all(predicate); 222 | /// assert_eq!(result, false); 223 | /// ``` 224 | fn all(&self, predicate: Pred) -> bool; 225 | } 226 | 227 | impl TestAll for Unit { 228 | fn all(&self, _: Pred) -> bool { 229 | true 230 | } 231 | } 232 | 233 | impl TestAll for Tuple 234 | where 235 | for<'a> Pred: UnaryPredicate<'a, First>, 236 | for<'a> Other: TestAll<>::NextUnaryPredicate>, 237 | { 238 | fn all(&self, predicate: Pred) -> bool { 239 | let (res, next) = predicate.test(&self.0); 240 | res && TestAll::all(&self.1, next) 241 | } 242 | } 243 | -------------------------------------------------------------------------------- /src/search.rs: -------------------------------------------------------------------------------- 1 | //! Provides the ability to search tuple elements by type. 2 | //! 3 | //! Check the documentation page of [`Search`] for details. 4 | 5 | use crate::{foreach::Mapper, Tuple, TupleLenEqTo, TupleLike, Unit}; 6 | use std::marker::PhantomData; 7 | 8 | /// Helper type indicates that the search has been completed. 9 | pub struct Complete; 10 | 11 | /// Helper type indicates that current element is excluded by the search result. 12 | pub struct Unused(PhantomData); 13 | 14 | /// Helper type indicates that current element is included by the search result. 15 | pub struct Used(PhantomData); 16 | 17 | /// Search for an element of a specific type in a tuple. 18 | /// 19 | /// There is currently a restriction: only one element in the tuple can be of the type being searched. 20 | pub trait Search: TupleLike { 21 | /// The type of the remainder of the tuple after taking out the searched element. 22 | type TakeRemainder: TupleLike; 23 | 24 | /// The type of tuple that replace one element to another value that may be of a different type. 25 | type MapReplaceOutput: TupleLike; 26 | 27 | /// Take out the searched element, and get the remainder of tuple. 28 | /// 29 | /// Add a type annotation to the searched element to let [`take()`](TupleLike::take()) know which one you want. 30 | /// 31 | /// **NOTE**: The type of this element must exist only once in the tuple. 32 | /// 33 | /// If you want to take out the element at a specific index, see [`take!`](crate::take!). 34 | /// 35 | /// If you want to take out the first or last element, see [`pop()`][TupleLike::pop()]. 36 | /// 37 | /// Hint: The [`TupleLike`] trait provides the [`take()`](TupleLike::take()) method as the wrapper 38 | /// for this [`take()`](Search::take()) method. 39 | /// 40 | /// # Example 41 | /// 42 | /// ``` 43 | /// use tuplez::{tuple, TupleLike}; 44 | /// 45 | /// let tup = tuple!(3.14, "hello", 5, [1, 2, 3]); 46 | /// let (value, remainder): (i32, _) = tup.take(); // Add type annotation for `value` 47 | /// assert_eq!(value, 5); 48 | /// assert_eq!(remainder, tuple!(3.14, "hello", [1, 2, 3])); 49 | /// ``` 50 | /// 51 | /// If you cannot add a type annotation, you can also use the [`take!`](crate::take!) macro: 52 | /// 53 | /// ``` 54 | /// use tuplez::{take, tuple}; 55 | /// 56 | /// let tup = tuple!(3.14, "hello", 5, [1, 2, 3]); 57 | /// let (value, remainder) = take!(tup; i32); 58 | /// assert_eq!(value, 5); 59 | /// assert_eq!(remainder, tuple!(3.14, "hello", [1, 2, 3])); 60 | /// ``` 61 | fn take(self) -> (T, Self::TakeRemainder); 62 | 63 | /// Get an immutable reference of the searched element. 64 | /// 65 | /// Add a type annotation to the searched element to let [`get_ref()`](TupleLike::get_ref()) know which one you want. 66 | /// 67 | /// **NOTE**: The type of this element must exist only once in the tuple. 68 | /// 69 | /// If you want to get the element by its index, see [`get!`](crate::get!); 70 | /// 71 | /// Hint: The [`TupleLike`] trait provides the [`get_ref()`](TupleLike::get_ref()) method as the wrapper 72 | /// for this [`get_ref()`](Search::get_ref()) method. 73 | /// 74 | /// # Example 75 | /// 76 | /// ``` 77 | /// use tuplez::{tuple, TupleLike}; 78 | /// 79 | /// let tup = tuple!(3.14, "hello", 5, [1, 2, 3]); 80 | /// let arr: &[i32; 3] = tup.get_ref(); 81 | /// assert_eq!(arr, &[1, 2, 3]); 82 | /// ``` 83 | fn get_ref(&self) -> &T; 84 | 85 | /// Get a mutable reference of the searched element. 86 | /// 87 | /// Add a type annotation to the searched element to let [`get_mut()`](TupleLike::get_mut()) know which one you want. 88 | /// 89 | /// **NOTE**: The type of this element must exist only once in the tuple. 90 | /// 91 | /// If you want to get the element by its index, see [`get!`](crate::get!); 92 | /// 93 | /// Hint: The [`TupleLike`] trait provides the [`get_mut()`](TupleLike::get_mut()) method as the wrapper 94 | /// for this [`get_mut()`](Search::get_mut()) method. 95 | /// 96 | /// # Example 97 | /// 98 | /// ``` 99 | /// use tuplez::{tuple, TupleLike}; 100 | /// 101 | /// let mut tup = tuple!(3.14, "hello", 5, [1, 2, 3]); 102 | /// let s: &mut &str = tup.get_mut(); 103 | /// *s = "world"; 104 | /// assert_eq!(tup, tuple!(3.14, "world", 5, [1, 2, 3])); 105 | /// ``` 106 | fn get_mut(&mut self) -> &mut T; 107 | 108 | /// Swap a specific element of the same type with another value. 109 | /// 110 | /// **NOTE**: The type of this element must exist only once in the tuple. 111 | /// 112 | /// Hint: The [`TupleLike`] trait provides the [`swap()`](TupleLike::swap()) method as the wrapper 113 | /// for this [`swap()`](Search::swap()) method. 114 | /// 115 | /// # Example 116 | /// 117 | /// ``` 118 | /// use tuplez::{tuple, TupleLike}; 119 | /// 120 | /// let mut tup = tuple!(3.14, "hello", 5, [1, 2, 3]); 121 | /// let mut s = "world"; 122 | /// tup.swap(&mut s); 123 | /// assert_eq!(tup, tuple!(3.14, "world", 5, [1, 2, 3])); 124 | /// assert_eq!(s, "hello"); 125 | /// ``` 126 | fn swap(&mut self, value: &mut T) { 127 | std::mem::swap(Search::get_mut(self), value); 128 | } 129 | 130 | /// Replace a specific element of the same type with another value. 131 | /// 132 | /// Return the replaced value. 133 | /// 134 | /// **NOTE**: The type of this element must exist only once in the tuple. 135 | /// 136 | /// Hint: If you don’t want to consume the input tuple, then what you are looking 137 | /// for might be [`swap()`](TupleLike::swap()). 138 | /// 139 | /// Hint: The [`TupleLike`] trait provides the [`replace()`](TupleLike::replace()) method as the wrapper 140 | /// for this [`replace()`](Search::replace()) method. 141 | /// 142 | /// # Example 143 | /// 144 | /// ``` 145 | /// use tuplez::{tuple, TupleLike}; 146 | /// 147 | /// let mut tup = tuple!(3.14, "hello", 5, [1, 2, 3]); 148 | /// let s = tup.replace("world"); 149 | /// assert_eq!(tup, tuple!(3.14, "world", 5, [1, 2, 3])); 150 | /// assert_eq!(s, "hello"); 151 | /// ``` 152 | fn replace(&mut self, mut value: T) -> T { 153 | Search::swap(self, &mut value); 154 | value 155 | } 156 | 157 | /// Replace a specific element with another value that may be of a different type. 158 | /// 159 | /// The new element is generated a the user-defined function. 160 | /// 161 | /// Hint: The [`TupleLike`] trait provides the [`map_replace()`](TupleLike::map_replace()) method as the wrapper 162 | /// for this [`map_replace()`](Search::map_replace()) method. 163 | /// 164 | /// # Example 165 | /// 166 | /// ``` 167 | /// use tuplez::{tuple, TupleLike}; 168 | /// 169 | /// let tup = tuple!(1, 3.14, "hello", Some([1, 2, 3])); 170 | /// let result = tup.map_replace(|x: f64| x.to_string()); 171 | /// assert_eq!(result, tuple!(1, "3.14".to_string(), "hello", Some([1, 2, 3]))) 172 | /// ``` 173 | fn map_replace(self, f: F) -> Self::MapReplaceOutput 174 | where 175 | F: FnOnce(T) -> U; 176 | } 177 | 178 | impl Search for Tuple 179 | where 180 | Other: TupleLike, 181 | { 182 | type TakeRemainder = Other; 183 | 184 | type MapReplaceOutput = Tuple; 185 | 186 | fn take(self) -> (First, Self::TakeRemainder) { 187 | (self.0, self.1) 188 | } 189 | 190 | fn get_ref(&self) -> &First { 191 | &self.0 192 | } 193 | 194 | fn get_mut(&mut self) -> &mut First { 195 | &mut self.0 196 | } 197 | 198 | fn map_replace(self, f: F) -> Self::MapReplaceOutput 199 | where 200 | F: FnOnce(First) -> U, 201 | { 202 | Tuple(f(self.0), self.1) 203 | } 204 | } 205 | 206 | impl Search> for Tuple 207 | where 208 | Other: Search, 209 | { 210 | type TakeRemainder = Tuple; 211 | 212 | type MapReplaceOutput = Tuple>; 213 | 214 | fn take(self) -> (T, Self::TakeRemainder) { 215 | let (value, remainder) = Search::take(self.1); 216 | (value, Tuple(self.0, remainder)) 217 | } 218 | 219 | fn get_ref(&self) -> &T { 220 | Search::get_ref(&self.1) 221 | } 222 | 223 | fn get_mut(&mut self) -> &mut T { 224 | Search::get_mut(&mut self.1) 225 | } 226 | 227 | fn map_replace(self, f: F) -> Self::MapReplaceOutput 228 | where 229 | F: FnOnce(T) -> U, 230 | { 231 | Tuple(self.0, Search::map_replace(self.1, f)) 232 | } 233 | } 234 | 235 | /// replace tail elements of the tuple. 236 | pub trait TailReplaceable: TupleLike { 237 | /// The type of the tuple after replacing its elements. 238 | type ReplaceOutput: TupleLike; 239 | 240 | /// The type of the tuple that collect all replaced elements. 241 | type Replaced: TupleLike; 242 | 243 | /// Replace the last N elements of the tuple with all elements of another tuple of N elements. 244 | /// 245 | /// Hint: The [`TupleLike`] trait provides the [`replace_tail()`](TupleLike::replace_tail()) method as the wrapper 246 | /// for this [`replace_tail()`](TailReplaceable::replace_tail()) method. 247 | /// 248 | /// # Example 249 | /// 250 | /// ``` 251 | /// use tuplez::{tuple, TupleLike}; 252 | /// 253 | /// let tup = tuple!(1, "2", 3.0, Some(4)); 254 | /// let tup2 = tuple!("z", 8); 255 | /// let (output, replaced) = tup.replace_tail(tup2); 256 | /// assert_eq!(output, tuple!(1, "2", "z", 8)); 257 | /// assert_eq!(replaced, tuple!(3.0, Some(4))); 258 | /// ``` 259 | fn replace_tail(self, rhs: T) -> (Self::ReplaceOutput, Self::Replaced); 260 | } 261 | 262 | impl TailReplaceable for U 263 | where 264 | T: TupleLenEqTo, 265 | U: TupleLike, 266 | { 267 | type ReplaceOutput = T; 268 | type Replaced = U; 269 | 270 | fn replace_tail(self, rhs: T) -> (Self::ReplaceOutput, Self::Replaced) { 271 | (rhs, self) 272 | } 273 | } 274 | 275 | impl TailReplaceable> for Tuple 276 | where 277 | T: TupleLike, 278 | Other: TailReplaceable, 279 | { 280 | type ReplaceOutput = Tuple; 281 | type Replaced = Other::Replaced; 282 | 283 | fn replace_tail(self, rhs: T) -> (Self::ReplaceOutput, Self::Replaced) { 284 | let (output, replaced) = TailReplaceable::replace_tail(self.1, rhs); 285 | (Tuple(self.0, output), replaced) 286 | } 287 | } 288 | 289 | /// Search for subsequences of tuples. 290 | /// 291 | /// The subsequence must have one and only one candidate in the supersequence. 292 | pub trait Subseq: TupleLike 293 | where 294 | Seq: TupleLike, 295 | { 296 | /// Take out a subsequence. 297 | /// 298 | /// **NOTE**: The subsequence must have one and only one candidate in the supersequence. 299 | /// 300 | /// Add a type annotation to the subsequence to let [`subseq()`](Subseq::subseq()) know. 301 | /// 302 | /// Hint: The [`TupleLike`] trait provides the [`subseq()`](TupleLike::subseq()) method as the wrapper 303 | /// for this [`subseq()`](Subseq::subseq()) method. 304 | /// 305 | /// # Example 306 | /// 307 | /// ``` 308 | /// use tuplez::{tuple, TupleLike, tuple_t}; 309 | /// 310 | /// let tup = tuple!(12, "hello", 24, 3.14, true); 311 | /// let subseq: tuple_t!(&str, bool) = tup.subseq(); 312 | /// assert_eq!(subseq, tuple!("hello", true)); 313 | /// 314 | /// // Two candidates available: `(12, true)` or `(24, true)`. 315 | /// // let subseq: tuple_t!(i32, bool) = tup.subseq(); 316 | /// 317 | /// // No candidates available. 318 | /// // `(true, "hello")` cannot be a candidate, since its element order is 319 | /// // different from the supersequence. 320 | /// // let subseq: tuple_t!(bool, &str) = tup.subseq(); 321 | /// 322 | /// // Although `24` is also `i32`, but only `(12, "hello")` is a candidate. 323 | /// let subseq: tuple_t!(i32, &str) = tup.subseq(); 324 | /// assert_eq!(subseq, tuple!(12, "hello")); 325 | /// 326 | /// // It's OK to pick all `i32`s since there is only one candidate. 327 | /// let subseq: tuple_t!(i32, i32) = tup.subseq(); 328 | /// assert_eq!(subseq, tuple!(12, 24)); 329 | /// ``` 330 | fn subseq(self) -> Seq; 331 | 332 | /// Similar to [`subseq()`](Subseq::subseq()), 333 | /// but all its elements are immutable references to the supersequence's elements. 334 | /// 335 | /// **NOTE**: The subsequence must have one and only one candidate in the supersequence. 336 | /// 337 | /// Hint: The [`TupleLike`] trait provides the [`subseq_ref()`](TupleLike::subseq_ref()) method as 338 | /// the wrapper for this [`subseq_ref()`](Subseq::subseq_ref()) method. 339 | /// 340 | /// Rust is almost impossible to infer generic types by the return type annotation, 341 | /// so you need to call it like: 342 | /// 343 | /// ``` 344 | /// use tuplez::{tuple, TupleLike, tuple_t}; 345 | /// 346 | /// let tup = tuple!(12, "hello", vec![1, 2, 3], 24, 3.14, true); 347 | /// let subseq = tup.subseq_ref::(); 348 | /// assert_eq!(subseq, tuple!(&"hello", &true)); 349 | /// ``` 350 | fn subseq_ref(&self) -> Seq::AsRefOutput<'_>; 351 | 352 | /// Similar to [`subseq()`](Subseq::subseq()), 353 | /// but all its elements are mutable references to the supersequence's elements. 354 | /// 355 | /// **NOTE**: The subsequence must have one and only one candidate in the supersequence. 356 | /// 357 | /// Hint: The [`TupleLike`] trait provides the [`subseq_mut()`](TupleLike::subseq_mut()) method as 358 | /// the wrapper for this [`subseq_mut()`](Subseq::subseq_mut()) method. 359 | /// 360 | /// Rust is almost impossible to infer generic types by the return type annotation, 361 | /// so you need to call it like: 362 | /// 363 | /// ``` 364 | /// use tuplez::{get, tuple, TupleLike, tuple_t}; 365 | /// 366 | /// let mut tup = tuple!(12, "hello", vec![1, 2, 3], 24, 3.14, true); 367 | /// let subseq = tup.subseq_mut::(); 368 | /// *get!(subseq; 0) = "world"; 369 | /// *get!(subseq; 1) = false; 370 | /// assert_eq!(tup, tuple!(12, "world", vec![1, 2, 3], 24, 3.14, false)); 371 | /// ``` 372 | fn subseq_mut(&mut self) -> Seq::AsMutOutput<'_>; 373 | 374 | /// Swap elements with a subsequence. 375 | /// 376 | /// See [`subseq()`](Subseq::subseq()) to see which inputs are subsequence. 377 | /// 378 | /// **NOTE**: The subsequence must have one and only one candidate in the supersequence. 379 | /// 380 | /// Hint: The [`TupleLike`] trait provides the [`swap_subseq()`](TupleLike::swap_subseq()) method as 381 | /// the wrapper for this [`swap_subseq()`](Subseq::swap_subseq()) method. 382 | /// 383 | /// # Example 384 | /// 385 | /// ``` 386 | /// use tuplez::{tuple, TupleLike}; 387 | /// 388 | /// let mut tup = tuple!(1, Some("hello"), 2, Some(()), 3.14, 3); 389 | /// let mut tup2 = tuple!(Some("world"), 9.8); 390 | /// tup.swap_subseq(&mut tup2); 391 | /// assert_eq!(tup, tuple!(1, Some("world"), 2, Some(()), 9.8, 3)); 392 | /// assert_eq!(tup2, tuple!(Some("hello"), 3.14)); 393 | /// ``` 394 | fn swap_subseq(&mut self, subseq: &mut Seq); 395 | 396 | /// Replace elements with a subsequence. 397 | /// 398 | /// See [`subseq()`](Subseq::subseq()) to see which inputs are subsequence. 399 | /// 400 | /// **NOTE**: The subsequence must have one and only one candidate in the supersequence. 401 | /// 402 | /// It returns a subsequence consisting of the replaced elements. 403 | /// 404 | /// Hint: If you don't want to consume the input tuple, 405 | /// then what you are looking for might be [`swap_subseq()`](Subseq::swap_subseq()). 406 | /// 407 | /// Hint: The [`TupleLike`] trait provides the [`replace_subseq()`](TupleLike::replace_subseq()) method as 408 | /// the wrapper for this [`replace_subseq()`](Subseq::replace_subseq()) method. 409 | /// 410 | /// # Example 411 | /// 412 | /// ``` 413 | /// use tuplez::{tuple, TupleLike}; 414 | /// 415 | /// let mut tup = tuple!(1, Some("hello"), 2, Some(()), 3.14, 3); 416 | /// let replaced = tup.replace_subseq(tuple!(Some("world"), 9.8)); 417 | /// assert_eq!(tup, tuple!(1, Some("world"), 2, Some(()), 9.8, 3)); 418 | /// assert_eq!(replaced, tuple!(Some("hello"), 3.14)); 419 | /// ``` 420 | fn replace_subseq(&mut self, mut subseq: Seq) -> Seq { 421 | Subseq::swap_subseq(self, &mut subseq); 422 | subseq 423 | } 424 | } 425 | 426 | impl Subseq for Unit { 427 | fn subseq(self) -> Unit { 428 | Unit 429 | } 430 | fn subseq_ref(&self) -> ::AsRefOutput<'_> { 431 | Unit 432 | } 433 | fn subseq_mut(&mut self) -> ::AsMutOutput<'_> { 434 | Unit 435 | } 436 | fn swap_subseq(&mut self, _: &mut Unit) {} 437 | } 438 | 439 | impl Subseq, Used> for Tuple 440 | where 441 | Other1: TupleLike + Subseq, 442 | Other2: TupleLike, 443 | { 444 | fn subseq(self) -> Tuple { 445 | Tuple(self.0, Subseq::subseq(self.1)) 446 | } 447 | 448 | fn subseq_ref(&self) -> as TupleLike>::AsRefOutput<'_> { 449 | Tuple(&self.0, Subseq::subseq_ref(&self.1)) 450 | } 451 | 452 | fn subseq_mut(&mut self) -> as TupleLike>::AsMutOutput<'_> { 453 | Tuple(&mut self.0, Subseq::subseq_mut(&mut self.1)) 454 | } 455 | 456 | fn swap_subseq(&mut self, subseq: &mut Tuple) { 457 | std::mem::swap(&mut self.0, &mut subseq.0); 458 | Subseq::swap_subseq(&mut self.1, &mut subseq.1); 459 | } 460 | } 461 | 462 | impl Subseq> for Tuple 463 | where 464 | T: TupleLike, 465 | Other: TupleLike + Subseq, 466 | { 467 | fn subseq(self) -> T { 468 | Subseq::subseq(self.1) 469 | } 470 | 471 | fn subseq_ref(&self) -> ::AsRefOutput<'_> { 472 | Subseq::subseq_ref(&self.1) 473 | } 474 | 475 | fn subseq_mut(&mut self) -> ::AsMutOutput<'_> { 476 | Subseq::subseq_mut(&mut self.1) 477 | } 478 | 479 | fn swap_subseq(&mut self, subseq: &mut T) { 480 | Subseq::swap_subseq(&mut self.1, subseq); 481 | } 482 | } 483 | 484 | /// Replace elements of a specific subsequence to another sequence 485 | /// that may be of different element types. 486 | pub trait SubseqMapReplace: Subseq 487 | where 488 | Seq: TupleLike, 489 | { 490 | /// The type of tuple that replace elements of a specific subsequence 491 | /// to another sequence that may be of different element types. 492 | type MapReplaceOutput: TupleLike; 493 | 494 | /// Replace elements of specific subsequence with another sequence 495 | /// that may be of different element types. 496 | /// 497 | /// The elements of new sequence is generated from the user-defined mapper. 498 | /// 499 | /// Check out [`Mapper`]’s documentation page to learn how to build a mapper. 500 | /// 501 | /// Hint: The [`TupleLike`] trait provides the [`map_replace_subseq()`](TupleLike::map_replace_subseq()) 502 | /// method as the wrapper for this [`map_replace_subseq()`](SubseqMapReplace::map_replace_subseq()) method. 503 | /// 504 | /// # Example 505 | /// 506 | /// ``` 507 | /// use std::fmt::Debug; 508 | /// use tuplez::{mapper, tuple, TupleLike, tuple_t}; 509 | /// 510 | /// let tup = tuple!(1, 3.14, "hello", [1, 2, 3]); 511 | /// let result = tup.map_replace_subseq::(mapper! { 512 | /// |x: f64| -> i32 { x as i32 } 513 | /// |x: [T; N]| -> String { format!("{x:?}") } 514 | /// }); 515 | /// assert_eq!(result, tuple!(1, 3, "hello", "[1, 2, 3]".to_string())) 516 | /// ``` 517 | fn map_replace_subseq(self, f: F) -> Self::MapReplaceOutput; 518 | } 519 | 520 | impl SubseqMapReplace for Unit { 521 | type MapReplaceOutput = Unit; 522 | 523 | fn map_replace_subseq(self, _: F) -> Self::MapReplaceOutput { 524 | Unit 525 | } 526 | } 527 | 528 | impl SubseqMapReplace, F, Used> 529 | for Tuple 530 | where 531 | Other1: TupleLike + SubseqMapReplace>::NextMapper, I>, 532 | Other2: TupleLike, 533 | F: Mapper, 534 | { 535 | type MapReplaceOutput = Tuple; 536 | 537 | fn map_replace_subseq(self, f: F) -> Self::MapReplaceOutput { 538 | let (output, next) = f.map(self.0); 539 | Tuple(output, SubseqMapReplace::map_replace_subseq(self.1, next)) 540 | } 541 | } 542 | 543 | impl SubseqMapReplace> for Tuple 544 | where 545 | T: TupleLike, 546 | Other: TupleLike + SubseqMapReplace, 547 | { 548 | type MapReplaceOutput = Tuple; 549 | 550 | fn map_replace_subseq(self, f: F) -> Self::MapReplaceOutput { 551 | Tuple(self.0, SubseqMapReplace::map_replace_subseq(self.1, f)) 552 | } 553 | } 554 | 555 | /// Search for contiguous subsequences of tuples. 556 | /// 557 | /// Unlike [`Subseq`], this trait requires that all elements of the subsequence are 558 | /// contiguous in the supersequence. 559 | /// 560 | /// The contiguous subsequence must have one and only one candidate in the supersequence. 561 | pub trait ConSubseq: TupleLike 562 | where 563 | Seq: TupleLike, 564 | { 565 | /// Take out a contiguous subsequence. 566 | /// 567 | /// Unlike [`subseq()`](Subseq::subseq()), this method requires that all elements of the subsequence are 568 | /// contiguous in the supersequence. Sometimes it can do things that [`subseq()`](Subseq::subseq()) can't. 569 | /// 570 | /// **NOTE**: The contiguous subsequence must have one and only one candidate in the supersequence. 571 | /// 572 | /// Add a type annotation to the contiguous subsequence to let [`con_subseq()`](ConSubseq::con_subseq()) know. 573 | /// 574 | /// Hint: The [`TupleLike`] trait provides the [`con_subseq()`](TupleLike::con_subseq()) method as the wrapper 575 | /// for this [`con_subseq()`](ConSubseq::con_subseq()) method. 576 | /// 577 | /// # Example 578 | /// 579 | /// ``` 580 | /// use tuplez::{tuple, TupleLike, tuple_t}; 581 | /// 582 | /// let tup = tuple!(12, "hello", 24, true, false); 583 | /// 584 | /// // For `subseq`, 4 candidates available: 585 | /// // `(12, true)`, 586 | /// // `(12, false)`, 587 | /// // `(24, true)`, 588 | /// // `(24, false)`, 589 | /// // so this cannot be compiled. 590 | /// // let subseq: tuple_t!(i32, bool) = tup.subseq(); 591 | /// 592 | /// // But for `con_subseq`,only `(24, true)` is a candidate. 593 | /// let subseq: tuple_t!(i32, bool) = tup.con_subseq(); 594 | /// assert_eq!(subseq, tuple!(24, true)); 595 | /// ``` 596 | fn con_subseq(self) -> Seq; 597 | 598 | /// Similar to [`con_subseq()`](ConSubseq::con_subseq()), 599 | /// but all its elements are immutable references to the supersequence's elements. 600 | /// 601 | /// **NOTE**: The contiguous subsequence must have one and only one candidate in the supersequence. 602 | /// 603 | /// Rust is almost impossible to infer generic types by the return type annotation, 604 | /// so you need to call it like: 605 | /// 606 | /// Hint: The [`TupleLike`] trait provides the [`con_subseq_ref()`](TupleLike::con_subseq_ref()) method 607 | /// as the wrapper for this [`con_subseq_ref()`](ConSubseq::con_subseq_ref()) method. 608 | /// 609 | /// ``` 610 | /// use tuplez::{tuple, TupleLike, tuple_t}; 611 | /// 612 | /// let tup = tuple!(12, "hello", vec![1, 2, 3], 24, 3.14, true); 613 | /// let subseq = tup.con_subseq_ref::(); 614 | /// assert_eq!(subseq, tuple!(&24, &3.14)); 615 | /// ``` 616 | fn con_subseq_ref(&self) -> Seq::AsRefOutput<'_>; 617 | 618 | /// Similar to [`con_subseq()`](ConSubseq::con_subseq()), 619 | /// but all its elements are mutable references to the supersequence's elements. 620 | /// 621 | /// **NOTE**: The contiguous subsequence must have one and only one candidate in the supersequence. 622 | /// 623 | /// Rust is almost impossible to infer generic types by the return type annotation, 624 | /// so you need to call it like: 625 | /// 626 | /// Hint: The [`TupleLike`] trait provides the [`con_subseq_mut()`](TupleLike::con_subseq_mut()) method 627 | /// as the wrapper for this [`con_subseq_mut()`](ConSubseq::con_subseq_mut()) method. 628 | /// 629 | /// ``` 630 | /// use tuplez::{get, tuple, TupleLike, tuple_t}; 631 | /// 632 | /// let mut tup = tuple!(12, "hello", vec![1, 2, 3], "world", 24, 36); 633 | /// let subseq = tup.con_subseq_mut::(); 634 | /// *get!(subseq; 0) = "rust"; 635 | /// *get!(subseq; 1) = 0; 636 | /// assert_eq!(tup, tuple!(12, "hello", vec![1, 2, 3], "rust", 0, 36)); 637 | /// ``` 638 | fn con_subseq_mut(&mut self) -> Seq::AsMutOutput<'_>; 639 | 640 | /// Swap elements with a contiguous subsequence. 641 | /// 642 | /// Unlike [`swap_subseq()`](Subseq::swap_subseq()), this method requires that all 643 | /// elements of the subsequence are contiguous in the supersequence. 644 | /// Sometimes it can do things that [`swap_subseq()`](Subseq::swap_subseq()) can't. 645 | /// 646 | /// **NOTE**: The contiguous subsequence must have one and only one candidate in the supersequence. 647 | /// 648 | /// Hint: The [`TupleLike`] trait provides the [`swap_con_subseq()`](TupleLike::swap_con_subseq()) method 649 | /// as the wrapper for this [`swap_con_subseq()`](ConSubseq::swap_con_subseq()) method. 650 | /// 651 | /// # Example 652 | /// 653 | /// ``` 654 | /// use tuplez::{tuple, TupleLike}; 655 | /// 656 | /// let mut tup = tuple!(1, Some("hello"), 2, Some(()), 3.14, 3); 657 | /// let mut tup2 = tuple!(4, None::<()>); 658 | /// tup.swap_con_subseq(&mut tup2); 659 | /// assert_eq!(tup, tuple!(1, Some("hello"), 4, None::<()>, 3.14, 3)); 660 | /// assert_eq!(tup2, tuple!(2, Some(()))); 661 | /// ``` 662 | fn swap_con_subseq(&mut self, subseq: &mut Seq); 663 | 664 | /// Replace elements with a contiguous subsequence. 665 | /// 666 | /// Unlike [`replace_subseq()`](Subseq::replace_subseq()), this method requires that 667 | /// all elements of the subsequence are contiguous in the supersequence. 668 | /// Sometimes it can do things that [`replace_subseq()`](Subseq::replace_subseq()) can't. 669 | /// 670 | /// **NOTE**: The contiguous subsequence must have one and only one candidate in the supersequence. 671 | /// 672 | /// It returns a contiguous subsequence consisting of the replaced elements. 673 | /// 674 | /// Hint: If you don't want to consume the input tuple, 675 | /// then what you are looking for might be [`swap_con_subseq()`](TupleLike::swap_con_subseq()). 676 | /// 677 | /// Hint: The [`TupleLike`] trait provides the [`replace_con_subseq()`](TupleLike::replace_con_subseq()) method 678 | /// as the wrapper for this [`replace_con_subseq()`](ConSubseq::replace_con_subseq()) method. 679 | /// 680 | /// # Example 681 | /// 682 | /// ``` 683 | /// use tuplez::{tuple, TupleLike}; 684 | /// 685 | /// let mut tup = tuple!(1, Some("hello"), 2, Some(()), 3.14, 3); 686 | /// let replaced = tup.replace_con_subseq(tuple!(4, None::<()>)); 687 | /// assert_eq!(tup, tuple!(1, Some("hello"), 4, None::<()>, 3.14, 3)); 688 | /// assert_eq!(replaced, tuple!(2, Some(()))); 689 | /// ``` 690 | fn replace_con_subseq(&mut self, mut subseq: Seq) -> Seq { 691 | ConSubseq::swap_con_subseq(self, &mut subseq); 692 | subseq 693 | } 694 | } 695 | 696 | impl ConSubseq for Unit { 697 | fn con_subseq(self) -> Unit { 698 | Unit 699 | } 700 | 701 | fn con_subseq_ref(&self) -> ::AsRefOutput<'_> { 702 | Unit 703 | } 704 | 705 | fn con_subseq_mut(&mut self) -> ::AsMutOutput<'_> { 706 | Unit 707 | } 708 | 709 | fn swap_con_subseq(&mut self, _: &mut Unit) {} 710 | } 711 | 712 | impl ConSubseq> for Tuple 713 | where 714 | T: TupleLike, 715 | Other: ConSubseq, 716 | { 717 | fn con_subseq(self) -> T { 718 | ConSubseq::con_subseq(self.1) 719 | } 720 | 721 | fn con_subseq_ref(&self) -> ::AsRefOutput<'_> { 722 | ConSubseq::con_subseq_ref(&self.1) 723 | } 724 | 725 | fn con_subseq_mut(&mut self) -> ::AsMutOutput<'_> { 726 | ConSubseq::con_subseq_mut(&mut self.1) 727 | } 728 | 729 | fn swap_con_subseq(&mut self, subseq: &mut T) { 730 | ConSubseq::swap_con_subseq(&mut self.1, subseq) 731 | } 732 | } 733 | 734 | impl ConSubseq, Used> for Tuple 735 | where 736 | Other: ConSubseq, 737 | { 738 | fn con_subseq(self) -> Tuple { 739 | Tuple(self.0, Unit) 740 | } 741 | 742 | fn con_subseq_ref(&self) -> as TupleLike>::AsRefOutput<'_> { 743 | Tuple(&self.0, Unit) 744 | } 745 | 746 | fn con_subseq_mut(&mut self) -> as TupleLike>::AsMutOutput<'_> { 747 | Tuple(&mut self.0, Unit) 748 | } 749 | 750 | fn swap_con_subseq(&mut self, subseq: &mut Tuple) { 751 | std::mem::swap(&mut self.0, &mut subseq.0); 752 | } 753 | } 754 | 755 | impl ConSubseq>, Used> 756 | for Tuple 757 | where 758 | Other1: ConSubseq, Used>, 759 | Other2: TupleLike, 760 | { 761 | fn con_subseq(self) -> Tuple> { 762 | Tuple(self.0, ConSubseq::con_subseq(self.1)) 763 | } 764 | 765 | fn con_subseq_ref( 766 | &self, 767 | ) -> > as TupleLike>::AsRefOutput<'_> { 768 | Tuple(&self.0, ConSubseq::con_subseq_ref(&self.1)) 769 | } 770 | 771 | fn con_subseq_mut( 772 | &mut self, 773 | ) -> > as TupleLike>::AsMutOutput<'_> { 774 | Tuple(&mut self.0, ConSubseq::con_subseq_mut(&mut self.1)) 775 | } 776 | 777 | fn swap_con_subseq(&mut self, subseq: &mut Tuple>) { 778 | std::mem::swap(&mut self.0, &mut subseq.0); 779 | ConSubseq::swap_con_subseq(&mut self.1, &mut subseq.1); 780 | } 781 | } 782 | 783 | /// Replace elements of a specific contiguous subsequence to another sequence 784 | /// that may be of different element types. 785 | pub trait ConSubseqMapReplace: ConSubseq 786 | where 787 | Seq: TupleLike, 788 | { 789 | /// The type of tuple that replace elements of a specific contiguous subsequence 790 | /// to another sequence that may be of different element types. 791 | type MapReplaceOutput: TupleLike; 792 | 793 | /// Replace elements of specific contiguous subsequence with another sequence 794 | /// that may be of different element types. 795 | /// 796 | /// The elements of new sequence is generated from the user-defined mapper. 797 | /// 798 | /// Check out [`Mapper`]’s documentation page to learn how to build a mapper. 799 | /// 800 | /// Hint: The [`TupleLike`] trait provides the [`map_replace_con_subseq()`](TupleLike::map_replace_con_subseq()) 801 | /// method as the wrapper for this [`map_replace_con_subseq()`](ConSubseqMapReplace::map_replace_con_subseq()) method. 802 | /// 803 | /// # Example 804 | /// 805 | /// ``` 806 | /// use tuplez::{mapper, tuple, TupleLike, tuple_t}; 807 | /// 808 | /// let tup = tuple!("1", "2", "3", true, false, true); 809 | /// let result = tup.map_replace_con_subseq::(mapper! { 810 | /// |x: &str| -> i32 { x.parse().unwrap() } 811 | /// |x: bool| -> bool { !x } 812 | /// }); 813 | /// assert_eq!(result, tuple!("1", "2", 3, false, true, true)); 814 | /// ``` 815 | fn map_replace_con_subseq(self, f: F) -> Self::MapReplaceOutput; 816 | } 817 | 818 | impl ConSubseqMapReplace for Unit { 819 | type MapReplaceOutput = Unit; 820 | 821 | fn map_replace_con_subseq(self, _: F) -> Self::MapReplaceOutput { 822 | Unit 823 | } 824 | } 825 | 826 | impl ConSubseqMapReplace> for Tuple 827 | where 828 | T: TupleLike, 829 | Other: ConSubseqMapReplace, 830 | { 831 | type MapReplaceOutput = Tuple; 832 | fn map_replace_con_subseq(self, f: F) -> Self::MapReplaceOutput { 833 | Tuple( 834 | self.0, 835 | ConSubseqMapReplace::map_replace_con_subseq(self.1, f), 836 | ) 837 | } 838 | } 839 | 840 | impl ConSubseqMapReplace, F, Used> for Tuple 841 | where 842 | Other: ConSubseqMapReplace>::NextMapper, I>, 843 | F: Mapper, 844 | { 845 | type MapReplaceOutput = Tuple; 846 | 847 | fn map_replace_con_subseq(self, f: F) -> Self::MapReplaceOutput { 848 | Tuple(f.map(self.0).0, self.1) 849 | } 850 | } 851 | 852 | impl 853 | ConSubseqMapReplace>, F, Used> for Tuple 854 | where 855 | Other1: ConSubseqMapReplace, >::NextMapper, Used>, 856 | Other2: TupleLike, 857 | F: Mapper, 858 | { 859 | type MapReplaceOutput = Tuple; 860 | 861 | fn map_replace_con_subseq(self, f: F) -> Self::MapReplaceOutput { 862 | let (output, next) = f.map(self.0); 863 | Tuple( 864 | output, 865 | ConSubseqMapReplace::map_replace_con_subseq(self.1, next), 866 | ) 867 | } 868 | } 869 | 870 | #[cfg(test)] 871 | mod test { 872 | #[test] 873 | fn test_unit_subsequence() { 874 | use tuplez::{search::ConSubseq, search::Subseq, tuple, tuple_t}; 875 | 876 | let tup = tuple!(1, 2.5, "hello"); 877 | let subseq: tuple_t!() = tup.subseq(); 878 | assert_eq!(subseq, tuple!()); 879 | let subseq: tuple_t!() = tup.con_subseq(); 880 | assert_eq!(subseq, tuple!()); 881 | } 882 | } 883 | -------------------------------------------------------------------------------- /src/tupleize.rs: -------------------------------------------------------------------------------- 1 | /// Convert between [`Tuple`](crate::Tuple) and struct types. 2 | /// 3 | /// If there are no special requirements then you should use [the derive marco](derive@crate::Tupleize). 4 | /// 5 | /// # Example 6 | /// ``` 7 | /// use tuplez::{tuple, Tupleize}; 8 | /// 9 | /// #[derive(Tupleize, Debug, PartialEq, Eq)] 10 | /// struct Person { 11 | /// name: &'static str, 12 | /// age: u32, 13 | /// meta: Meta, 14 | /// } 15 | /// 16 | /// let john = Person { 17 | /// name: "John", 18 | /// age: 21, 19 | /// meta: vec![9, 8, 7], 20 | /// }; 21 | /// assert_eq!(john.tupleize(), tuple!("John", 21, vec![9, 8, 7])); 22 | /// 23 | /// let smith = Person { 24 | /// name: "Smith", 25 | /// age: 49, 26 | /// meta: Some(88.88), 27 | /// }; 28 | /// assert_eq!(smith, Person::from(tuple!("Smith", 49, Some(88.88)))); 29 | /// ``` 30 | pub trait Tupleize: From + Into { 31 | /// The equivalent tuple type with the same number of elements, the same element types, 32 | /// and the same element order as the struct. 33 | type Equivalent: From; 34 | 35 | /// Convert from self into a tuple. 36 | fn tupleize(self) -> Self::Equivalent { 37 | >::from(self) 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/uninit.rs: -------------------------------------------------------------------------------- 1 | //! Provide operations on tuples consisting of [`MaybeUninit`] elements. 2 | 3 | use crate::{search::*, Tuple, TupleLike, Unit}; 4 | use std::mem::MaybeUninit; 5 | 6 | /// Provide operations on tuples consisting of [`MaybeUninit`] elements. 7 | pub trait Uninit: TupleLike { 8 | /// The type of the tuple consisting of values of each [`MaybeUninit`] elements. 9 | type Initialized: TupleLike; 10 | 11 | /// Extract the values of a tuple consisting of [`MaybeUninit`] elements. 12 | /// 13 | /// Hint: The [`TupleLike`] trait provides the [`uninit_assume_init()`](TupleLike::uninit_assume_init()) 14 | /// method as the wrapper for this [`assume_init()`](Uninit::assume_init()) method. 15 | /// 16 | /// # Safety 17 | /// 18 | /// Same as [`MaybeUninit::assume_init()`](MaybeUninit::assume_init()). 19 | /// 20 | /// # Example 21 | /// 22 | /// ``` 23 | /// use tuplez::{tuple, TupleLike, tuple_t}; 24 | /// 25 | /// let mut uninit = ::uninit(); 26 | /// uninit.uninit_write_one(12); 27 | /// uninit.uninit_write_one(true); 28 | /// uninit.uninit_write_one("hello"); 29 | /// let tup = unsafe { uninit.uninit_assume_init() }; 30 | /// assert_eq!(tup, tuple!(12, true, "hello")); 31 | /// ``` 32 | unsafe fn assume_init(self) -> Self::Initialized; 33 | 34 | /// Read the values of a tuple consisting of [`MaybeUninit`] elements. 35 | /// 36 | /// Hint: The [`TupleLike`] trait provides the [`uninit_assume_init_read()`](TupleLike::uninit_assume_init_read()) 37 | /// method as the wrapper for this [`assume_init_read()`](Uninit::assume_init_read()) method. 38 | /// 39 | /// # Safety 40 | /// 41 | /// Same as [`MaybeUninit::assume_init_read()`](MaybeUninit::assume_init_read()). 42 | /// 43 | /// # Example 44 | /// 45 | /// ``` 46 | /// use tuplez::{tuple, TupleLike, tuple_t}; 47 | /// 48 | /// let mut uninit = >)>::uninit(); 49 | /// uninit.uninit_write_one(12); 50 | /// uninit.uninit_write_one(None); 51 | /// let tup1 = unsafe { uninit.uninit_assume_init_read() }; 52 | /// // SAFETY: `i32` implements `Copy`, duplicating a `None` value is safe. 53 | /// let tup2 = unsafe { uninit.uninit_assume_init_read() }; 54 | /// assert_eq!(tup1, tup2); 55 | /// ``` 56 | unsafe fn assume_init_read(&self) -> Self::Initialized; 57 | 58 | /// Get immutable references to values of a tuple consisting of [`MaybeUninit`] elements. 59 | /// 60 | /// Hint: The [`TupleLike`] trait provides the [`uninit_assume_init_ref()`](TupleLike::uninit_assume_init_ref()) 61 | /// method as the wrapper for this [`assume_init_ref()`](Uninit::assume_init_ref()) method. 62 | /// 63 | /// # Safety 64 | /// 65 | /// Same as [`MaybeUninit::assume_init_ref()`](MaybeUninit::assume_init_ref()). 66 | /// 67 | /// # Example 68 | /// 69 | /// ``` 70 | /// use tuplez::{get, tuple, TupleLike, tuple_t}; 71 | /// 72 | /// let mut uninit = )>::uninit(); 73 | /// uninit.uninit_write_one(12); 74 | /// uninit.uninit_write_one(vec![1, 2, 3]); 75 | /// let tup_ref = unsafe { uninit.uninit_assume_init_ref() }; 76 | /// assert_eq!(get!(tup_ref; 0), &12); 77 | /// assert_eq!(get!(tup_ref; 1), &vec![1, 2, 3]); 78 | /// unsafe { uninit.uninit_assume_init_drop(); } 79 | /// ``` 80 | unsafe fn assume_init_ref(&self) -> ::AsRefOutput<'_>; 81 | 82 | /// Get mutable references to values of a tuple consisting of [`MaybeUninit`] elements. 83 | /// 84 | /// Hint: The [`TupleLike`] trait provides the [`uninit_assume_init_mut()`](TupleLike::uninit_assume_init_mut()) 85 | /// method as the wrapper for this [`assume_init_mut()`](Uninit::assume_init_mut()) method. 86 | /// 87 | /// # Safety 88 | /// 89 | /// Same as [`MaybeUninit::assume_init_mut()`](MaybeUninit::assume_init_mut()). 90 | /// 91 | /// # Example 92 | /// 93 | /// ``` 94 | /// use tuplez::{get, tuple, TupleLike, tuple_t}; 95 | /// 96 | /// let mut uninit = )>::uninit(); 97 | /// uninit.uninit_write_one(12); 98 | /// uninit.uninit_write_one(vec![1, 2, 3]); 99 | /// let tup_mut = unsafe { uninit.uninit_assume_init_mut() }; 100 | /// *get!(tup_mut; 0) += 1; 101 | /// get!(tup_mut; 1).push(4); 102 | /// let tup = unsafe { uninit.uninit_assume_init() }; 103 | /// assert_eq!(tup, tuple!(13, vec![1, 2, 3, 4])); 104 | /// ``` 105 | unsafe fn assume_init_mut(&mut self) -> ::AsMutOutput<'_>; 106 | 107 | /// Drop values in place for a tuple consisting of [`MaybeUninit`] elements. 108 | /// 109 | /// Hint: The [`TupleLike`] trait provides the [`uninit_assume_init_drop()`](TupleLike::uninit_assume_init_drop()) 110 | /// method as the wrapper for this [`assume_init_drop()`](Uninit::assume_init_drop()) method. 111 | /// 112 | /// # Safety 113 | /// 114 | /// Same as [`MaybeUninit::assume_init_drop()`](MaybeUninit::assume_init_drop()). 115 | unsafe fn assume_init_drop(&mut self); 116 | 117 | /// Get points to values of a tuple consisting of [`MaybeUninit`] elements. 118 | /// 119 | /// Hint: The [`TupleLike`] trait provides the [`uninit_as_ptr()`](TupleLike::uninit_as_ptr()) 120 | /// method as the wrapper for this [`as_ptr()`](Uninit::as_ptr()) method. 121 | /// 122 | /// # Example 123 | /// 124 | /// ``` 125 | /// use tuplez::{get, TupleLike, tuple_t}; 126 | /// 127 | /// let mut uninit = )>::uninit(); 128 | /// uninit.uninit_write_one(12); 129 | /// uninit.uninit_write_one(vec![1, 2, 3]); 130 | /// let v = unsafe { &*get!(uninit.uninit_as_ptr(); 1) }; 131 | /// assert_eq!(v.len(), 3); 132 | /// unsafe { uninit.uninit_assume_init_drop(); } 133 | /// ``` 134 | fn as_ptr(&self) -> ::AsPtrOutput; 135 | 136 | /// Get mutable points to values of a tuple consisting of [`MaybeUninit`] elements. 137 | /// 138 | /// Hint: The [`TupleLike`] trait provides the [`uninit_as_mut_ptr()`](TupleLike::uninit_as_mut_ptr()) 139 | /// method as the wrapper for this [`as_mut_ptr()`](Uninit::as_mut_ptr()) method. 140 | /// 141 | /// # Example 142 | /// 143 | /// ``` 144 | /// use tuplez::{get, TupleLike, tuple_t}; 145 | /// 146 | /// let mut uninit = )>::uninit(); 147 | /// uninit.uninit_write_one(12); 148 | /// uninit.uninit_write_one(vec![1, 2, 3]); 149 | /// let v = unsafe { &mut *get!(uninit.uninit_as_mut_ptr(); 1) }; 150 | /// v.push(4); 151 | /// assert_eq!(v.len(), 4); 152 | /// unsafe { uninit.uninit_assume_init_drop(); } 153 | /// ``` 154 | fn as_mut_ptr(&mut self) -> ::AsMutPtrOutput; 155 | 156 | /// Set values to a tuple consisting of [`MaybeUninit`] elements. 157 | /// 158 | /// Similar to [`MaybeUninit::write()`](MaybeUninit::write()), 159 | /// this overwrites any previous value without dropping it. 160 | /// 161 | /// Hint: The [`TupleLike`] trait provides the [`uninit_write()`](TupleLike::uninit_write()) 162 | /// method as the wrapper for this [`write()`](Uninit::write()) method. 163 | /// 164 | /// # Example 165 | /// 166 | /// ``` 167 | /// use tuplez::{tuple, TupleLike, tuple_t}; 168 | /// 169 | /// let mut uninit = ::uninit(); 170 | /// uninit.uninit_write(tuple!(12, true, "hello")); 171 | /// let tup = unsafe { uninit.uninit_assume_init() }; 172 | /// assert_eq!(tup, tuple!(12, true, "hello")); 173 | /// ``` 174 | fn write( 175 | &mut self, 176 | init: Self::Initialized, 177 | ) -> ::AsMutOutput<'_>; 178 | } 179 | 180 | impl Uninit for Unit { 181 | type Initialized = Unit; 182 | 183 | unsafe fn assume_init(self) -> Self::Initialized { 184 | self 185 | } 186 | 187 | unsafe fn assume_init_read(&self) -> Self::Initialized { 188 | Unit 189 | } 190 | 191 | unsafe fn assume_init_ref(&self) -> ::AsRefOutput<'_> { 192 | Unit 193 | } 194 | 195 | unsafe fn assume_init_mut(&mut self) -> ::AsMutOutput<'_> { 196 | Unit 197 | } 198 | 199 | unsafe fn assume_init_drop(&mut self) {} 200 | 201 | fn as_ptr(&self) -> ::AsPtrOutput { 202 | Unit 203 | } 204 | 205 | fn as_mut_ptr(&mut self) -> ::AsMutPtrOutput { 206 | Unit 207 | } 208 | 209 | fn write(&mut self, _: Self::Initialized) -> ::AsMutOutput<'_> { 210 | Unit 211 | } 212 | } 213 | 214 | impl Uninit for Tuple, Other> 215 | where 216 | Other: Uninit, 217 | { 218 | type Initialized = Tuple; 219 | 220 | unsafe fn assume_init(self) -> Self::Initialized { 221 | Tuple(self.0.assume_init(), Uninit::assume_init(self.1)) 222 | } 223 | 224 | unsafe fn assume_init_read(&self) -> Self::Initialized { 225 | Tuple(self.0.assume_init_read(), Uninit::assume_init_read(&self.1)) 226 | } 227 | 228 | unsafe fn assume_init_ref(&self) -> ::AsRefOutput<'_> { 229 | Tuple(self.0.assume_init_ref(), Uninit::assume_init_ref(&self.1)) 230 | } 231 | 232 | unsafe fn assume_init_mut(&mut self) -> ::AsMutOutput<'_> { 233 | Tuple( 234 | self.0.assume_init_mut(), 235 | Uninit::assume_init_mut(&mut self.1), 236 | ) 237 | } 238 | 239 | unsafe fn assume_init_drop(&mut self) { 240 | self.0.assume_init_drop(); 241 | Uninit::assume_init_drop(&mut self.1); 242 | } 243 | 244 | fn as_ptr(&self) -> ::AsPtrOutput { 245 | Tuple(self.0.as_ptr(), Uninit::as_ptr(&self.1)) 246 | } 247 | 248 | fn as_mut_ptr(&mut self) -> ::AsMutPtrOutput { 249 | Tuple(self.0.as_mut_ptr(), Uninit::as_mut_ptr(&mut self.1)) 250 | } 251 | 252 | fn write( 253 | &mut self, 254 | init: Self::Initialized, 255 | ) -> ::AsMutOutput<'_> { 256 | Tuple(self.0.write(init.0), Uninit::write(&mut self.1, init.1)) 257 | } 258 | } 259 | 260 | /// Provide subsequence operations on tuples consisting of [`MaybeUninit`] elements. 261 | pub trait UninitSubseq: Subseq 262 | where 263 | Seq: TupleLike, 264 | { 265 | /// The type of tuple consisting of elements not in the subsequence and 266 | /// values of each [`MaybeUninit`] elements in the subsequence. 267 | type PartiallyInitialized; 268 | 269 | /// Extract values of a specific subsequence consisting of [`MaybeUninit`] elements. 270 | /// 271 | /// Hint: The [`TupleLike`] trait provides the [`uninit_assume_init_subseq()`](TupleLike::uninit_assume_init_subseq()) 272 | /// method as the wrapper for this [`assume_init_subseq()`](UninitSubseq::assume_init_subseq()) method. 273 | /// 274 | /// # Safety 275 | /// 276 | /// Same as [`MaybeUninit::assume_init()`](MaybeUninit::assume_init()). 277 | /// 278 | /// # Example 279 | /// 280 | /// ``` 281 | /// use std::mem::MaybeUninit; 282 | /// use tuplez::{get, tuple, TupleLike, tuple_t}; 283 | /// 284 | /// let mut tup = tuple!( 285 | /// 12, 286 | /// MaybeUninit::::zeroed(), 287 | /// MaybeUninit::<&str>::uninit(), 288 | /// MaybeUninit::>::uninit(), 289 | /// false, 290 | /// ); 291 | /// tup.uninit_write_one(vec![1, 2, 3]); 292 | /// let part_init = unsafe { 293 | /// tup.uninit_assume_init_subseq::), _>() 294 | /// }; 295 | /// assert_eq!(get!(part_init; 1), 0); 296 | /// assert_eq!(get!(part_init; 3), vec![1, 2, 3]); 297 | /// let _: tuple_t!(i32, i32, MaybeUninit<&str>, Vec, bool) = part_init; 298 | /// ``` 299 | unsafe fn assume_init_subseq(self) -> Self::PartiallyInitialized; 300 | 301 | /// Read the values of a specific subsequence consisting of [`MaybeUninit`] elements. 302 | /// 303 | /// Hint: The [`TupleLike`] trait provides the 304 | /// [`uninit_assume_init_read_subseq()`](TupleLike::uninit_assume_init_read_subseq()) 305 | /// method as the wrapper for this [`assume_init_read_subseq()`](UninitSubseq::assume_init_read_subseq()) method. 306 | /// 307 | /// # Safety 308 | /// 309 | /// Same as [`MaybeUninit::assume_init_read()`](MaybeUninit::assume_init_read()). 310 | /// 311 | /// # Example 312 | /// 313 | /// ``` 314 | /// use std::mem::MaybeUninit; 315 | /// use tuplez::{tuple, TupleLike, tuple_t}; 316 | /// 317 | /// let mut tup = tuple!( 318 | /// 12, 319 | /// MaybeUninit::::zeroed(), 320 | /// MaybeUninit::<&str>::uninit(), 321 | /// MaybeUninit::>::uninit(), 322 | /// false, 323 | /// ); 324 | /// tup.uninit_write_one(vec![1, 2, 3]); 325 | /// let inited = unsafe { 326 | /// tup.uninit_assume_init_read_subseq::), _>() 327 | /// }; 328 | /// assert_eq!(inited, tuple!(0, vec![1, 2, 3])); 329 | /// ``` 330 | unsafe fn assume_init_read_subseq(&self) -> Seq; 331 | 332 | /// Get immutable references to values of a specific subsequence 333 | /// consisting of [`MaybeUninit`] elements. 334 | /// 335 | /// Hint: The [`TupleLike`] trait provides the 336 | /// [`uninit_assume_init_ref_subseq()`](TupleLike::uninit_assume_init_ref_subseq()) 337 | /// method as the wrapper for this [`assume_init_ref_subseq()`](UninitSubseq::assume_init_ref_subseq()) method. 338 | /// 339 | /// # Safety 340 | /// 341 | /// Same as [`MaybeUninit::assume_init_ref()`](MaybeUninit::assume_init_ref()). 342 | /// 343 | /// # Example 344 | /// 345 | /// ``` 346 | /// use std::mem::MaybeUninit; 347 | /// use tuplez::{tuple, TupleLike, tuple_t}; 348 | /// 349 | /// let mut tup = tuple!( 350 | /// 12, 351 | /// MaybeUninit::::zeroed(), 352 | /// MaybeUninit::<&str>::uninit(), 353 | /// MaybeUninit::>::uninit(), 354 | /// false, 355 | /// ); 356 | /// tup.uninit_write_one(vec![1, 2, 3]); 357 | /// let inited_ref = unsafe { 358 | /// tup.uninit_assume_init_ref_subseq::), _>() 359 | /// }; 360 | /// assert_eq!(inited_ref, tuple!(&0, &vec![1, 2, 3])); 361 | /// unsafe { tup.uninit_assume_init_drop_subseq::), _>() }; 362 | /// ``` 363 | unsafe fn assume_init_ref_subseq(&self) -> ::AsRefOutput<'_>; 364 | 365 | /// Get mutable references to values of a specific subsequence 366 | /// consisting of [`MaybeUninit`] elements. 367 | /// 368 | /// Hint: The [`TupleLike`] trait provides the 369 | /// [`uninit_assume_init_mut_subseq()`](TupleLike::uninit_assume_init_mut_subseq()) 370 | /// method as the wrapper for this [`assume_init_mut_subseq()`](UninitSubseq::assume_init_mut_subseq()) method. 371 | /// 372 | /// # Safety 373 | /// 374 | /// Same as [`MaybeUninit::assume_init_mut()`](MaybeUninit::assume_init_mut()). 375 | /// 376 | /// # Example 377 | /// 378 | /// ``` 379 | /// use std::mem::MaybeUninit; 380 | /// use tuplez::{get, tuple, TupleLike, tuple_t}; 381 | /// 382 | /// let mut tup = tuple!( 383 | /// 12, 384 | /// MaybeUninit::::zeroed(), 385 | /// MaybeUninit::<&str>::uninit(), 386 | /// MaybeUninit::>::uninit(), 387 | /// false, 388 | /// ); 389 | /// tup.uninit_write_one(vec![1, 2, 3]); 390 | /// let inited_mut = unsafe { 391 | /// tup.uninit_assume_init_mut_subseq::), _>() 392 | /// }; 393 | /// *get!(inited_mut; 0) += 1; 394 | /// get!(inited_mut; 1).push(4); 395 | /// assert_eq!(inited_mut, tuple!(&mut 1, &mut vec![1, 2, 3, 4])); 396 | /// unsafe { tup.uninit_assume_init_drop_subseq::), _>() }; 397 | /// ``` 398 | unsafe fn assume_init_mut_subseq(&mut self) -> ::AsMutOutput<'_>; 399 | 400 | /// Get pointers to values of a specific subsequence 401 | /// consisting of [`MaybeUninit`] elements. 402 | /// 403 | /// Hint: The [`TupleLike`] trait provides the [`uninit_subseq_as_ptr()`](TupleLike::uninit_subseq_as_ptr()) 404 | /// method as the wrapper for this [`subseq_as_ptr()`](UninitSubseq::subseq_as_ptr()) method. 405 | /// 406 | /// # Example 407 | /// 408 | /// ``` 409 | /// use std::mem::MaybeUninit; 410 | /// use tuplez::{get, tuple, TupleLike, tuple_t}; 411 | /// 412 | /// let mut tup = tuple!( 413 | /// 12, 414 | /// MaybeUninit::::zeroed(), 415 | /// MaybeUninit::<&str>::uninit(), 416 | /// MaybeUninit::>::uninit(), 417 | /// false, 418 | /// ); 419 | /// tup.uninit_write_one(vec![1, 2, 3]); 420 | /// let inited_ptr = tup.uninit_subseq_as_ptr::), _>(); 421 | /// unsafe { 422 | /// assert_eq!(*get!(inited_ptr; 0), 0); 423 | /// assert_eq!(*get!(inited_ptr; 1), vec![1, 2, 3]); 424 | /// tup.uninit_assume_init_drop_subseq::), _>(); 425 | /// } 426 | /// ``` 427 | fn subseq_as_ptr(&self) -> ::AsPtrOutput; 428 | 429 | /// Get mutable pointers to values of a specific subsequence 430 | /// consisting of [`MaybeUninit`] elements. 431 | /// 432 | /// Hint: The [`TupleLike`] trait provides the 433 | /// [`uninit_subseq_as_mut_ptr()`](TupleLike::uninit_subseq_as_mut_ptr()) 434 | /// method as the wrapper for this [`subseq_as_mut_ptr()`](UninitSubseq::subseq_as_mut_ptr()) method. 435 | /// 436 | /// # Example 437 | /// 438 | /// ``` 439 | /// use std::mem::MaybeUninit; 440 | /// use tuplez::{get, tuple, TupleLike, tuple_t}; 441 | /// 442 | /// let mut tup = tuple!( 443 | /// 12, 444 | /// MaybeUninit::::zeroed(), 445 | /// MaybeUninit::<&str>::uninit(), 446 | /// MaybeUninit::>::uninit(), 447 | /// false, 448 | /// ); 449 | /// tup.uninit_write_one(vec![1, 2, 3]); 450 | /// let inited_ptr = tup.uninit_subseq_as_mut_ptr::), _>(); 451 | /// unsafe { 452 | /// *get!(inited_ptr; 0) += 1; 453 | /// (*get!(inited_ptr; 1)).push(4); 454 | /// assert_eq!(*get!(inited_ptr; 0), 1); 455 | /// assert_eq!(*get!(inited_ptr; 1), vec![1, 2, 3, 4]); 456 | /// tup.uninit_assume_init_drop_subseq::), _>(); 457 | /// } 458 | /// ``` 459 | fn subseq_as_mut_ptr(&mut self) -> ::AsMutPtrOutput; 460 | 461 | /// Set values to a subsequence consisting of [`MaybeUninit`] elements. 462 | /// 463 | /// **NOTE**: The subsequence must have one and only one candidate in the supersequence. 464 | /// 465 | /// Similar to [`MaybeUninit::write()`](MaybeUninit::write()), 466 | /// this overwrites any previous value without dropping it. 467 | ///Hint: The [`TupleLike`] trait provides the [`uninit_write_subseq()`](TupleLike::uninit_write_subseq()) 468 | /// method as the wrapper for this [`write_subseq()`](UninitSubseq::write_subseq()) method. 469 | /// Hint: The [`TupleLike`] trait provides the [`uninit_write_subseq()`](TupleLike::uninit_write_subseq()) 470 | /// method as the wrapper for this [`write_subseq()`](UninitSubseq::write_subseq()) method. 471 | /// 472 | /// # Example 473 | /// 474 | /// ``` 475 | /// use tuplez::{tuple, TupleLike, tuple_t}; 476 | /// 477 | /// let mut uninit = ::uninit(); 478 | /// uninit.uninit_write_one(true); 479 | /// uninit.uninit_write_subseq(tuple!(12, "hello")); 480 | /// let tup = unsafe { uninit.uninit_assume_init() }; 481 | /// assert_eq!(tup, tuple!(12, true, "hello")); 482 | /// ``` 483 | fn write_subseq(&mut self, subseq: Seq) -> Seq::AsMutOutput<'_>; 484 | 485 | /// Drop values in place for a subsequence consisting of [`MaybeUninit`] elements. 486 | /// 487 | /// **NOTE**: The subsequence must have one and only one candidate in the supersequence. 488 | /// 489 | /// Hint: The [`TupleLike`] trait provides the [`uninit_assume_init_drop_subseq()`](TupleLike::uninit_assume_init_drop_subseq()) 490 | /// method as the wrapper for this [`assume_init_drop_subseq()`](UninitSubseq::assume_init_drop_subseq()) method. 491 | /// 492 | /// # Safety 493 | /// 494 | /// Same as [`MaybeUninit::assume_init_drop()`](MaybeUninit::assume_init_drop()). 495 | unsafe fn assume_init_drop_subseq(&mut self); 496 | } 497 | 498 | impl UninitSubseq for Unit { 499 | type PartiallyInitialized = Unit; 500 | 501 | unsafe fn assume_init_subseq(self) -> Self::PartiallyInitialized { 502 | Unit 503 | } 504 | 505 | unsafe fn assume_init_read_subseq(&self) -> Unit { 506 | Unit 507 | } 508 | 509 | unsafe fn assume_init_ref_subseq(&self) -> ::AsRefOutput<'_> { 510 | Unit 511 | } 512 | 513 | unsafe fn assume_init_mut_subseq(&mut self) -> ::AsMutOutput<'_> { 514 | Unit 515 | } 516 | 517 | fn subseq_as_ptr(&self) -> ::AsPtrOutput { 518 | Unit 519 | } 520 | 521 | fn subseq_as_mut_ptr(&mut self) -> ::AsMutPtrOutput { 522 | Unit 523 | } 524 | 525 | fn write_subseq(&mut self, _: Unit) -> ::AsMutOutput<'_> { 526 | Unit 527 | } 528 | 529 | unsafe fn assume_init_drop_subseq(&mut self) {} 530 | } 531 | 532 | impl UninitSubseq, Used> 533 | for Tuple, Other1> 534 | where 535 | Other2: TupleLike, 536 | Other1: UninitSubseq, 537 | { 538 | type PartiallyInitialized = Tuple; 539 | 540 | unsafe fn assume_init_subseq(self) -> Self::PartiallyInitialized { 541 | Tuple( 542 | self.0.assume_init(), 543 | UninitSubseq::assume_init_subseq(self.1), 544 | ) 545 | } 546 | 547 | unsafe fn assume_init_read_subseq(&self) -> Tuple { 548 | Tuple( 549 | self.0.assume_init_read(), 550 | UninitSubseq::assume_init_read_subseq(&self.1), 551 | ) 552 | } 553 | 554 | unsafe fn assume_init_ref_subseq( 555 | &self, 556 | ) -> as TupleLike>::AsRefOutput<'_> { 557 | Tuple( 558 | self.0.assume_init_ref(), 559 | UninitSubseq::assume_init_ref_subseq(&self.1), 560 | ) 561 | } 562 | 563 | unsafe fn assume_init_mut_subseq( 564 | &mut self, 565 | ) -> as TupleLike>::AsMutOutput<'_> { 566 | Tuple( 567 | self.0.assume_init_mut(), 568 | UninitSubseq::assume_init_mut_subseq(&mut self.1), 569 | ) 570 | } 571 | 572 | fn subseq_as_ptr(&self) -> as TupleLike>::AsPtrOutput { 573 | Tuple(self.0.as_ptr(), UninitSubseq::subseq_as_ptr(&self.1)) 574 | } 575 | 576 | fn subseq_as_mut_ptr(&mut self) -> as TupleLike>::AsMutPtrOutput { 577 | Tuple( 578 | self.0.as_mut_ptr(), 579 | UninitSubseq::subseq_as_mut_ptr(&mut self.1), 580 | ) 581 | } 582 | 583 | fn write_subseq( 584 | &mut self, 585 | subseq: Tuple, 586 | ) -> as TupleLike>::AsMutOutput<'_> { 587 | Tuple( 588 | self.0.write(subseq.0), 589 | UninitSubseq::write_subseq(&mut self.1, subseq.1), 590 | ) 591 | } 592 | 593 | unsafe fn assume_init_drop_subseq(&mut self) { 594 | self.0.assume_init_drop(); 595 | UninitSubseq::assume_init_drop_subseq(&mut self.1); 596 | } 597 | } 598 | 599 | impl UninitSubseq> for Tuple 600 | where 601 | T: TupleLike, 602 | Other: TupleLike + UninitSubseq, 603 | { 604 | type PartiallyInitialized = Tuple; 605 | 606 | unsafe fn assume_init_subseq(self) -> Self::PartiallyInitialized { 607 | Tuple(self.0, UninitSubseq::assume_init_subseq(self.1)) 608 | } 609 | 610 | unsafe fn assume_init_read_subseq(&self) -> T { 611 | UninitSubseq::assume_init_read_subseq(&self.1) 612 | } 613 | 614 | unsafe fn assume_init_ref_subseq(&self) -> ::AsRefOutput<'_> { 615 | UninitSubseq::assume_init_ref_subseq(&self.1) 616 | } 617 | 618 | unsafe fn assume_init_mut_subseq(&mut self) -> ::AsMutOutput<'_> { 619 | UninitSubseq::assume_init_mut_subseq(&mut self.1) 620 | } 621 | 622 | fn subseq_as_ptr(&self) -> ::AsPtrOutput { 623 | UninitSubseq::subseq_as_ptr(&self.1) 624 | } 625 | 626 | fn subseq_as_mut_ptr(&mut self) -> ::AsMutPtrOutput { 627 | UninitSubseq::subseq_as_mut_ptr(&mut self.1) 628 | } 629 | 630 | fn write_subseq(&mut self, subseq: T) -> ::AsMutOutput<'_> { 631 | UninitSubseq::write_subseq(&mut self.1, subseq) 632 | } 633 | 634 | unsafe fn assume_init_drop_subseq(&mut self) { 635 | UninitSubseq::assume_init_drop_subseq(&mut self.1); 636 | } 637 | } 638 | 639 | /// Provide contiguous subsequence operations on tuples consisting of [`MaybeUninit`] elements. 640 | pub trait UninitConSubseq: ConSubseq 641 | where 642 | Seq: TupleLike, 643 | { 644 | /// The type of tuple consisting of elements not in the contiguous subsequence and 645 | /// values of each [`MaybeUninit`] elements in the contiguous subsequence. 646 | type PartiallyInitialized; 647 | 648 | /// Extract values of a specific contiguous subsequence consisting of [`MaybeUninit`] elements. 649 | /// 650 | /// Hint: The [`TupleLike`] trait provides the 651 | /// [`uninit_assume_init_con_subseq()`](TupleLike::uninit_assume_init_con_subseq()) method as 652 | /// the wrapper for this [`assume_init_con_subseq()`](UninitConSubseq::assume_init_con_subseq()) method. 653 | /// 654 | /// # Safety 655 | /// 656 | /// Same as [`MaybeUninit::assume_init()`](MaybeUninit::assume_init()). 657 | /// 658 | /// # Example 659 | /// 660 | /// ``` 661 | /// use std::mem::MaybeUninit; 662 | /// use tuplez::{get, tuple, TupleLike, tuple_t}; 663 | /// 664 | /// let mut tup = tuple!( 665 | /// 12, 666 | /// MaybeUninit::::zeroed(), 667 | /// MaybeUninit::::new(13), 668 | /// MaybeUninit::>::uninit(), 669 | /// false, 670 | /// ); 671 | /// tup.uninit_write_one(vec![1, 2, 3]); 672 | /// let part_init = unsafe { 673 | /// tup.uninit_assume_init_con_subseq::), _>() 674 | /// }; 675 | /// assert_eq!(get!(part_init; 2), 13); 676 | /// assert_eq!(get!(part_init; 3), vec![1, 2, 3]); 677 | /// let _: tuple_t!(i32, MaybeUninit, i32, Vec, bool) = part_init; 678 | /// ``` 679 | unsafe fn assume_init_con_subseq(self) -> Self::PartiallyInitialized; 680 | 681 | /// Read the values of a specific contiguous subsequence consisting of [`MaybeUninit`] elements. 682 | /// 683 | /// Hint: The [`TupleLike`] trait provides the 684 | /// [`uninit_assume_init_read_con_subseq()`](TupleLike::uninit_assume_init_read_con_subseq()) method as 685 | /// the wrapper for this [`assume_init_read_con_subseq()`](UninitConSubseq::assume_init_read_con_subseq()) method. 686 | /// 687 | /// # Safety 688 | /// 689 | /// Same as [`MaybeUninit::assume_init_read()`](MaybeUninit::assume_init_read()). 690 | /// 691 | /// # Example 692 | /// 693 | /// ``` 694 | /// use std::mem::MaybeUninit; 695 | /// use tuplez::{tuple, TupleLike, tuple_t}; 696 | /// 697 | /// let mut tup = tuple!( 698 | /// 12, 699 | /// MaybeUninit::::zeroed(), 700 | /// MaybeUninit::::new(13), 701 | /// MaybeUninit::>::uninit(), 702 | /// false, 703 | /// ); 704 | /// tup.uninit_write_one(vec![1, 2, 3]); 705 | /// let inited = unsafe { 706 | /// tup.uninit_assume_init_read_con_subseq::), _>() 707 | /// }; 708 | /// assert_eq!(inited, tuple!(13, vec![1, 2, 3])); 709 | /// ``` 710 | unsafe fn assume_init_read_con_subseq(&self) -> Seq; 711 | 712 | /// Get immutable references to values of a specific contiguous subsequence 713 | /// consisting of [`MaybeUninit`] elements. 714 | /// 715 | /// Hint: The [`TupleLike`] trait provides the 716 | /// [`uninit_assume_init_ref_con_subseq()`](TupleLike::uninit_assume_init_ref_con_subseq()) method as 717 | /// the wrapper for this [`assume_init_ref_con_subseq()`](UninitConSubseq::assume_init_ref_con_subseq()) method. 718 | /// 719 | /// # Safety 720 | /// 721 | /// Same as [`MaybeUninit::assume_init_ref()`](MaybeUninit::assume_init_ref()). 722 | /// 723 | /// # Example 724 | /// 725 | /// ``` 726 | /// use std::mem::MaybeUninit; 727 | /// use tuplez::{tuple, TupleLike, tuple_t}; 728 | /// 729 | /// let mut tup = tuple!( 730 | /// 12, 731 | /// MaybeUninit::::zeroed(), 732 | /// MaybeUninit::::new(13), 733 | /// MaybeUninit::>::uninit(), 734 | /// false, 735 | /// ); 736 | /// tup.uninit_write_one(vec![1, 2, 3]); 737 | /// let inited_ref = unsafe { 738 | /// tup.uninit_assume_init_ref_con_subseq::), _>() 739 | /// }; 740 | /// assert_eq!(inited_ref, tuple!(&13, &vec![1, 2, 3])); 741 | /// unsafe { tup.uninit_assume_init_drop_con_subseq::), _>() }; 742 | /// ``` 743 | unsafe fn assume_init_ref_con_subseq(&self) -> ::AsRefOutput<'_>; 744 | 745 | /// Get mutable references to values of a specific contiguous subsequence 746 | /// consisting of [`MaybeUninit`] elements. 747 | /// 748 | /// Hint: The [`TupleLike`] trait provides the 749 | /// [`uninit_assume_init_mut_con_subseq()`](TupleLike::uninit_assume_init_mut_con_subseq()) method as 750 | /// the wrapper for this [`assume_init_mut_con_subseq()`](UninitConSubseq::assume_init_mut_con_subseq()) method. 751 | /// 752 | /// # Safety 753 | /// 754 | /// Same as [`MaybeUninit::assume_init_mut()`](MaybeUninit::assume_init_mut()). 755 | /// 756 | /// # Example 757 | /// 758 | /// ``` 759 | /// use std::mem::MaybeUninit; 760 | /// use tuplez::{get, tuple, TupleLike, tuple_t}; 761 | /// 762 | /// let mut tup = tuple!( 763 | /// 12, 764 | /// MaybeUninit::::zeroed(), 765 | /// MaybeUninit::::new(13), 766 | /// MaybeUninit::>::uninit(), 767 | /// false, 768 | /// ); 769 | /// tup.uninit_write_one(vec![1, 2, 3]); 770 | /// let inited_mut = unsafe { 771 | /// tup.uninit_assume_init_mut_con_subseq::), _>() 772 | /// }; 773 | /// *get!(inited_mut; 0) += 1; 774 | /// get!(inited_mut; 1).push(4); 775 | /// assert_eq!(inited_mut, tuple!(&mut 14, &mut vec![1, 2, 3, 4])); 776 | /// unsafe { tup.uninit_assume_init_drop_con_subseq::), _>() }; 777 | /// ``` 778 | unsafe fn assume_init_mut_con_subseq(&mut self) -> ::AsMutOutput<'_>; 779 | 780 | /// Get pointers to values of a specific contiguous subsequence 781 | /// consisting of [`MaybeUninit`] elements. 782 | /// 783 | /// Hint: The [`TupleLike`] trait provides the 784 | /// [`uninit_con_subseq_as_ptr()`](TupleLike::uninit_con_subseq_as_ptr()) method as 785 | /// the wrapper for this [`con_subseq_as_ptr()`](UninitConSubseq::con_subseq_as_ptr()) method. 786 | /// 787 | /// # Example 788 | /// 789 | /// ``` 790 | /// use std::mem::MaybeUninit; 791 | /// use tuplez::{get, tuple, TupleLike, tuple_t}; 792 | /// 793 | /// let mut tup = tuple!( 794 | /// 12, 795 | /// MaybeUninit::::zeroed(), 796 | /// MaybeUninit::::new(13), 797 | /// MaybeUninit::>::uninit(), 798 | /// false, 799 | /// ); 800 | /// tup.uninit_write_one(vec![1, 2, 3]); 801 | /// let inited_ptr = tup.uninit_con_subseq_as_ptr::), _>(); 802 | /// unsafe { 803 | /// assert_eq!(*get!(inited_ptr; 0), 13); 804 | /// assert_eq!(*get!(inited_ptr; 1), vec![1, 2, 3]); 805 | /// tup.uninit_assume_init_drop_con_subseq::), _>(); 806 | /// } 807 | /// ``` 808 | fn con_subseq_as_ptr(&self) -> ::AsPtrOutput; 809 | 810 | /// Get mutable pointers to values of a specific contiguous subsequence 811 | /// consisting of [`MaybeUninit`] elements. 812 | /// 813 | /// Hint: The [`TupleLike`] trait provides the 814 | /// [`uninit_con_subseq_as_mut_ptr()`](TupleLike::uninit_con_subseq_as_mut_ptr()) method as 815 | /// the wrapper for this [`con_subseq_as_mut_ptr()`](UninitConSubseq::con_subseq_as_mut_ptr()) method. 816 | /// 817 | /// # Example 818 | /// 819 | /// ``` 820 | /// use std::mem::MaybeUninit; 821 | /// use tuplez::{get, tuple, TupleLike, tuple_t}; 822 | /// 823 | /// let mut tup = tuple!( 824 | /// 12, 825 | /// MaybeUninit::::zeroed(), 826 | /// MaybeUninit::::new(13), 827 | /// MaybeUninit::>::uninit(), 828 | /// false, 829 | /// ); 830 | /// tup.uninit_write_one(vec![1, 2, 3]); 831 | /// let inited_ptr = tup.uninit_con_subseq_as_mut_ptr::), _>(); 832 | /// unsafe { 833 | /// *get!(inited_ptr; 0) += 1; 834 | /// (*get!(inited_ptr; 1)).push(4); 835 | /// assert_eq!(*get!(inited_ptr; 0), 14); 836 | /// assert_eq!(*get!(inited_ptr; 1), vec![1, 2, 3, 4]); 837 | /// tup.uninit_assume_init_drop_con_subseq::), _>(); 838 | /// } 839 | /// ``` 840 | fn con_subseq_as_mut_ptr(&mut self) -> ::AsMutPtrOutput; 841 | 842 | /// Set values to a contiguous subsequence consisting of [`MaybeUninit`] elements. 843 | /// 844 | /// Similar to [`MaybeUninit::write()`](MaybeUninit::write()), 845 | /// this overwrites any previous value without dropping it. 846 | /// 847 | /// **NOTE**: The contiguous subsequence must have one and only one candidate in the supersequence. 848 | /// 849 | /// Hint: The [`TupleLike`] trait provides the [`uninit_write_con_subseq()`](TupleLike::uninit_write_con_subseq()) 850 | /// method as the wrapper for this [`write_con_subseq()`](UninitConSubseq::write_con_subseq()) method. 851 | /// 852 | /// # Example 853 | /// 854 | /// ``` 855 | /// use tuplez::{tuple, TupleLike, tuple_t}; 856 | /// 857 | /// let mut uninit = ::uninit(); 858 | /// uninit.uninit_write_one(true); 859 | /// uninit.uninit_write_subseq(tuple!(12, "hello")); 860 | /// let tup = unsafe { uninit.uninit_assume_init() }; 861 | /// assert_eq!(tup, tuple!(12, true, "hello")); 862 | /// ``` 863 | fn write_con_subseq(&mut self, subseq: Seq) -> Seq::AsMutOutput<'_>; 864 | 865 | /// Drop values in place for a contiguous subsequence consisting of [`MaybeUninit`] elements. 866 | /// 867 | /// **NOTE**: The contiguous subsequence must have one and only one candidate in the supersequence. 868 | /// 869 | /// Hint: The [`TupleLike`] trait provides the [`uninit_assume_init_drop_con_subseq()`](TupleLike::uninit_assume_init_drop_con_subseq()) 870 | /// method as the wrapper for this [`assume_init_drop_con_subseq()`](UninitConSubseq::assume_init_drop_con_subseq()) method. 871 | /// 872 | /// # Safety 873 | /// 874 | /// Same as [`MaybeUninit::assume_init_drop()`](MaybeUninit::assume_init_drop()). 875 | unsafe fn assume_init_drop_con_subseq(&mut self); 876 | } 877 | 878 | impl UninitConSubseq for Unit { 879 | type PartiallyInitialized = Unit; 880 | 881 | unsafe fn assume_init_con_subseq(self) -> Self::PartiallyInitialized { 882 | Unit 883 | } 884 | 885 | unsafe fn assume_init_read_con_subseq(&self) -> Unit { 886 | Unit 887 | } 888 | 889 | unsafe fn assume_init_ref_con_subseq(&self) -> ::AsRefOutput<'_> { 890 | Unit 891 | } 892 | 893 | unsafe fn assume_init_mut_con_subseq(&mut self) -> ::AsMutOutput<'_> { 894 | Unit 895 | } 896 | 897 | fn con_subseq_as_ptr(&self) -> ::AsPtrOutput { 898 | Unit 899 | } 900 | 901 | fn con_subseq_as_mut_ptr(&mut self) -> ::AsMutPtrOutput { 902 | Unit 903 | } 904 | 905 | fn write_con_subseq(&mut self, _: Unit) -> ::AsMutOutput<'_> { 906 | Unit 907 | } 908 | 909 | unsafe fn assume_init_drop_con_subseq(&mut self) {} 910 | } 911 | 912 | impl UninitConSubseq> for Tuple 913 | where 914 | T: TupleLike, 915 | Other: UninitConSubseq, 916 | { 917 | type PartiallyInitialized = Tuple; 918 | 919 | unsafe fn assume_init_con_subseq(self) -> Self::PartiallyInitialized { 920 | Tuple(self.0, UninitConSubseq::assume_init_con_subseq(self.1)) 921 | } 922 | 923 | unsafe fn assume_init_read_con_subseq(&self) -> T { 924 | UninitConSubseq::assume_init_read_con_subseq(&self.1) 925 | } 926 | 927 | unsafe fn assume_init_ref_con_subseq(&self) -> ::AsRefOutput<'_> { 928 | UninitConSubseq::assume_init_ref_con_subseq(&self.1) 929 | } 930 | 931 | unsafe fn assume_init_mut_con_subseq(&mut self) -> ::AsMutOutput<'_> { 932 | UninitConSubseq::assume_init_mut_con_subseq(&mut self.1) 933 | } 934 | 935 | fn con_subseq_as_ptr(&self) -> ::AsPtrOutput { 936 | UninitConSubseq::con_subseq_as_ptr(&self.1) 937 | } 938 | 939 | fn con_subseq_as_mut_ptr(&mut self) -> ::AsMutPtrOutput { 940 | UninitConSubseq::con_subseq_as_mut_ptr(&mut self.1) 941 | } 942 | 943 | fn write_con_subseq(&mut self, subseq: T) -> ::AsMutOutput<'_> { 944 | UninitConSubseq::write_con_subseq(&mut self.1, subseq) 945 | } 946 | 947 | unsafe fn assume_init_drop_con_subseq(&mut self) { 948 | UninitConSubseq::assume_init_drop_con_subseq(&mut self.1); 949 | } 950 | } 951 | 952 | impl UninitConSubseq, Used> 953 | for Tuple, Other> 954 | where 955 | Other: UninitConSubseq, 956 | { 957 | type PartiallyInitialized = Tuple; 958 | 959 | unsafe fn assume_init_con_subseq(self) -> Self::PartiallyInitialized { 960 | Tuple(self.0.assume_init(), self.1) 961 | } 962 | 963 | unsafe fn assume_init_read_con_subseq(&self) -> Tuple { 964 | Tuple(self.0.assume_init_read(), Unit) 965 | } 966 | 967 | unsafe fn assume_init_ref_con_subseq( 968 | &self, 969 | ) -> as TupleLike>::AsRefOutput<'_> { 970 | Tuple(self.0.assume_init_ref(), Unit) 971 | } 972 | 973 | unsafe fn assume_init_mut_con_subseq( 974 | &mut self, 975 | ) -> as TupleLike>::AsMutOutput<'_> { 976 | Tuple(self.0.assume_init_mut(), Unit) 977 | } 978 | 979 | fn con_subseq_as_ptr(&self) -> as TupleLike>::AsPtrOutput { 980 | Tuple(self.0.as_ptr(), Unit) 981 | } 982 | 983 | fn con_subseq_as_mut_ptr(&mut self) -> as TupleLike>::AsMutPtrOutput { 984 | Tuple(self.0.as_mut_ptr(), Unit) 985 | } 986 | 987 | fn write_con_subseq( 988 | &mut self, 989 | subseq: Tuple, 990 | ) -> as TupleLike>::AsMutOutput<'_> { 991 | Tuple(self.0.write(subseq.0), Unit) 992 | } 993 | 994 | unsafe fn assume_init_drop_con_subseq(&mut self) { 995 | self.0.assume_init_drop(); 996 | } 997 | } 998 | 999 | impl 1000 | UninitConSubseq>, Used> 1001 | for Tuple, Other1> 1002 | where 1003 | Other1: UninitConSubseq, Used>, 1004 | Other2: TupleLike, 1005 | { 1006 | type PartiallyInitialized = Tuple; 1007 | 1008 | unsafe fn assume_init_con_subseq(self) -> Self::PartiallyInitialized { 1009 | Tuple( 1010 | self.0.assume_init(), 1011 | UninitConSubseq::assume_init_con_subseq(self.1), 1012 | ) 1013 | } 1014 | 1015 | unsafe fn assume_init_read_con_subseq(&self) -> Tuple> { 1016 | Tuple( 1017 | self.0.assume_init_read(), 1018 | UninitConSubseq::assume_init_read_con_subseq(&self.1), 1019 | ) 1020 | } 1021 | 1022 | unsafe fn assume_init_ref_con_subseq( 1023 | &self, 1024 | ) -> > as TupleLike>::AsRefOutput<'_> { 1025 | Tuple( 1026 | self.0.assume_init_ref(), 1027 | UninitConSubseq::assume_init_ref_con_subseq(&self.1), 1028 | ) 1029 | } 1030 | 1031 | unsafe fn assume_init_mut_con_subseq( 1032 | &mut self, 1033 | ) -> > as TupleLike>::AsMutOutput<'_> { 1034 | Tuple( 1035 | self.0.assume_init_mut(), 1036 | UninitConSubseq::assume_init_mut_con_subseq(&mut self.1), 1037 | ) 1038 | } 1039 | 1040 | fn con_subseq_as_ptr( 1041 | &self, 1042 | ) -> > as TupleLike>::AsPtrOutput { 1043 | Tuple(self.0.as_ptr(), UninitConSubseq::con_subseq_as_ptr(&self.1)) 1044 | } 1045 | 1046 | fn con_subseq_as_mut_ptr( 1047 | &mut self, 1048 | ) -> > as TupleLike>::AsMutPtrOutput { 1049 | Tuple( 1050 | self.0.as_mut_ptr(), 1051 | UninitConSubseq::con_subseq_as_mut_ptr(&mut self.1), 1052 | ) 1053 | } 1054 | 1055 | fn write_con_subseq( 1056 | &mut self, 1057 | subseq: Tuple>, 1058 | ) -> > as TupleLike>::AsMutOutput<'_> { 1059 | Tuple( 1060 | self.0.write(subseq.0), 1061 | UninitConSubseq::write_con_subseq(&mut self.1, subseq.1), 1062 | ) 1063 | } 1064 | 1065 | unsafe fn assume_init_drop_con_subseq(&mut self) { 1066 | self.0.assume_init_drop(); 1067 | UninitConSubseq::assume_init_drop_con_subseq(&mut self.1); 1068 | } 1069 | } 1070 | -------------------------------------------------------------------------------- /src/unwrap.rs: -------------------------------------------------------------------------------- 1 | //! Provides the ability to unwrap elements of tuples. 2 | //! 3 | //! This module is only available when the `unwrap` feature is enabled (enabled by default). 4 | //! 5 | //! Since this module introduces the [`unwrap()`](Unwrap::unwrap()) method that may cause panic, 6 | //! you may choose to disable it to avoid. Even if you accept it, it is more recommended that you use [`unwrap_or_default()`](UnwrapOrDefault::unwrap_or_default()) or 7 | //! [`try_unwrap()`](Tuple::try_unwrap()) to avoid panic. 8 | 9 | use crate::{Tuple, TupleLike, Unit}; 10 | 11 | /// Indicate that a type is a wrapper of a value and can be unwrapped into it. 12 | /// 13 | /// [`Unwrap`] is implemented by default for four types: 14 | /// * [`Option`](std::option::Option) 15 | /// * [`Result`](std::result::Result) 16 | /// * [`Unit`] 17 | /// * [`Tuple`](crate::Tuple) if all types `T0`, `T1`, ... `Tn` implement [`Unwrap`]. 18 | /// 19 | /// Implement [`Unwrap`] for your own wrapper types so that a [`Tuple`] containing your wrappers can be [`unwrap()`](Unwrap::unwrap()). 20 | #[cfg_attr(docsrs, doc(cfg(feature = "unwrap")))] 21 | pub trait Unwrap { 22 | /// Type of the contained value. 23 | type UnwrapOutput; 24 | 25 | /// Get the contained value. 26 | /// 27 | /// Because this function may panic, its use is generally discouraged. Instead, 28 | /// use [`unwrap_or_default()`](UnwrapOrDefault::unwrap_or_default()) or 29 | /// [`try_unwrap()`](Tuple::try_unwrap()). 30 | /// 31 | /// Hint: The [`TupleLike`] trait provides the [`unwrap()`](TupleLike::unwrap()) method as the wrapper 32 | /// for this [`unwrap()`](Unwrap::unwrap()) method. 33 | /// 34 | /// # Panic 35 | /// 36 | /// Panic if self does not contain a value. 37 | /// 38 | /// # Example 39 | /// 40 | /// ``` 41 | /// use tuplez::{tuple, TupleLike}; 42 | /// 43 | /// let tup = tuple!(Some(1), Ok::(3.14), Some("hello")); 44 | /// assert_eq!(tup.unwrap(), tuple!(1, 3.14, "hello")); 45 | /// ``` 46 | fn unwrap(self) -> Self::UnwrapOutput; 47 | 48 | /// Check if self contains a value. 49 | /// 50 | /// Soundness requirement: When [`has_value()`](Unwrap::has_value()) returns true, [`unwrap()`](Unwrap::unwrap()) cannot panic. 51 | /// 52 | /// Hint: The [`TupleLike`] trait provides the [`has_value()`](TupleLike::has_value()) method as the wrapper 53 | /// for this [`has_value()`](Unwrap::has_value()) method. 54 | /// 55 | /// # Example 56 | /// 57 | /// ``` 58 | /// use tuplez::{tuple, TupleLike}; 59 | /// 60 | /// assert_eq!(tuple!(Some(1), Some(3.14), Ok::<&str, ()>("hello")).has_value(), true); 61 | /// assert_eq!(tuple!(None::, Some(3.14), Err::<&str, ()>(())).has_value(), false); 62 | /// ``` 63 | fn has_value(&self) -> bool; 64 | } 65 | 66 | /// Indicate that a type is a wrapper of a value and can be unwrapped into it or the default value. 67 | /// 68 | /// Unlike [`Unwrap`], the trait [`UnwrapOrDefault`] indicates that when the wrapper does not contain a value, 69 | /// it's able to create a default value instead of panic. 70 | /// 71 | /// [`UnwrapOrDefault`] is implemented by default for four types: 72 | /// * [`Option`](std::option::Option) 73 | /// * [`Result`](std::result::Result) 74 | /// * [`Unit`] 75 | /// * [`Tuple`](crate::Tuple) if all types `T0`, `T1`, ... `Tn` implement [`UnwrapOrDefault`]. 76 | /// 77 | /// Implement [`UnwrapOrDefault`] for your own wrapper types so that a [`Tuple`] containing your wrappers can 78 | /// be [`unwrap_or_default()`](UnwrapOrDefault::unwrap_or_default()). 79 | #[cfg_attr(docsrs, doc(cfg(feature = "unwrap")))] 80 | pub trait UnwrapOrDefault { 81 | /// Type of the contained value. 82 | type UnwrapOutput; 83 | 84 | /// Get the contained value, or the default value if self does not contain a value. 85 | /// 86 | /// Hint: The [`TupleLike`] trait provides the [`unwrap_or_default()`](TupleLike::unwrap_or_default()) 87 | /// method as the wrapper for this [`unwrap_or_default()`](UnwrapOrDefault::unwrap_or_default()) method. 88 | /// 89 | /// # Example 90 | /// 91 | /// ``` 92 | /// use tuplez::{tuple, TupleLike}; 93 | /// 94 | /// let tup = tuple!(Some(1), Err::("failed"), Some("hello")); 95 | /// assert_eq!(tup.unwrap_or_default(), tuple!(1, 0.0, "hello")); 96 | /// ``` 97 | fn unwrap_or_default(self) -> Self::UnwrapOutput; 98 | } 99 | 100 | impl Unwrap for Option { 101 | type UnwrapOutput = T; 102 | fn unwrap(self) -> Self::UnwrapOutput { 103 | self.unwrap() 104 | } 105 | fn has_value(&self) -> bool { 106 | self.is_some() 107 | } 108 | } 109 | 110 | impl Unwrap for Result { 111 | type UnwrapOutput = T; 112 | fn unwrap(self) -> Self::UnwrapOutput { 113 | self.unwrap() 114 | } 115 | fn has_value(&self) -> bool { 116 | self.is_ok() 117 | } 118 | } 119 | 120 | impl UnwrapOrDefault for Option { 121 | type UnwrapOutput = T; 122 | fn unwrap_or_default(self) -> Self::UnwrapOutput { 123 | self.unwrap_or_default() 124 | } 125 | } 126 | 127 | impl UnwrapOrDefault for Result { 128 | type UnwrapOutput = T; 129 | fn unwrap_or_default(self) -> Self::UnwrapOutput { 130 | self.unwrap_or_default() 131 | } 132 | } 133 | 134 | impl Unwrap for Unit { 135 | type UnwrapOutput = Unit; 136 | fn unwrap(self) -> Self::UnwrapOutput { 137 | Self 138 | } 139 | fn has_value(&self) -> bool { 140 | true 141 | } 142 | } 143 | 144 | impl Unwrap for Tuple 145 | where 146 | Other: TupleLike + Unwrap, 147 | First: Unwrap, 148 | { 149 | type UnwrapOutput = Tuple; 150 | fn unwrap(self) -> Self::UnwrapOutput { 151 | Tuple(Unwrap::unwrap(self.0), Unwrap::unwrap(self.1)) 152 | } 153 | fn has_value(&self) -> bool { 154 | Unwrap::has_value(&self.0) && Unwrap::has_value(&self.1) 155 | } 156 | } 157 | 158 | impl UnwrapOrDefault for Unit { 159 | type UnwrapOutput = Unit; 160 | fn unwrap_or_default(self) -> Self::UnwrapOutput { 161 | Self 162 | } 163 | } 164 | 165 | impl Unit { 166 | /// Always be `Some(tuple!())`. 167 | pub fn try_unwrap(self) -> Option { 168 | Some(self) 169 | } 170 | } 171 | 172 | impl UnwrapOrDefault for Tuple 173 | where 174 | Other: TupleLike + UnwrapOrDefault, 175 | First: UnwrapOrDefault, 176 | { 177 | type UnwrapOutput = Tuple; 178 | fn unwrap_or_default(self) -> Self::UnwrapOutput { 179 | Tuple( 180 | UnwrapOrDefault::unwrap_or_default(self.0), 181 | UnwrapOrDefault::unwrap_or_default(self.1), 182 | ) 183 | } 184 | } 185 | -------------------------------------------------------------------------------- /tuplez-macros/.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | -------------------------------------------------------------------------------- /tuplez-macros/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "tuplez-macros" 3 | version = "0.7.0" 4 | description = "Procedural macros implementation of tuplez" 5 | authors.workspace = true 6 | license.workspace = true 7 | readme.workspace = true 8 | edition.workspace = true 9 | documentation.workspace = true 10 | repository.workspace = true 11 | keywords.workspace = true 12 | categories = [ "data-structures", "development-tools::procedural-macro-helpers" ] 13 | 14 | [lib] 15 | proc-macro = true 16 | 17 | [dependencies] 18 | syn = { version = "2.0", features = ["full"] } 19 | quote = "1.0" 20 | proc-macro2 = "1.0" 21 | -------------------------------------------------------------------------------- /tuplez-macros/src/lib.rs: -------------------------------------------------------------------------------- 1 | use proc_macro::TokenStream; 2 | use proc_macro2::Span; 3 | use quote::quote; 4 | use syn::{parse_macro_input, parse_quote, Data, DeriveInput, Expr, Fields, Ident, LitInt}; 5 | 6 | mod parser; 7 | 8 | use parser::*; 9 | 10 | #[proc_macro] 11 | pub fn tuple_traits_impl(input: TokenStream) -> TokenStream { 12 | let max = parse_macro_input!(input as LitInt); 13 | let max: usize = match max.base10_parse() { 14 | Ok(v) => v, 15 | Err(e) => return e.into_compile_error().into(), 16 | }; 17 | 18 | let mut impls = vec![]; 19 | impls.push(quote! { 20 | impl ::tuplez::ToPrimitive for ::tuplez::Unit { 21 | type Primitive = (); 22 | fn primitive(self) -> Self::Primitive {} 23 | } 24 | impl From<()> for ::tuplez::Unit { 25 | fn from(_: ()) -> Self { 26 | ::tuplez::Unit 27 | } 28 | } 29 | #[cfg(not(feature = "any_array"))] 30 | impl ::tuplez::ToArray for ::tuplez::Unit { 31 | type Array = [T; 0]; 32 | type Iter<'a> = std::array::IntoIter<&'a T, 0> where Self: 'a, T: 'a; 33 | type IterMut<'a> = std::array::IntoIter<&'a mut T, 0> where Self: 'a, T: 'a; 34 | fn to_array(self) -> Self::Array { 35 | Default::default() 36 | } 37 | fn iter<'a>(&'a self) -> Self::Iter<'a> 38 | where 39 | Self: 'a, 40 | T: 'a 41 | { 42 | self.as_ref().to_array().into_iter() 43 | } 44 | fn iter_mut<'a>(&'a mut self) -> Self::IterMut<'a> 45 | where 46 | Self: 'a, 47 | T: 'a 48 | { 49 | self.as_mut().to_array().into_iter() 50 | } 51 | } 52 | #[cfg(not(feature = "any_array"))] 53 | impl From<[T; 0]> for ::tuplez::Unit { 54 | fn from(_: [T; 0]) -> Self { 55 | ::tuplez::Unit 56 | } 57 | } 58 | }); 59 | 60 | let mut tys = vec![]; 61 | let mut pats = vec![]; 62 | for i in 0..max { 63 | tys.push(Ident::new(&format!("T{i}"), Span::call_site())); 64 | pats.push(Ident::new(&format!("v{i}"), Span::call_site())); 65 | let count = LitInt::new(&format!("{}", i + 1), Span::call_site()); 66 | impls.push(quote! { 67 | impl<#(#tys),*> ::tuplez::ToPrimitive for ::tuplez::tuple_t!(#(#tys),*) { 68 | type Primitive = (#(#tys),*,); 69 | fn primitive(self) -> Self::Primitive { 70 | let ::tuplez::tuple_pat!(#(#pats),*) = self; 71 | (#(#pats),*,) 72 | } 73 | } 74 | impl<#(#tys),*> From<(#(#tys),*,)> for ::tuplez::tuple_t!(#(#tys),*) { 75 | fn from((#(#pats),*,): (#(#tys),*,)) -> Self { 76 | ::tuplez::tuple!(#(#pats),*) 77 | } 78 | } 79 | #[cfg(not(feature = "any_array"))] 80 | impl ToArray for ::tuplez::tuple_t!(T; #count) { 81 | type Array = [T; #count]; 82 | type Iter<'a> = std::array::IntoIter<&'a T, #count> where Self: 'a, T: 'a; 83 | type IterMut<'a> = std::array::IntoIter<&'a mut T, #count> where Self: 'a, T: 'a; 84 | fn to_array(self) -> Self::Array { 85 | let ::tuplez::tuple_pat!(#(#pats),*) = self; 86 | [#(#pats),*] 87 | } 88 | fn iter<'a>(&'a self) -> Self::Iter<'a> 89 | where 90 | Self: 'a, 91 | T: 'a 92 | { 93 | self.as_ref().to_array().into_iter() 94 | } 95 | fn iter_mut<'a>(&'a mut self) -> Self::IterMut<'a> 96 | where 97 | Self: 'a, 98 | T: 'a 99 | { 100 | self.as_mut().to_array().into_iter() 101 | } 102 | } 103 | #[cfg(not(feature = "any_array"))] 104 | impl From<[T; #count]> for ::tuplez::tuple_t!(T; #count) { 105 | fn from([#(#pats),*]: [T; #count]) -> Self { 106 | ::tuplez::tuple!(#(#pats),*) 107 | } 108 | } 109 | }); 110 | } 111 | 112 | quote! {#(#impls)*}.into() 113 | } 114 | 115 | #[proc_macro] 116 | pub fn tuple(input: TokenStream) -> TokenStream { 117 | let ReExportTuplez { 118 | path, 119 | other: TupleGen(exprs), 120 | } = parse_macro_input!(input as ReExportTuplez); 121 | let mut unpack = quote!( #path::Unit ); 122 | for expr in exprs.into_iter().rev() { 123 | unpack = quote!( #path::Tuple( #expr, #unpack) ); 124 | } 125 | unpack.into() 126 | } 127 | 128 | #[proc_macro] 129 | pub fn tuple_t(input: TokenStream) -> TokenStream { 130 | let ReExportTuplez { 131 | path, 132 | other: TupleType(types), 133 | } = parse_macro_input!(input as ReExportTuplez); 134 | let mut unpack = quote!( #path::Unit ); 135 | for ty in types.into_iter().rev() { 136 | unpack = quote!( #path::Tuple< #ty, #unpack> ); 137 | } 138 | unpack.into() 139 | } 140 | 141 | #[proc_macro] 142 | pub fn tuple_pat(input: TokenStream) -> TokenStream { 143 | let ReExportTuplez { 144 | path, 145 | other: TuplePat { mut pats, leader }, 146 | } = parse_macro_input!(input as ReExportTuplez); 147 | let mut unpack; 148 | if pats.is_empty() { 149 | unpack = quote!(_); 150 | } else if leader { 151 | unpack = quote!(..); 152 | for pat in pats.into_iter().rev() { 153 | unpack = quote!( #path::Tuple( #pat, #unpack) ); 154 | } 155 | } else { 156 | let last = pats.pop().unwrap(); 157 | unpack = quote!(#last); 158 | for pat in pats.into_iter().rev() { 159 | unpack = quote!( #path::Tuple( #pat, #unpack) ); 160 | } 161 | } 162 | unpack.into() 163 | } 164 | 165 | #[proc_macro] 166 | pub fn get(input: TokenStream) -> TokenStream { 167 | let TupleIndex { tup, index } = parse_macro_input!(input as TupleIndex); 168 | let field = quote!(. 1); 169 | let fields = vec![field.clone(); index]; 170 | quote!( (#tup) #(#fields)* . 0).into() 171 | } 172 | 173 | #[proc_macro] 174 | pub fn take(input: TokenStream) -> TokenStream { 175 | let ReExportTuplez { 176 | path, 177 | other: result, 178 | } = parse_macro_input!(input as ReExportTuplez); 179 | match result { 180 | TupleTake { 181 | tup, 182 | ext: IndexOrType::Index(index), 183 | } => { 184 | let tup = quote!( let tup_ = #tup ); 185 | let field = quote!(. 1); 186 | let mut fields = vec![field.clone(); index]; 187 | let element = quote!( tup_ #(#fields)* . 0 ); 188 | let mut unpack = quote!( tup_ #(#fields)* . 1 ); 189 | for _ in 0..index { 190 | _ = fields.pop(); 191 | unpack = quote!( #path::Tuple( tup_ #(#fields)* . 0, #unpack ) ) 192 | } 193 | quote!({ 194 | #tup ; 195 | ( #element, #unpack ) 196 | }) 197 | } 198 | TupleTake { 199 | tup, 200 | ext: IndexOrType::Type(ty), 201 | } => quote!({ 202 | use #path::TupleLike; 203 | let (element_, remainder_): (#ty, _) = (#tup).take(); 204 | (element_, remainder_) 205 | }), 206 | } 207 | .into() 208 | } 209 | 210 | #[proc_macro] 211 | pub fn pick(input: TokenStream) -> TokenStream { 212 | let TuplePick { tup, indices } = parse_macro_input!(input as TuplePick); 213 | let tup = quote!( let tup_ = #tup ); 214 | let max = *indices.iter().max().unwrap(); 215 | let unpicked_indices = (0..max).filter(|i| !indices.contains(i)); 216 | let field = quote!(. 1); 217 | let picked = indices 218 | .iter() 219 | .map(|x| { 220 | let fields = vec![field.clone(); *x]; 221 | quote!( tup_ #(#fields)* .0 ) 222 | }) 223 | .rfold( 224 | quote!(tuplez::Unit), 225 | |packed, token| quote!( tuplez::Tuple( #token, #packed ) ), 226 | ); 227 | let tail = { 228 | let fields = vec![field.clone(); max]; 229 | quote!( tup_ #(#fields)* .1 ) 230 | }; 231 | let unpicked = unpicked_indices 232 | .map(|x| { 233 | let fields = vec![field.clone(); x]; 234 | quote!( tup_ #(#fields)* .0 ) 235 | }) 236 | .rfold( 237 | tail, 238 | |packed, token| quote!( tuplez::Tuple( #token, #packed ) ), 239 | ); 240 | quote!({ 241 | #tup ; 242 | ( #picked, #unpicked ) 243 | }) 244 | .into() 245 | } 246 | 247 | #[proc_macro] 248 | pub fn split_at(input: TokenStream) -> TokenStream { 249 | let ReExportTuplez { 250 | path, 251 | other: TupleIndex { tup, index }, 252 | } = parse_macro_input!(input as ReExportTuplez); 253 | let tup = quote!( let tup_ = #tup ); 254 | let field = quote!(. 1); 255 | let mut fields = vec![field.clone(); index]; 256 | let mut unpack = quote!( #path::Unit ); 257 | let other = quote!( tup_ #(#fields)* ); 258 | for _ in 0..index { 259 | _ = fields.pop(); 260 | unpack = quote!( #path::Tuple( tup_ #(#fields)* . 0, #unpack ) ); 261 | } 262 | quote!({ 263 | #tup ; 264 | ( #unpack, #other ) 265 | }) 266 | .into() 267 | } 268 | 269 | #[proc_macro] 270 | pub fn swap_at(input: TokenStream) -> TokenStream { 271 | let TupleSwap { tup, left, right } = parse_macro_input!(input as TupleSwap); 272 | let tup = quote!( let mut tup_ = #tup ); 273 | let field = quote!(. 1); 274 | let max = std::cmp::max(*left.iter().max().unwrap(), *right.iter().max().unwrap()); 275 | let mut indices: Vec = (0..=max).collect(); 276 | for i in 0..left.len() { 277 | indices.swap(left[i], right[i]); 278 | } 279 | let tail = { 280 | let fields = vec![field.clone(); max]; 281 | quote!( tup_ #(#fields)* .1 ) 282 | }; 283 | let output = indices 284 | .into_iter() 285 | .map(|x| { 286 | let fields = vec![field.clone(); x]; 287 | quote!( tup_ #(#fields)* .0 ) 288 | }) 289 | .rfold( 290 | tail, 291 | |packed, token| quote!( tuplez::Tuple( #token, #packed ) ), 292 | ); 293 | 294 | quote!({ 295 | #tup ; 296 | #output 297 | }) 298 | .into() 299 | } 300 | 301 | #[proc_macro] 302 | pub fn apply(input: TokenStream) -> TokenStream { 303 | let TupleApply { 304 | tup, 305 | mut func, 306 | args, 307 | } = parse_macro_input!(input as TupleApply); 308 | let tup = quote!( #[allow(unused_mut)] let mut tup_ = #tup ); 309 | let field_at = |index| { 310 | let field = quote!(. 1); 311 | let fields = vec![field.clone(); index]; 312 | parse_quote!( tup_ #(#fields)* . 0) 313 | }; 314 | args.0 315 | .into_iter() 316 | .map(move |arg| match arg { 317 | TupleArg::Move(index) => field_at(index), 318 | TupleArg::Ref(index) => { 319 | let arg = field_at(index); 320 | parse_quote!(& #arg) 321 | } 322 | TupleArg::Mut(index) => { 323 | let arg = field_at(index); 324 | parse_quote!(& mut #arg) 325 | } 326 | }) 327 | .for_each(|arg| match &mut func { 328 | Expr::Call(call) => call.args.push(arg), 329 | Expr::MethodCall(call) => call.args.push(arg), 330 | _ => (), 331 | }); 332 | quote!({ 333 | #tup ; 334 | #func 335 | }) 336 | .into() 337 | } 338 | 339 | #[proc_macro] 340 | pub fn mapper(input: TokenStream) -> TokenStream { 341 | let ReExportTuplez { 342 | path, 343 | other: Mapper(rules), 344 | } = parse_macro_input!(input as ReExportTuplez); 345 | let rules = rules.into_iter().map( 346 | |Rule { 347 | generic, 348 | mut inputs, 349 | output_type, 350 | body, 351 | }| { 352 | let (x, tyx, mutx) = inputs.pop_front().unwrap(); 353 | let tyx = tyx.unwrap(); 354 | let mutx = if mutx { quote!(mut) } else { quote!() }; 355 | let tyout = output_type.unwrap(); 356 | 357 | quote!( 358 | impl #generic Mapper<#tyx> for __Mapper { 359 | type Output = #tyout; 360 | type NextMapper = Self; 361 | fn map(self, value: #tyx) -> (Self::Output, Self::NextMapper) { 362 | let f = | #mutx #x : #tyx | -> #tyout #body; 363 | (f(value), self) 364 | } 365 | } 366 | ) 367 | }, 368 | ); 369 | quote!( 370 | { 371 | use #path::foreach::Mapper; 372 | #[derive(Copy, Clone, Debug)] 373 | struct __Mapper; 374 | #(#rules)* 375 | __Mapper 376 | } 377 | ) 378 | .into() 379 | } 380 | 381 | #[proc_macro] 382 | pub fn folder(input: TokenStream) -> TokenStream { 383 | let ReExportTuplez { 384 | path, 385 | other: Folder(rules), 386 | } = parse_macro_input!(input as ReExportTuplez); 387 | let rules = rules.into_iter().map( 388 | |Rule { 389 | generic, 390 | mut inputs, 391 | output_type, 392 | body, 393 | }| { 394 | let (acc, tyacc, mutacc) = inputs.pop_front().unwrap(); 395 | let (x, tyx, mutx) = inputs.pop_front().unwrap(); 396 | let tyacc = tyacc.unwrap(); 397 | let mutacc = if mutacc { quote!(mut) } else { quote!() }; 398 | let tyx = tyx.unwrap(); 399 | let mutx = if mutx { quote!(mut) } else { quote!() }; 400 | let tyout = output_type.unwrap(); 401 | 402 | quote!( 403 | impl #generic Folder<#tyx, #tyout> for __Folder { 404 | type Output = #tyout; 405 | type NextFolder = Self; 406 | fn fold(self, acc: #tyacc, value: #tyx) -> (Self::Output, Self::NextFolder) { 407 | let f = | #mutacc #acc: #tyacc, #mutx #x: #tyx | -> #tyout #body; 408 | (f(acc, value), self) 409 | } 410 | } 411 | ) 412 | }, 413 | ); 414 | quote!( 415 | { 416 | use #path::fold::Folder; 417 | #[derive(Copy, Clone, Debug)] 418 | struct __Folder; 419 | #(#rules)* 420 | __Folder 421 | } 422 | ) 423 | .into() 424 | } 425 | 426 | #[proc_macro] 427 | pub fn unary_pred(input: TokenStream) -> TokenStream { 428 | let ReExportTuplez { 429 | path, 430 | other: UnaryPredicate(rules), 431 | } = parse_macro_input!(input as ReExportTuplez); 432 | let rules = rules.into_iter().map( 433 | |Rule { 434 | generic, 435 | mut inputs, 436 | output_type, 437 | body, 438 | }| { 439 | let (x, tyx, mutx) = inputs.pop_front().unwrap(); 440 | let tyx = tyx.unwrap(); 441 | let mutx = if mutx { quote!(mut) } else { quote!() }; 442 | let tyout = output_type.unwrap(); 443 | 444 | quote!( 445 | impl #generic Mapper<& #tyx> for __UnaryPred { 446 | type Output = #tyout; 447 | type NextMapper = Self; 448 | fn map(self, value: & #tyx) -> (Self::Output, Self::NextMapper) { 449 | let f = | #mutx #x : & #tyx | -> #tyout #body; 450 | (f(value), self) 451 | } 452 | } 453 | ) 454 | }, 455 | ); 456 | quote!( 457 | { 458 | use #path::foreach::Mapper; 459 | #[derive(Copy, Clone, Debug)] 460 | struct __UnaryPred; 461 | #(#rules)* 462 | __UnaryPred 463 | } 464 | ) 465 | .into() 466 | } 467 | 468 | #[proc_macro_derive(Tupleize)] 469 | pub fn tupleize_derive(input: TokenStream) -> TokenStream { 470 | let DeriveInput { 471 | attrs: _, 472 | vis: _, 473 | ident, 474 | generics, 475 | data, 476 | } = parse_macro_input!(input as DeriveInput); 477 | 478 | let Data::Struct(data) = data else { 479 | return syn::Error::new(ident.span(), "expected struct") 480 | .to_compile_error() 481 | .into(); 482 | }; 483 | let (tuple_ty, from_tuple, to_tuple) = data.fields.iter().enumerate().rev().fold( 484 | (quote!(tuplez::Unit), quote!(), quote!(tuplez::Unit)), 485 | |(ty, from, to), (index, field)| { 486 | let field_ty = &field.ty; 487 | let ty = quote!( ::tuplez::Tuple< #field_ty, #ty > ); 488 | match &field.ident { 489 | Some(ident) => { 490 | let field = quote!(. 1); 491 | let fields = vec![field.clone(); index]; 492 | let element = quote!( value #(#fields)* . 0); 493 | let from = quote!( #ident: #element, #from ); 494 | let to = quote!( ::tuplez::Tuple( value . #ident, #to) ); 495 | (ty, from, to) 496 | } 497 | None => { 498 | let field = quote!(. 1); 499 | let fields = vec![field.clone(); index]; 500 | let from = quote!( value #(#fields)* . 0, #from ); 501 | let index = syn::Index::from(index); 502 | let to = quote!( ::tuplez::Tuple( value . #index, #to) ); 503 | (ty, from, to) 504 | } 505 | } 506 | }, 507 | ); 508 | let from_tuple = match &data.fields { 509 | Fields::Named(_) => quote!( Self { #from_tuple } ), 510 | Fields::Unnamed(_) => quote!( Self(#from_tuple) ), 511 | Fields::Unit => quote!(Self), 512 | }; 513 | let (impl_generics, ty_generics, where_clause) = generics.split_for_impl(); 514 | quote!( 515 | impl #impl_generics ::std::convert::From<#ident #ty_generics> for #tuple_ty #where_clause { 516 | fn from(value: #ident #ty_generics) -> Self { 517 | #to_tuple 518 | } 519 | } 520 | 521 | impl #impl_generics ::std::convert::From<#tuple_ty> for #ident #ty_generics #where_clause { 522 | fn from(value: #tuple_ty) -> Self { 523 | #from_tuple 524 | } 525 | } 526 | 527 | impl #impl_generics ::tuplez::Tupleize for #ident #ty_generics #where_clause { 528 | type Equivalent = #tuple_ty; 529 | } 530 | ) 531 | .into() 532 | } 533 | -------------------------------------------------------------------------------- /tuplez-macros/src/parser.rs: -------------------------------------------------------------------------------- 1 | use std::{ 2 | collections::VecDeque, 3 | ops::{Add, AddAssign}, 4 | }; 5 | 6 | use quote::ToTokens; 7 | use syn::{ 8 | parse::Parse, parse_quote, Expr, ExprBlock, Generics, Ident, LitInt, Pat, Path, Token, Type, 9 | }; 10 | 11 | pub struct ReExportTuplez { 12 | pub path: Path, 13 | pub other: T, 14 | } 15 | 16 | impl Parse for ReExportTuplez { 17 | fn parse(input: syn::parse::ParseStream) -> syn::Result { 18 | let path = input.parse()?; 19 | let _: Token![;] = input.parse()?; 20 | let other = input.parse()?; 21 | Ok(Self { path, other }) 22 | } 23 | } 24 | 25 | pub struct TupleGen(pub Vec); 26 | 27 | impl Parse for TupleGen { 28 | fn parse(input: syn::parse::ParseStream) -> syn::Result { 29 | let mut exprs = vec![]; 30 | loop { 31 | if input.is_empty() { 32 | return Ok(TupleGen(exprs)); 33 | } 34 | let ty: Expr = input.parse()?; 35 | if input.is_empty() { 36 | exprs.push(ty); 37 | return Ok(TupleGen(exprs)); 38 | } 39 | let lookahead = input.lookahead1(); 40 | if lookahead.peek(Token![,]) { 41 | let _: Token![,] = input.parse()?; 42 | exprs.push(ty); 43 | continue; 44 | } 45 | if lookahead.peek(Token![;]) { 46 | let _: Token![;] = input.parse()?; 47 | let num: LitInt = input.parse()?; 48 | let num: usize = num.base10_parse()?; 49 | for _ in 0..num { 50 | exprs.push(ty.clone()); 51 | } 52 | if input.is_empty() { 53 | return Ok(TupleGen(exprs)); 54 | } 55 | let _: Token![,] = input.parse()?; 56 | } else { 57 | return Err(lookahead.error()); 58 | } 59 | } 60 | } 61 | } 62 | 63 | pub struct TupleType(pub Vec); 64 | 65 | impl Parse for TupleType { 66 | fn parse(input: syn::parse::ParseStream) -> syn::Result { 67 | let mut types = vec![]; 68 | loop { 69 | if input.is_empty() { 70 | return Ok(TupleType(types)); 71 | } 72 | let ty: Type = input.parse()?; 73 | if input.is_empty() { 74 | types.push(ty); 75 | return Ok(TupleType(types)); 76 | } 77 | let lookahead = input.lookahead1(); 78 | if lookahead.peek(Token![,]) { 79 | let _: Token![,] = input.parse()?; 80 | types.push(ty); 81 | continue; 82 | } 83 | if lookahead.peek(Token![;]) { 84 | let _: Token![;] = input.parse()?; 85 | let num: LitInt = input.parse()?; 86 | let num: usize = num.base10_parse()?; 87 | for _ in 0..num { 88 | types.push(ty.clone()); 89 | } 90 | if input.is_empty() { 91 | return Ok(TupleType(types)); 92 | } 93 | let _: Token![,] = input.parse()?; 94 | } else { 95 | return Err(lookahead.error()); 96 | } 97 | } 98 | } 99 | } 100 | 101 | pub struct TuplePat { 102 | pub pats: Vec, 103 | pub leader: bool, 104 | } 105 | 106 | impl Parse for TuplePat { 107 | fn parse(input: syn::parse::ParseStream) -> syn::Result { 108 | let mut pats = vec![]; 109 | let leader = if input.peek(Token![#]) { 110 | let _: Token![#] = input.parse()?; 111 | false 112 | } else { 113 | true 114 | }; 115 | loop { 116 | if input.is_empty() { 117 | return Ok(TuplePat { pats, leader }); 118 | } 119 | let pat = Pat::parse_multi(input)?; 120 | if input.is_empty() { 121 | pats.push(pat); 122 | return Ok(TuplePat { pats, leader }); 123 | } 124 | let lookahead = input.lookahead1(); 125 | if lookahead.peek(Token![,]) { 126 | let _: Token![,] = input.parse()?; 127 | pats.push(pat); 128 | continue; 129 | } 130 | if lookahead.peek(Token![;]) { 131 | let _: Token![;] = input.parse()?; 132 | let num: LitInt = input.parse()?; 133 | let num: usize = num.base10_parse()?; 134 | for _ in 0..num { 135 | pats.push(pat.clone()); 136 | } 137 | if input.is_empty() { 138 | return Ok(TuplePat { pats, leader }); 139 | } 140 | let _: Token![,] = input.parse()?; 141 | } else { 142 | return Err(lookahead.error()); 143 | } 144 | } 145 | } 146 | } 147 | 148 | pub struct TupleIndex { 149 | pub tup: Expr, 150 | pub index: usize, 151 | } 152 | 153 | impl Parse for TupleIndex { 154 | fn parse(input: syn::parse::ParseStream) -> syn::Result { 155 | let tup: Expr = input.parse()?; 156 | let _: Token![;] = input.parse()?; 157 | let index: LitInt = input.parse()?; 158 | let index: usize = index.base10_parse()?; 159 | Ok(TupleIndex { tup, index }) 160 | } 161 | } 162 | 163 | pub enum IndexOrType { 164 | Index(usize), 165 | Type(Type), 166 | } 167 | 168 | pub struct TupleTake { 169 | pub tup: Expr, 170 | pub ext: IndexOrType, 171 | } 172 | 173 | impl Parse for TupleTake { 174 | fn parse(input: syn::parse::ParseStream) -> syn::Result { 175 | let tup: Expr = input.parse()?; 176 | let _: Token![;] = input.parse()?; 177 | if input.peek(LitInt) { 178 | let index: LitInt = input.parse()?; 179 | let index: usize = index.base10_parse()?; 180 | return Ok(TupleTake { 181 | tup, 182 | ext: IndexOrType::Index(index), 183 | }); 184 | } 185 | let ty: Type = input.parse()?; 186 | Ok(TupleTake { 187 | tup, 188 | ext: IndexOrType::Type(ty), 189 | }) 190 | } 191 | } 192 | 193 | pub struct TuplePick { 194 | pub tup: Expr, 195 | pub indices: Vec, 196 | } 197 | 198 | impl Parse for TuplePick { 199 | fn parse(input: syn::parse::ParseStream) -> syn::Result { 200 | let tup = input.parse()?; 201 | let mut indices = Vec::::default(); 202 | let _: Token![;] = input.parse()?; 203 | loop { 204 | let start: LitInt = input.parse()?; 205 | let start: usize = start.base10_parse()?; 206 | let mut end = start; 207 | if input.peek(Token![-]) { 208 | let _: Token![-] = input.parse()?; 209 | let end_: LitInt = input.parse()?; 210 | end = end_.base10_parse()?; 211 | } 212 | if input.peek(Token![,]) { 213 | let _: Token![,] = input.parse()?; 214 | } 215 | if start <= end { 216 | (start..=end).for_each(|i| indices.push(i)); 217 | } else { 218 | (end..=start).rev().for_each(|i| indices.push(i)); 219 | } 220 | if input.is_empty() { 221 | break; 222 | } 223 | } 224 | 225 | Ok(TuplePick { tup, indices }) 226 | } 227 | } 228 | 229 | pub enum TupleArg { 230 | Move(usize), 231 | Ref(usize), 232 | Mut(usize), 233 | } 234 | 235 | #[derive(Default)] 236 | pub struct ArgList(pub Vec); 237 | 238 | impl Add for ArgList { 239 | type Output = Self; 240 | fn add(mut self, rhs: Self) -> Self::Output { 241 | self += rhs; 242 | self 243 | } 244 | } 245 | 246 | impl AddAssign for ArgList { 247 | fn add_assign(&mut self, mut rhs: Self) { 248 | self.0.append(&mut rhs.0); 249 | } 250 | } 251 | 252 | impl Parse for ArgList { 253 | fn parse(input: syn::parse::ParseStream) -> syn::Result { 254 | let mut args = Vec::new(); 255 | 256 | let mut ctor: fn(usize) -> TupleArg = TupleArg::Move; 257 | if input.peek(Token![&]) { 258 | let _: Token![&] = input.parse()?; 259 | ctor = TupleArg::Ref; 260 | if input.peek(Token![mut]) { 261 | let _: Token![mut] = input.parse()?; 262 | ctor = TupleArg::Mut; 263 | } 264 | } 265 | 266 | let start: LitInt = input.parse()?; 267 | let start: usize = start.base10_parse()?; 268 | let mut end = start; 269 | if input.peek(Token![-]) { 270 | let _: Token![-] = input.parse()?; 271 | let end_: LitInt = input.parse()?; 272 | end = end_.base10_parse()?; 273 | } 274 | if start <= end { 275 | (start..=end).for_each(|i| args.push(ctor(i))); 276 | } else { 277 | (end..=start).rev().for_each(|i| args.push(ctor(i))); 278 | } 279 | 280 | Ok(ArgList(args)) 281 | } 282 | } 283 | 284 | pub struct TupleSwap { 285 | pub tup: Expr, 286 | pub left: Vec, 287 | pub right: Vec, 288 | } 289 | 290 | impl Parse for TupleSwap { 291 | fn parse(input: syn::parse::ParseStream) -> syn::Result { 292 | let tup = input.parse()?; 293 | let mut left = vec![]; 294 | let mut right = vec![]; 295 | let _: Token![;] = input.parse()?; 296 | 297 | let left_start: LitInt = input.parse()?; 298 | let left_start: usize = left_start.base10_parse()?; 299 | let mut left_end = left_start; 300 | if input.peek(Token![-]) { 301 | let _: Token![-] = input.parse()?; 302 | let end: LitInt = input.parse()?; 303 | left_end = end.base10_parse()?; 304 | } 305 | if left_start <= left_end { 306 | (left_start..=left_end).for_each(|i| left.push(i)); 307 | } else { 308 | (left_end..=left_start).rev().for_each(|i| left.push(i)); 309 | } 310 | 311 | let _: Token![,] = input.parse()?; 312 | 313 | let right_start: LitInt = input.parse()?; 314 | let right_start: usize = right_start.base10_parse()?; 315 | let mut right_end = right_start; 316 | if input.peek(Token![-]) { 317 | let _: Token![-] = input.parse()?; 318 | let end: LitInt = input.parse()?; 319 | right_end = end.base10_parse()?; 320 | } 321 | if right_start <= right_end { 322 | (right_start..=right_end).for_each(|i| right.push(i)); 323 | } else { 324 | (right_end..=right_start).rev().for_each(|i| right.push(i)); 325 | } 326 | 327 | if left.len() != right.len() { 328 | return Err(input.error("Indices groups must be of equal length")); 329 | } 330 | 331 | if left.iter().any(|i| right.contains(i)) { 332 | return Err(input.error("Indices overlap")); 333 | } 334 | Ok(TupleSwap { tup, left, right }) 335 | } 336 | } 337 | 338 | pub struct TupleApply { 339 | pub tup: Expr, 340 | pub func: Expr, 341 | pub args: ArgList, 342 | } 343 | 344 | impl Parse for TupleApply { 345 | fn parse(input: syn::parse::ParseStream) -> syn::Result { 346 | let tup = input.parse()?; 347 | let _: Token![=>] = input.parse()?; 348 | let mut func: Expr = input.parse()?; 349 | 350 | let args = match &mut func { 351 | Expr::Call(call) => std::mem::take(&mut call.args), 352 | Expr::MethodCall(call) => std::mem::take(&mut call.args), 353 | _ => return Err(input.error("expected function call")), 354 | } 355 | .into_iter() 356 | .map(|arg| syn::parse2::(arg.into_token_stream())) 357 | .try_fold(ArgList::default(), |acc, x| x.map(|x| acc + x))?; 358 | 359 | Ok(TupleApply { tup, func, args }) 360 | } 361 | } 362 | 363 | pub struct Rule { 364 | pub generic: Option, 365 | pub inputs: VecDeque<(Ident, Option, bool)>, 366 | pub output_type: Option, 367 | pub body: ExprBlock, 368 | } 369 | 370 | impl Parse for Rule { 371 | fn parse(input: syn::parse::ParseStream) -> syn::Result { 372 | let generic = if input.peek(Token![<]) { 373 | Some(input.parse()?) 374 | } else { 375 | None 376 | }; 377 | let _: Token![|] = input.parse()?; 378 | let mut inputs = VecDeque::new(); 379 | loop { 380 | let mut mutable = false; 381 | if input.peek(Token![mut]) { 382 | let _: Token![mut] = input.parse()?; 383 | mutable = true; 384 | } 385 | let ident = input.parse()?; 386 | let mut ty = None; 387 | if input.peek(Token![:]) { 388 | let _: Token![:] = input.parse()?; 389 | ty = Some(input.parse()?); 390 | } 391 | inputs.push_back((ident, ty, mutable)); 392 | let lookahead = input.lookahead1(); 393 | if lookahead.peek(Token![,]) { 394 | let _: Token![,] = input.parse()?; 395 | } else if lookahead.peek(Token![|]) { 396 | let _: Token![|] = input.parse()?; 397 | break; 398 | } else { 399 | return Err(lookahead.error()); 400 | } 401 | } 402 | let mut output_type = None; 403 | if input.peek(Token![->]) { 404 | let _: Token![->] = input.parse()?; 405 | output_type = Some(input.parse()?); 406 | } 407 | let body = input.parse()?; 408 | loop { 409 | if input.peek(Token![,]) { 410 | let _: Token![,] = input.parse()?; 411 | } else if input.peek(Token![;]) { 412 | let _: Token![;] = input.parse()?; 413 | } else { 414 | break; 415 | } 416 | } 417 | 418 | Ok(Rule { 419 | generic, 420 | inputs, 421 | output_type, 422 | body, 423 | }) 424 | } 425 | } 426 | 427 | pub struct Mapper(pub Vec); 428 | 429 | impl Parse for Mapper { 430 | fn parse(input: syn::parse::ParseStream) -> syn::Result { 431 | let mut rules: Vec = vec![]; 432 | loop { 433 | if input.is_empty() { 434 | break; 435 | } 436 | rules.push(input.parse()?); 437 | } 438 | for r in &mut rules { 439 | if r.inputs.len() != 1 { 440 | return Err(input.error("expected exactly one parameter")); 441 | } 442 | if r.inputs[0].1.is_none() { 443 | return Err(input.error("expected type annotation for the parameter")); 444 | } 445 | r.output_type.get_or_insert(r.inputs[0].1.clone().unwrap()); 446 | } 447 | Ok(Mapper(rules)) 448 | } 449 | } 450 | 451 | pub struct Folder(pub Vec); 452 | 453 | impl Parse for Folder { 454 | fn parse(input: syn::parse::ParseStream) -> syn::Result { 455 | let acc_type: Type = input.parse()?; 456 | let _: Token![;] = input.parse()?; 457 | let mut rules: Vec = vec![]; 458 | loop { 459 | if input.is_empty() { 460 | break; 461 | } 462 | rules.push(input.parse()?); 463 | } 464 | for r in &mut rules { 465 | if r.inputs.len() != 2 { 466 | return Err(input.error("expected exactly two parameters")); 467 | } 468 | if r.inputs[1].1.is_none() { 469 | return Err(input.error("expected type annotation for the second parameter")); 470 | } 471 | r.inputs[0].1.get_or_insert(acc_type.clone()); 472 | r.output_type.get_or_insert(acc_type.clone()); 473 | } 474 | Ok(Folder(rules)) 475 | } 476 | } 477 | 478 | pub struct UnaryPredicate(pub Vec); 479 | 480 | impl Parse for UnaryPredicate { 481 | fn parse(input: syn::parse::ParseStream) -> syn::Result { 482 | let mut rules: Vec = vec![]; 483 | loop { 484 | if input.is_empty() { 485 | break; 486 | } 487 | rules.push(input.parse()?); 488 | } 489 | let bool_ty: Type = parse_quote!(bool); 490 | for r in &mut rules { 491 | if r.inputs.len() != 1 { 492 | return Err(input.error("expected exactly one parameter")); 493 | } 494 | if r.inputs[0].1.is_none() { 495 | return Err(input.error("expected type annotation for the parameter")); 496 | } 497 | r.output_type.get_or_insert(bool_ty.clone()); 498 | } 499 | Ok(UnaryPredicate(rules)) 500 | } 501 | } 502 | --------------------------------------------------------------------------------