├── .gitignore ├── .travis.yml ├── Cargo.toml ├── LICENSE-APACHE ├── LICENSE-MIT ├── README.md ├── README.tpl ├── src └── lib.rs └── tests ├── disable_without_specialization.rs ├── doc_comments.rs ├── flexible_machines.rs ├── multi_parameter_data.rs ├── smallfsck.rs ├── specialization_concrete.rs ├── specialization_data.rs ├── specific_attrs.rs └── unbounded_parameters.rs /.gitignore: -------------------------------------------------------------------------------- 1 | target 2 | Cargo.lock 3 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | sudo: false 2 | language: rust 3 | rust: 4 | - nightly 5 | - beta 6 | - stable 7 | before_script: 8 | - | 9 | pip install 'travis-cargo<0.2' --user && 10 | export PATH=$HOME/.local/bin:$PATH 11 | script: 12 | - | 13 | travis-cargo build && 14 | travis-cargo test && 15 | travis-cargo bench && 16 | travis-cargo --only stable doc 17 | after_success: 18 | - travis-cargo --only stable doc-upload 19 | env: 20 | global: 21 | - TRAVIS_CARGO_NIGHTLY_FEATURE=specialization 22 | - secure: 30REu+NvD+YtO7MKX8D9Wx+fGwErHlJl0hBv5Yvt3df+ThLxlq1UPwURfpbaxMcYLja46KwtyAp0PsFt6xAntylocdmxxVk8t+U9itQ1NTXgxnXwVhxdST6ryS3AmWp7QrdfaTSQM68o758YjY46mnRGIYjRPv11qK84IuMTaKr6LFQcRU2FuH86UgXJ4ZtcZppEl57165uCvuvbiUGu0JMXAHThvXEuQA53yjNTwa/gCEygL5/EiS843vavCuNImT/RvAcPoGt2YZZG4NHg61wKxdA+SC1UCypKZEPLgHpeyhcBhagLjGHpNQzhOcv9Axy22hBW1aMWPrujs44oN8MADKPb7NmjB9l3VvGgXrwJj7KqEfKF79iC6cFiVvF3LYEP5VK7ZdLTYpZnRJfSHcl2wKQzqNcjjQ/MksFB9EfT6hTayXqRtKASF5hVq7xU0T6h2MNBrnKrsRcfIQvLHzXCKW42wkSr00tddhMJnQavdQ3E+EkxI7lPpqj8N/aCloXRYGnE/mrRIBsu1O7W3ZD+pUZjuoK13e21MNAoKBOVZUjRg/gM++3ije3QcwIEqDKMjGpPMP/1rTiI9Wbo/Xi6PkexOXcKrxta9dR6in9mxli/CjdCJDEKYvactw65Y2wQcsthvK3o59ZjdAksxvzPHMCd8gtPgT4vb0PL0Yo= 23 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | authors = ["Sean Leffler "] 3 | description = "A macro system for creating type operators in Rust and writing type-level logic." 4 | documentation = "https://docs.rs/type-operators" 5 | homepage = "https://github.com/sdleffler/type-operators-rs" 6 | keywords = ["type", "type-level", "operator", "macro"] 7 | license = "MIT/Apache-2.0" 8 | name = "type-operators" 9 | readme = "README.md" 10 | repository = "https://github.com/sdleffler/type-operators-rs" 11 | version = "0.3.5" 12 | 13 | [dev-dependencies] 14 | bit-vec = "0.4.3" 15 | 16 | [features] 17 | default = [] 18 | nightly = ["specialization"] 19 | specialization = [] 20 | -------------------------------------------------------------------------------- /LICENSE-APACHE: -------------------------------------------------------------------------------- 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 2016 Sean Leffler 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) 2016 Sean Leffler 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 | [![Build Status](https://travis-ci.org/sdleffler/type-operators-rs.svg?branch=master)](https://travis-ci.org/sdleffler/type-operators-rs) 2 | [![Docs Status](https://docs.rs/type-operators/badge.svg)](https://docs.rs/type-operators) 3 | [![On crates.io](https://img.shields.io/crates/v/type-operators.svg)](https://crates.io/crates/type-operators) 4 | 5 | # type-operators 6 | 7 | ## The `type_operators` macro - a DSL for declaring type operators and type-level logic in Rust. 8 | 9 | This crate contains a macro for declaring type operators in Rust. Type operators are like functions 10 | which act at the type level. The `type_operators` macro works by translating a LISP-y DSL into a big mess of 11 | traits and impls with associated types. 12 | 13 | ## The DSL 14 | 15 | Let's take a look at this fairly small example: 16 | 17 | ```rust 18 | type_operators! { 19 | [A, B, C, D, E] 20 | 21 | data Nat { 22 | P, 23 | I(Nat = P), 24 | O(Nat = P), 25 | } 26 | } 27 | ``` 28 | 29 | There are two essential things to note in this example. The first is the "gensym list" - Rust does 30 | not currently have a way to generate unique identifiers, so we have to supply our own. It is on *you* 31 | to avoid clashes between these pseudo-gensyms and the names of the structs involved! If we put `P`, `I`, or `O` 32 | into the gensym list, things could get really bad! We'd get type errors at compile-time stemming from trait 33 | bounds, coming from the definitions of type operators later. Thankfully, the gensym list can be fairly small 34 | and usually never uses more than two or three symbols. 35 | 36 | The second thing is the `data` declaration. This declares a group of structs which fall under a marker trait. 37 | In our case, `Nat` is the marker trait generated and `P`, `I`, and `O` are the structs generated. This example 38 | shows an implementation of natural numbers (positive integers, including zero) which are represented as types. 39 | So, `P` indicates the end of a natural number - think of it as a sort of nil; we're working with a linked list 40 | here, at the type level. So, `I

` would represent "one plus twice `P`", which of course comes out to `1`; 41 | `O

` would represent "twice `P`", which of course comes out to zero. If we look at `I` and `O` as bits of a 42 | binary number, we come out with a sort of reversed binary representation where the "bit" furthest to the left 43 | is the least significant bit. As such, `O>` represents `4`, `I>>` represents `9`, and so on. 44 | 45 | When we write `I(Nat = P)`, the `= P` denotes a default. This lets us write `I`, and have it be inferred to be 46 | `I

`, which is probably what you mean if you just write `I` alone. `Nat` gives a trait bound. To better demonstrate, 47 | here is (roughly) what the above invocation of `type_operators` expands to: 48 | 49 | ```rust 50 | pub trait Nat {} 51 | 52 | pub struct P; 53 | impl Nat for P {} 54 | 55 | pub struct I(PhantomData<(A)>); 56 | impl Nat for I {} 57 | 58 | pub struct O(PhantomData<(A)>); 59 | impl Nat for O {} 60 | ``` 61 | 62 | The `Undefined` value looks a little silly, but it allows for the definition of division in a way which uses 63 | type-level comparison and branching. More on that later. 64 | 65 | The above definition has a problem. We cannot *fold* our type-level representation down into a numerical representation. 66 | That makes our type-level natural numbers useless! That's why `type_operators` provides another way of defining 67 | type-level representations, the `concrete` declaration: 68 | 69 | ```rust 70 | type_operators! { 71 | [A, B, C, D, E] 72 | 73 | concrete Nat => usize { 74 | P => 0, 75 | I(N: Nat = P) => 1 + 2 * N, 76 | O(N: Nat = P) => 2 * N, 77 | Undefined => panic!("Undefined type-level arithmetic result!"), 78 | } 79 | } 80 | ``` 81 | 82 | This adds an associated function to the `Nat` trait called `reify`, which allows you to turn your type-level 83 | representations into concrete values of type `usize` (in this case.) If you've ever seen primitive-recursive 84 | functions, then this should look a bit familiar to you - it's reminiscent of a recursion scheme, which is a 85 | way of recursing over a value to map it into something else. (See also "catamorphism".) It should be fairly 86 | obvious how this works, but if not, here's a breakdown: 87 | 88 | - `P` always represents zero, so we say that `P => 0`. Simple. 89 | - `I` represents double its argument plus one. If we annotate our macro's definition with a variable `N`, 90 | then `type_operators` will automatically call `N::reify()` and substitute that value for your `N` in the 91 | expression you give it. So, in this way, we define the reification of `I` to be one plus two times the 92 | value that `N` reifies to. 93 | - `O` represents double its argument, so this one's straightforward - it's like `I`, but without the `1 +`. 94 | 95 | Okay. So now that we've got that under our belts, let's dive into something a bit more complex: let's define 96 | a type operator for addition. 97 | 98 | `type_operators` allows you to define recursive functions. Speaking generally, that's what you'll really need 99 | to pull this off whatever you do. (And speaking precisely, this whole approach was inspired by primitive-recursion.) 100 | So let's think about how we can add two binary numbers, starting at the least-significant bit: 101 | - Obviously, `P + P` should be `P`, since zero plus zero is zero. 102 | - What about `P + O`, for any natural number `N`? Well, that should be `O`. Same with `I`. As a matter of 103 | fact, now it looks pretty obvious that whenever we have `P` on one side, we should just say that whatever's on the 104 | other side is the result. 105 | So our little table of operations now looks like: 106 | ```text 107 | [P, P] => P 108 | [P, (O N)] => (O N) 109 | [P, (I N)] => (I N) 110 | [(O N), P] => (O N) 111 | [(I N), P] => (I N) 112 | ``` 113 | Now you're probably saying, "whoa! That doesn't look like Rust at all! Back up!" And that's because it *isn't.* I made 114 | a little LISP-like dialect to describe Rust types for this project because it makes things a lot easier to parse in 115 | macros; specifically, each little atomic type can be wrapped up in a pair of parentheses, while with angle brackets, 116 | Rust has to parse them as separate tokens. In this setup, `(O N)` means `O`, 117 | just `P` alone means `P`, etc. etc. The notation `[X, Y] => Z` means "given inputs `X` and `Y`, produce output `Z`." So 118 | it's a sort of pattern-matching. 119 | 120 | Now let's look at the more complex cases. We need to cover all the parts where combinations of `O` and `I` are 121 | added together. 122 | - `O + O` should come out to `O`. This is a fairly intuitive result, but we can describe it mathematically 123 | as `2 * m + 2 * n == 2 * (m + n)`. So, it's the distributive law, and most importantly, it cuts down on the *structure* 124 | of the arguments - we go from adding `O` and `O` to `M` and `N`, whatever they are, and `M` and `N` are clearly 125 | less complex than `O` and `O`. If we always see that our outputs have less complexity than the inputs, then we're 126 | that much closer to a proof that our little type operator always terminates with a result! 127 | - `I + O` and `O + I` should come out to `I`. Again, fairly intuitive. We have `1 + 2 * m + 2 * n`, 128 | which we can package up into `1 + 2 * (m + n)`. 129 | - `I + I` is the trickiest part here. We have `1 + 2 * m + 1 + 2 * n == 2 + 2 * m + 2 * n == 2 * (1 + m + n)`. We 130 | can implement this as `I`, but we can do a little bit better. More on that later, we'll head with the simpler 131 | implementation for now. 132 | 133 | Let's add these to the table: 134 | ```text 135 | [P, P] => P 136 | [P, (O N)] => (O N) 137 | [P, (I N)] => (I N) 138 | [(O N), P] => (O N) 139 | [(I N), P] => (I N) 140 | // New: 141 | [(O M), (O N)] => (O (# M N)) 142 | [(I M), (O N)] => (I (# M N)) 143 | [(O M), (I N)] => (I (# M N)) 144 | [(I M), (I N)] => (O (# (# I M) N)) 145 | ``` 146 | Here's something new: the `(# ...)` notation. This tells the macro, "hey, we wanna recurse." It's really shorthand 147 | for a slightly more complex piece of notation, but they both have one thing in common - *when type_operators processes 148 | the `(# ...)` notation, it uses it to calculate trait bounds.* This is because your type operator won't compile unless 149 | it's absolutely certain that `(# M N)` will actually have a defined result. At an even higher level, this is the reason 150 | I wish Rust had "closed type families" - if `P`, `I`, and `O` were in a closed type family `Nat`, Rust could check at compile-time 151 | and be absolutely sure that `(# M N)` existed for all `M` and `N` that are in the `Nat` family. 152 | 153 | So then. Let's load this into an invocation of `type_operators` to see how it looks like. It's pretty close to the table, 154 | but with a couple additions (I'm leaving out `Undefined` for now because it's not yet relevant): 155 | 156 | ```rust 157 | type_operators! { 158 | [A, B, C, D, E] 159 | 160 | concrete Nat => usize { 161 | P => 0, 162 | I(N: Nat = P) => 1 + 2 * N, 163 | O(N: Nat = P) => 2 * N, 164 | } 165 | 166 | (Sum) Adding(Nat, Nat): Nat { 167 | [P, P] => P 168 | forall (N: Nat) { 169 | [(O N), P] => (O N) 170 | [(I N), P] => (I N) 171 | [P, (O N)] => (O N) 172 | [P, (I N)] => (I N) 173 | } 174 | forall (N: Nat, M: Nat) { 175 | [(O M), (O N)] => (O (# M N)) 176 | [(I M), (O N)] => (I (# M N)) 177 | [(O M), (I N)] => (I (# M N)) 178 | [(I M), (I N)] => (O (# (# M N) I)) 179 | } 180 | } 181 | } 182 | ``` 183 | 184 | There are several things to note. First, the definition `(Sum) Adding(Nat, Nat): Nat`. This says, 185 | "this type operator takes two `Nat`s as input and outputs a `Nat`." Since addition is implemented 186 | as a recursive trait under the hood, this means we get a trait definition of the form: 187 | 188 | ```rust 189 | pub trait Adding: Nat { 190 | type Output: Nat; 191 | } 192 | ``` 193 | 194 | The `(Sum)` bit declares a nice, convenient alias for us, so that instead of typing `>::Output` 195 | to get the sum of two numbers, we can instead type `Sum`. Much neater. 196 | 197 | Second, the "quantifier" sections (the parts with `forall`) avoid Rust complaining about "undeclared type variables." In any given 198 | generic `impl`, we have to worry about declaring what type variables/generic type parameters we can use in 199 | that `impl`. The `forall` bit modifies the prelude of the `impl`. For example, `forall (N: Nat)` causes all the 200 | `impl`s inside its little block to be declared as `impl ...` instead of `impl ...`, so that we can use 201 | `N` as a variable inside those expressions. 202 | 203 | That just about wraps up our short introduction. To finish, here are the rest of the notations specific to our 204 | little LISP-y dialect, all of which can only be used on the right-hand side of a rule in the DSL: 205 | 206 | - `(@TypeOperator ...)` invokes another type operator (can be the original caller!) and generates the proper trait bounds. 207 | - `(% ...)` is like `(# ...)`, but does not generate any trait bounds. 208 | - `(& where () () ...)` allows for the definition of custom `where` clauses for a given 209 | `impl`. It can appear anywhere in the right-hand side of a rule in the DSL, but in general should probably always be 210 | written at the top-level for consistency. 211 | 212 | In addition, it is possible to use attributes such as `#[derive(...)]` or `#[cfg(...)]` on `data` and `concrete` definitions 213 | as well as individual elements inside them. In addition, attributes can be added to the `impl`s for rules. For example: 214 | 215 | ```rust 216 | type_operators! { 217 | [A, B, C, D, E] 218 | 219 | data Nat: Default + Debug where #[derive(Default, Debug)] { 220 | P, 221 | I(Nat = P), 222 | O(Nat = P), 223 | #[cfg(features = "specialization")] 224 | Error, 225 | #[cfg(features = "specialization")] 226 | DEFAULT, 227 | } 228 | 229 | (Sum) Adding(Nat, Nat): Nat { 230 | [P, P] => P 231 | forall (N: Nat) { 232 | [(O N), P] => (O N) 233 | [(I N), P] => (I N) 234 | [P, (O N)] => (O N) 235 | [P, (I N)] => (I N) 236 | } 237 | forall (N: Nat, M: Nat) { 238 | [(O M), (O N)] => (O (# M N)) 239 | [(I M), (O N)] => (I (# M N)) 240 | [(O M), (I N)] => (I (# M N)) 241 | [(I M), (I N)] => (O (# (# M N) I)) 242 | 243 | #[cfg(features = "specialization")] { 244 | {M, N} => Error 245 | } 246 | } 247 | } 248 | } 249 | ``` 250 | 251 | Note the block `#[cfg(features = "specialization")] { ... }`. This tells `type_operators!` to add the attribute 252 | `#[cfg(features = "specialization")]` to every `impl` declared inside. It's also worth noting that adding derives 253 | to every single statement inside a `concrete` or `data` declaration can be done as shown above with a `where` 254 | clause-like structure - the reason we have to do this is because if we were allowed to define it the intuitive 255 | way, there would be no easy way to extract doc comments on the group trait (thanks to macro parsing ambiguities.) 256 | 257 | Current bugs/improvements to be made: 258 | - Bounds in type operators are currently restricted to identifiers only - they should be augmented with a LISP-like 259 | dialect similar to the rest of the macro system. 260 | 261 | If questions are had, I may be found either at my email (which is listed on GitHub) or on the `#rust` IRC, where I go by 262 | the nick `sleffy`. 263 | 264 | 265 | ## License 266 | 267 | Licensed under either of 268 | 269 | * Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or http://www.apache.org/licenses/LICENSE-2.0) 270 | * MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT) 271 | 272 | at your option. 273 | 274 | ### Contribution 275 | 276 | Unless you explicitly state otherwise, any contribution intentionally 277 | submitted for inclusion in the work by you, as defined in the Apache-2.0 278 | license, shall be dual licensed as above, without any additional terms or 279 | conditions. 280 | -------------------------------------------------------------------------------- /README.tpl: -------------------------------------------------------------------------------- 1 | [![Build Status](https://travis-ci.org/sdleffler/type-operators-rs.svg?branch=master)](https://travis-ci.org/sdleffler/type-operators-rs) 2 | [![Docs Status](https://docs.rs/type-operators/badge.svg)](https://docs.rs/type-operators) 3 | [![On crates.io](https://img.shields.io/crates/v/type-operators.svg)](https://crates.io/crates/type-operators) 4 | 5 | {{readme}} 6 | 7 | ## License 8 | 9 | Licensed under either of 10 | 11 | * Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or http://www.apache.org/licenses/LICENSE-2.0) 12 | * MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT) 13 | 14 | at your option. 15 | 16 | ### Contribution 17 | 18 | Unless you explicitly state otherwise, any contribution intentionally 19 | submitted for inclusion in the work by you, as defined in the Apache-2.0 20 | license, shall be dual licensed as above, without any additional terms or 21 | conditions. 22 | -------------------------------------------------------------------------------- /src/lib.rs: -------------------------------------------------------------------------------- 1 | //! # The `type_operators` macro - a DSL for declaring type operators and type-level logic in Rust. 2 | //! 3 | //! This crate contains a macro for declaring type operators in Rust. Type operators are like functions 4 | //! which act at the type level. The `type_operators` macro works by translating a LISP-y DSL into a big mess of 5 | //! traits and impls with associated types. 6 | //! 7 | //! # The DSL 8 | //! 9 | //! Let's take a look at this fairly small example: 10 | //! 11 | //! ```rust 12 | //! # #[macro_use] extern crate type_operators; 13 | //! type_operators! { 14 | //! [A, B, C, D, E] 15 | //! 16 | //! data Nat { 17 | //! P, 18 | //! I(Nat = P), 19 | //! O(Nat = P), 20 | //! } 21 | //! } 22 | //! # fn main() {} 23 | //! ``` 24 | //! 25 | //! There are two essential things to note in this example. The first is the "gensym list" - Rust does 26 | //! not currently have a way to generate unique identifiers, so we have to supply our own. It is on *you* 27 | //! to avoid clashes between these pseudo-gensyms and the names of the structs involved! If we put `P`, `I`, or `O` 28 | //! into the gensym list, things could get really bad! We'd get type errors at compile-time stemming from trait 29 | //! bounds, coming from the definitions of type operators later. Thankfully, the gensym list can be fairly small 30 | //! and usually never uses more than two or three symbols. 31 | //! 32 | //! The second thing is the `data` declaration. This declares a group of structs which fall under a marker trait. 33 | //! In our case, `Nat` is the marker trait generated and `P`, `I`, and `O` are the structs generated. This example 34 | //! shows an implementation of natural numbers (positive integers, including zero) which are represented as types. 35 | //! So, `P` indicates the end of a natural number - think of it as a sort of nil; we're working with a linked list 36 | //! here, at the type level. So, `I

` would represent "one plus twice `P`", which of course comes out to `1`; 37 | //! `O

` would represent "twice `P`", which of course comes out to zero. If we look at `I` and `O` as bits of a 38 | //! binary number, we come out with a sort of reversed binary representation where the "bit" furthest to the left 39 | //! is the least significant bit. As such, `O>` represents `4`, `I>>` represents `9`, and so on. 40 | //! 41 | //! When we write `I(Nat = P)`, the `= P` denotes a default. This lets us write `I`, and have it be inferred to be 42 | //! `I

`, which is probably what you mean if you just write `I` alone. `Nat` gives a trait bound. To better demonstrate, 43 | //! here is (roughly) what the above invocation of `type_operators` expands to: 44 | //! 45 | //! ```rust 46 | //! # use std::marker::PhantomData; 47 | //! 48 | //! pub trait Nat {} 49 | //! 50 | //! pub struct P; 51 | //! impl Nat for P {} 52 | //! 53 | //! pub struct I(PhantomData<(A)>); 54 | //! impl Nat for I {} 55 | //! 56 | //! pub struct O(PhantomData<(A)>); 57 | //! impl Nat for O {} 58 | //! # fn main() {} 59 | //! ``` 60 | //! 61 | //! The `Undefined` value looks a little silly, but it allows for the definition of division in a way which uses 62 | //! type-level comparison and branching. More on that later. 63 | //! 64 | //! The above definition has a problem. We cannot *fold* our type-level representation down into a numerical representation. 65 | //! That makes our type-level natural numbers useless! That's why `type_operators` provides another way of defining 66 | //! type-level representations, the `concrete` declaration: 67 | //! 68 | //! ```rust 69 | //! # #[macro_use] 70 | //! # extern crate type_operators; 71 | //! 72 | //! type_operators! { 73 | //! [A, B, C, D, E] 74 | //! 75 | //! concrete Nat => usize { 76 | //! P => 0, 77 | //! I(N: Nat = P) => 1 + 2 * N, 78 | //! O(N: Nat = P) => 2 * N, 79 | //! Undefined => panic!("Undefined type-level arithmetic result!"), 80 | //! } 81 | //! } 82 | //! # fn main() {} 83 | //! ``` 84 | //! 85 | //! This adds an associated function to the `Nat` trait called `reify`, which allows you to turn your type-level 86 | //! representations into concrete values of type `usize` (in this case.) If you've ever seen primitive-recursive 87 | //! functions, then this should look a bit familiar to you - it's reminiscent of a recursion scheme, which is a 88 | //! way of recursing over a value to map it into something else. (See also "catamorphism".) It should be fairly 89 | //! obvious how this works, but if not, here's a breakdown: 90 | //! 91 | //! - `P` always represents zero, so we say that `P => 0`. Simple. 92 | //! - `I` represents double its argument plus one. If we annotate our macro's definition with a variable `N`, 93 | //! then `type_operators` will automatically call `N::reify()` and substitute that value for your `N` in the 94 | //! expression you give it. So, in this way, we define the reification of `I` to be one plus two times the 95 | //! value that `N` reifies to. 96 | //! - `O` represents double its argument, so this one's straightforward - it's like `I`, but without the `1 +`. 97 | //! 98 | //! Okay. So now that we've got that under our belts, let's dive into something a bit more complex: let's define 99 | //! a type operator for addition. 100 | //! 101 | //! `type_operators` allows you to define recursive functions. Speaking generally, that's what you'll really need 102 | //! to pull this off whatever you do. (And speaking precisely, this whole approach was inspired by primitive-recursion.) 103 | //! So let's think about how we can add two binary numbers, starting at the least-significant bit: 104 | //! - Obviously, `P + P` should be `P`, since zero plus zero is zero. 105 | //! - What about `P + O`, for any natural number `N`? Well, that should be `O`. Same with `I`. As a matter of 106 | //! fact, now it looks pretty obvious that whenever we have `P` on one side, we should just say that whatever's on the 107 | //! other side is the result. 108 | //! So our little table of operations now looks like: 109 | //! ```text 110 | //! [P, P] => P 111 | //! [P, (O N)] => (O N) 112 | //! [P, (I N)] => (I N) 113 | //! [(O N), P] => (O N) 114 | //! [(I N), P] => (I N) 115 | //! ``` 116 | //! Now you're probably saying, "whoa! That doesn't look like Rust at all! Back up!" And that's because it *isn't.* I made 117 | //! a little LISP-like dialect to describe Rust types for this project because it makes things a lot easier to parse in 118 | //! macros; specifically, each little atomic type can be wrapped up in a pair of parentheses, while with angle brackets, 119 | //! Rust has to parse them as separate tokens. In this setup, `(O N)` means `O`, 120 | //! just `P` alone means `P`, etc. etc. The notation `[X, Y] => Z` means "given inputs `X` and `Y`, produce output `Z`." So 121 | //! it's a sort of pattern-matching. 122 | //! 123 | //! Now let's look at the more complex cases. We need to cover all the parts where combinations of `O` and `I` are 124 | //! added together. 125 | //! - `O + O` should come out to `O`. This is a fairly intuitive result, but we can describe it mathematically 126 | //! as `2 * m + 2 * n == 2 * (m + n)`. So, it's the distributive law, and most importantly, it cuts down on the *structure* 127 | //! of the arguments - we go from adding `O` and `O` to `M` and `N`, whatever they are, and `M` and `N` are clearly 128 | //! less complex than `O` and `O`. If we always see that our outputs have less complexity than the inputs, then we're 129 | //! that much closer to a proof that our little type operator always terminates with a result! 130 | //! - `I + O` and `O + I` should come out to `I`. Again, fairly intuitive. We have `1 + 2 * m + 2 * n`, 131 | //! which we can package up into `1 + 2 * (m + n)`. 132 | //! - `I + I` is the trickiest part here. We have `1 + 2 * m + 1 + 2 * m == 2 + 2 * m + 2 * n == 2 * (1 + m + n)`. We 133 | //! can implement this as `I`, but we can do a little bit better. More on that later, we'll head with the simpler 134 | //! implementation for now. 135 | //! 136 | //! Let's add these to the table: 137 | //! ```text 138 | //! [P, P] => P 139 | //! [P, (O N)] => (O N) 140 | //! [P, (I N)] => (I N) 141 | //! [(O N), P] => (O N) 142 | //! [(I N), P] => (I N) 143 | //! // New: 144 | //! [(O M), (O N)] => (O (# M N)) 145 | //! [(I M), (O N)] => (I (# M N)) 146 | //! [(O M), (I N)] => (I (# M N)) 147 | //! [(I M), (I N)] => (O (# (# I M) N)) 148 | //! ``` 149 | //! Here's something new: the `(# ...)` notation. This tells the macro, "hey, we wanna recurse." It's really shorthand 150 | //! for a slightly more complex piece of notation, but they both have one thing in common - *when type_operators processes 151 | //! the `(# ...)` notation, it uses it to calculate trait bounds.* This is because your type operator won't compile unless 152 | //! it's absolutely certain that `(# M N)` will actually have a defined result. At an even higher level, this is the reason 153 | //! I wish Rust had "closed type families" - if `P`, `I`, and `O` were in a closed type family `Nat`, Rust could check at compile-time 154 | //! and be absolutely sure that `(# M N)` existed for all `M` and `N` that are in the `Nat` family. 155 | //! 156 | //! So then. Let's load this into an invocation of `type_operators` to see how it looks like. It's pretty close to the table, 157 | //! but with a couple additions (I'm leaving out `Undefined` for now because it's not yet relevant): 158 | //! 159 | //! ```rust 160 | //! # #[macro_use] extern crate type_operators; 161 | //! 162 | //! type_operators! { 163 | //! [A, B, C, D, E] 164 | //! 165 | //! concrete Nat => usize { 166 | //! P => 0, 167 | //! I(N: Nat = P) => 1 + 2 * N, 168 | //! O(N: Nat = P) => 2 * N, 169 | //! } 170 | //! 171 | //! (Sum) Adding(Nat, Nat): Nat { 172 | //! [P, P] => P 173 | //! forall (N: Nat) { 174 | //! [(O N), P] => (O N) 175 | //! [(I N), P] => (I N) 176 | //! [P, (O N)] => (O N) 177 | //! [P, (I N)] => (I N) 178 | //! } 179 | //! forall (N: Nat, M: Nat) { 180 | //! [(O M), (O N)] => (O (# M N)) 181 | //! [(I M), (O N)] => (I (# M N)) 182 | //! [(O M), (I N)] => (I (# M N)) 183 | //! [(I M), (I N)] => (O (# (# M N) I)) 184 | //! } 185 | //! } 186 | //! } 187 | //! # fn main() {} 188 | //! ``` 189 | //! 190 | //! There are several things to note. First, the definition `(Sum) Adding(Nat, Nat): Nat`. This says, 191 | //! "this type operator takes two `Nat`s as input and outputs a `Nat`." Since addition is implemented 192 | //! as a recursive trait under the hood, this means we get a trait definition of the form: 193 | //! 194 | //! ```rust 195 | //! # pub trait Nat {} 196 | //! pub trait Adding: Nat { 197 | //! type Output: Nat; 198 | //! } 199 | //! ``` 200 | //! 201 | //! The `(Sum)` bit declares a nice, convenient alias for us, so that instead of typing `>::Output` 202 | //! to get the sum of two numbers, we can instead type `Sum`. Much neater. 203 | //! 204 | //! Second, the "quantifier" sections (the parts with `forall`) avoid Rust complaining about "undeclared type variables." In any given 205 | //! generic `impl`, we have to worry about declaring what type variables/generic type parameters we can use in 206 | //! that `impl`. The `forall` bit modifies the prelude of the `impl`. For example, `forall (N: Nat)` causes all the 207 | //! `impl`s inside its little block to be declared as `impl ...` instead of `impl ...`, so that we can use 208 | //! `N` as a variable inside those expressions. 209 | //! 210 | //! That just about wraps up our short introduction. To finish, here are the rest of the notations specific to our 211 | //! little LISP-y dialect, all of which can only be used on the right-hand side of a rule in the DSL: 212 | //! 213 | //! - `(@TypeOperator ...)` invokes another type operator (can be the original caller!) and generates the proper trait bounds. 214 | //! - `(% ...)` is like `(# ...)`, but does not generate any trait bounds. 215 | //! - `(& where () () ...)` allows for the definition of custom `where` clauses for a given 216 | //! `impl`. It can appear anywhere in the right-hand side of a rule in the DSL, but in general should probably always be 217 | //! written at the top-level for consistency. 218 | //! 219 | //! In addition, it is possible to use attributes such as `#[derive(...)]` or `#[cfg(...)]` on `data` and `concrete` definitions 220 | //! as well as individual elements inside them. In addition, attributes can be added to the `impl`s for rules. For example: 221 | //! 222 | //! ```rust 223 | //! # #[macro_use] extern crate type_operators; 224 | //! # use std::fmt::Debug; 225 | //! type_operators! { 226 | //! [A, B, C, D, E] 227 | //! 228 | //! data Nat: Default + Debug where #[derive(Default, Debug)] { 229 | //! P, 230 | //! I(Nat = P), 231 | //! O(Nat = P), 232 | //! #[cfg(features = "specialization")] 233 | //! Error, 234 | //! #[cfg(features = "specialization")] 235 | //! DEFAULT, 236 | //! } 237 | //! 238 | //! (Sum) Adding(Nat, Nat): Nat { 239 | //! [P, P] => P 240 | //! forall (N: Nat) { 241 | //! [(O N), P] => (O N) 242 | //! [(I N), P] => (I N) 243 | //! [P, (O N)] => (O N) 244 | //! [P, (I N)] => (I N) 245 | //! } 246 | //! forall (N: Nat, M: Nat) { 247 | //! [(O M), (O N)] => (O (# M N)) 248 | //! [(I M), (O N)] => (I (# M N)) 249 | //! [(O M), (I N)] => (I (# M N)) 250 | //! [(I M), (I N)] => (O (# (# M N) I)) 251 | //! 252 | //! #[cfg(features = "specialization")] { 253 | //! {M, N} => Error 254 | //! } 255 | //! } 256 | //! } 257 | //! } 258 | //! # fn main() {} 259 | //! ``` 260 | //! 261 | //! Note the block `#[cfg(features = "specialization")] { ... }`. This tells `type_operators!` to add the attribute 262 | //! `#[cfg(features = "specialization")]` to every `impl` declared inside. It's also worth noting that adding derives 263 | //! to every single statement inside a `concrete` or `data` declaration can be done as shown above with a `where` 264 | //! clause-like structure - the reason we have to do this is because if we were allowed to define it the intuitive 265 | //! way, there would be no easy way to extract doc comments on the group trait (thanks to macro parsing ambiguities.) 266 | //! 267 | //! Current bugs/improvements to be made: 268 | //! - Bounds in type operators are currently restricted to identifiers only - they should be augmented with a LISP-like 269 | //! dialect similar to the rest of the macro system. 270 | //! 271 | //! If questions are had, I may be found either at my email (which is listed on GitHub) or on the `#rust` IRC, where I go by 272 | //! the nick `sleffy`. 273 | //! 274 | 275 | 276 | /// The `All` trait provides a workaround to the current parsing problem of a lack of truly unbounded type operator 277 | /// arguments. It's implemented for all types. 278 | pub trait All {} 279 | impl All for T {} 280 | 281 | 282 | /// The `type_operators` macro does a lot of different things. Specifically, there are two things 283 | /// it's meant to do: 284 | /// 1. Make declaring closed type families easier. (Although they never *really* end up closed... Good enough.) 285 | /// 2. Make declaring type operators easier. (Although there are still a lotta problems with this.) 286 | /// 287 | /// By "closed type family" here, I mean a family of structs which have a marker trait indicating that they 288 | /// "belong" to the family. A sort of type-level enum, if you will (if only something like that could truly 289 | /// exist in Rust some day!) And by "type operator", I mean a sort of function which acts on types and returns 290 | /// a type. In the following example, the natural numbers (encoded in binary here) are our "closed type family", 291 | /// and addition, subtraction, multiplication, division, etc. etc. are all our type operators. 292 | /// 293 | /// You should probably read the top-level documentation before you look at this more complex example. 294 | /// 295 | /// ``` 296 | /// # #[macro_use] 297 | /// # extern crate type_operators; 298 | /// 299 | /// type_operators! { 300 | /// [A, B, C, D, E] // The gensym list. Be careful not to have these collide with your struct names! 301 | /// 302 | /// // If I used `data` instead of concrete, no automatic `reify` function would be provided. 303 | /// // But since I did, we have a sort of inductive thing going on here, by which we can transform 304 | /// // any instance of this type into the reified version. 305 | /// 306 | /// // data Nat { 307 | /// // P, 308 | /// // I(Nat = P), 309 | /// // O(Nat = P), 310 | /// // } 311 | /// 312 | /// concrete Nat => usize { 313 | /// P => 0, 314 | /// I(N: Nat = P) => 1 + 2 * N, 315 | /// O(N: Nat = P) => 2 * N, 316 | /// Undefined => panic!("Undefined type-level arithmetic result!"), 317 | /// } 318 | /// 319 | /// // It's not just for natural numbers! Yes, we can do all sorts of logic here. However, in 320 | /// // this example, `Bool` is used later on in implementations that are hidden from you due 321 | /// // to their complexity. 322 | /// concrete Bool => bool { 323 | /// False => false, 324 | /// True => true, 325 | /// } 326 | /// 327 | /// (Pred) Predecessor(Nat): Nat { 328 | /// [Undefined] => Undefined 329 | /// [P] => Undefined 330 | /// forall (N: Nat) { 331 | /// [(O N)] => (I (# N)) 332 | /// [(I N)] => (O N) 333 | /// } 334 | /// } 335 | /// 336 | /// (Succ) Successor(Nat): Nat { 337 | /// [Undefined] => Undefined 338 | /// [P] => I 339 | /// forall (N: Nat) { 340 | /// [(O N)] => (I N) 341 | /// [(I N)] => (O (# N)) 342 | /// } 343 | /// } 344 | /// 345 | /// (Sum) Adding(Nat, Nat): Nat { 346 | /// [P, P] => P 347 | /// forall (N: Nat) { 348 | /// [(O N), P] => (O N) 349 | /// [(I N), P] => (I N) 350 | /// [P, (O N)] => (O N) 351 | /// [P, (I N)] => (I N) 352 | /// } 353 | /// forall (N: Nat, M: Nat) { 354 | /// [(O M), (O N)] => (O (# M N)) 355 | /// [(I M), (O N)] => (I (# M N)) 356 | /// [(O M), (I N)] => (I (# M N)) 357 | /// [(I M), (I N)] => (O (# (# M N) I)) 358 | /// } 359 | /// } 360 | /// 361 | /// (Difference) Subtracting(Nat, Nat): Nat { 362 | /// forall (N: Nat) { 363 | /// [N, P] => N 364 | /// } 365 | /// forall (N: Nat, M: Nat) { 366 | /// [(O M), (O N)] => (O (# M N)) 367 | /// [(I M), (O N)] => (I (# M N)) 368 | /// [(O M), (I N)] => (I (# (# M N) I)) 369 | /// [(I M), (I N)] => (O (# M N)) 370 | /// } 371 | /// } 372 | /// 373 | /// (Product) Multiplying(Nat, Nat): Nat { 374 | /// forall (N: Nat) { 375 | /// [P, N] => P 376 | /// } 377 | /// forall (N: Nat, M: Nat) { 378 | /// [(O M), N] => (# M (O N)) 379 | /// [(I M), N] => (@Adding N (# M (O N))) 380 | /// } 381 | /// } 382 | /// 383 | /// (If) NatIf(Bool, Nat, Nat): Nat { 384 | /// forall (T: Nat, U: Nat) { 385 | /// [True, T, U] => T 386 | /// [False, T, U] => U 387 | /// } 388 | /// } 389 | /// 390 | /// (NatIsUndef) NatIsUndefined(Nat): Bool { 391 | /// [Undefined] => True 392 | /// [P] => False 393 | /// forall (M: Nat) { 394 | /// [(O M)] => False 395 | /// [(I M)] => False 396 | /// } 397 | /// } 398 | /// 399 | /// (NatUndef) NatUndefined(Nat, Nat): Nat { 400 | /// forall (M: Nat) { 401 | /// [Undefined, M] => Undefined 402 | /// [P, M] => M 403 | /// } 404 | /// forall (M: Nat, N: Nat) { 405 | /// [(O N), M] => M 406 | /// [(I N), M] => M 407 | /// } 408 | /// } 409 | /// 410 | /// (TotalDifference) TotalSubtracting(Nat, Nat): Nat { 411 | /// [P, P] => P 412 | /// [Undefined, P] => Undefined 413 | /// forall (N: Nat) { 414 | /// [N, Undefined] => Undefined 415 | /// [P, (O N)] => (# P N) 416 | /// [P, (I N)] => Undefined 417 | /// [(O N), P] => (O N) 418 | /// [(I N), P] => (I N) 419 | /// [Undefined, (O N)] => Undefined 420 | /// [Undefined, (I N)] => Undefined 421 | /// } 422 | /// forall (N: Nat, M: Nat) { 423 | /// [(O M), (O N)] => (@NatUndefined (# M N) (O (# M N))) 424 | /// [(I M), (O N)] => (@NatUndefined (# M N) (I (# M N))) 425 | /// [(O M), (I N)] => (@NatUndefined (# (# M N) I) (I (# (# M N) I))) 426 | /// [(I M), (I N)] => (@NatUndefined (# M N) (O (# M N))) 427 | /// } 428 | /// } 429 | /// 430 | /// (Quotient) Quotienting(Nat, Nat): Nat { 431 | /// forall (D: Nat) { 432 | /// [Undefined, D] => Undefined 433 | /// [P, D] => (@NatIf (@NatIsUndefined (@TotalSubtracting P D)) O (@Successor (# (@TotalSubtracting P D) D))) 434 | /// } 435 | /// forall (N: Nat, D: Nat) { 436 | /// [(O N), D] => (@NatIf (@NatIsUndefined (@TotalSubtracting (O N) D)) O (@Successor (# (@TotalSubtracting (O N) D) D))) 437 | /// [(I N), D] => (@NatIf (@NatIsUndefined (@TotalSubtracting (I N) D)) O (@Successor (# (@TotalSubtracting (I N) D) D))) 438 | /// } 439 | /// } 440 | /// 441 | /// (Remainder) Remaindering(Nat, Nat): Nat { 442 | /// forall (D: Nat) { 443 | /// [Undefined, D] => Undefined 444 | /// [P, D] => (@NatIf (@NatIsUndefined (@TotalSubtracting P D)) P (# (@TotalSubtracting P D) D)) 445 | /// } 446 | /// forall (N: Nat, D: Nat) { 447 | /// [(O N), D] => (@NatIf (@NatIsUndefined (@TotalSubtracting (O N) D)) (O N) (# (@TotalSubtracting (O N) D) D)) 448 | /// [(I N), D] => (@NatIf (@NatIsUndefined (@TotalSubtracting (I N) D)) (I O) (# (@TotalSubtracting (I N) D) D)) 449 | /// } 450 | /// } 451 | /// } 452 | /// 453 | /// # fn main() { 454 | /// assert_eq!( as Nat>::reify(), 3); 455 | /// assert_eq!(> as Nat>::reify(), 5); 456 | /// assert_eq!(>, I> as Nat>::reify(), 8); 457 | /// assert_eq!(, O> as Nat>::reify(), 1); 458 | /// assert_eq!(>>, I> as Nat>::reify(), 5); 459 | /// assert_eq!(, I>> as Nat>::reify(), 15); 460 | /// assert_eq!(, O> as Nat>::reify(), 1); 461 | /// assert_eq!(>>, O>> as Nat>::reify(), 1); 462 | /// # } 463 | /// ``` 464 | #[macro_export] 465 | macro_rules! type_operators { 466 | ($gensym:tt $(#$docs:tt)* data $name:ident: $fbound:ident $(+ $bound:ident)* where $(#$attr:tt)+ { $($stuff:tt)* } $($rest:tt)*) => { 467 | $(#$docs)* 468 | pub trait $name: $fbound $(+ $bound)* {} 469 | 470 | _tlsm_data!([$name ($fbound $(+ $bound)*) [] $($attr)*] $gensym $($stuff)*); 471 | type_operators!($gensym $($rest)*); 472 | }; 473 | ($gensym:tt $(#$docs:tt)* data $name:ident where $(#$attr:tt)+ { $($stuff:tt)* } $($rest:tt)*) => { 474 | $(#$docs)* 475 | pub trait $name {} 476 | 477 | _tlsm_data!([$name () [] $($attr)*] $gensym $($stuff)*); 478 | type_operators!($gensym $($rest)*); 479 | }; 480 | ($gensym:tt $(#$docs:tt)* data $name:ident: $fbound:ident $(+ $bound:ident)* { $($stuff:tt)* } $($rest:tt)*) => { 481 | $(#$docs)* 482 | pub trait $name: $fbound $(+ $bound)* {} 483 | 484 | _tlsm_data!([$name ($fbound $(+ $bound)*) []] $gensym $($stuff)*); 485 | type_operators!($gensym $($rest)*); 486 | }; 487 | ($gensym:tt $(#$docs:tt)* data $name:ident { $($stuff:tt)* } $($rest:tt)*) => { 488 | $(#$docs)* 489 | pub trait $name {} 490 | 491 | _tlsm_data!([$name () []] $gensym $($stuff)*); 492 | type_operators!($gensym $($rest)*); 493 | }; 494 | 495 | ($gensym:tt $(#$docs:tt)* concrete $name:ident: $fbound:ident $(+ $bound:ident)* => $output:ty where $(#$attr:tt)+ { $($stuff:tt)* } $($rest:tt)*) => { 496 | $(#$docs)* 497 | pub trait $name: $fbound $(+ $bound)* { 498 | fn reify() -> $output; 499 | } 500 | 501 | _tlsm_concrete!([$name ($fbound $(+ $bound)*) [] $($attr)*] $output; $gensym $($stuff)*); 502 | type_operators!($gensym $($rest)*); 503 | }; 504 | ($gensym:tt $(#$docs:tt)* concrete $name:ident => $output:ty where $(#$attr:tt)+ { $($stuff:tt)* } $($rest:tt)*) => { 505 | $(#$docs)* 506 | pub trait $name { 507 | fn reify() -> $output; 508 | } 509 | 510 | _tlsm_concrete!([$name () [] $($attr)*] $output; $gensym $($stuff)*); 511 | type_operators!($gensym $($rest)*); 512 | }; 513 | ($gensym:tt $(#$docs:tt)* concrete $name:ident: $fbound:ident $(+ $bound:ident)* => $output:ty { $($stuff:tt)* } $($rest:tt)*) => { 514 | $(#$docs)* 515 | pub trait $name: $fbound $(+ $bound)* { 516 | fn reify() -> $output; 517 | } 518 | 519 | _tlsm_concrete!([$name ($fbound $(+ $bound)*) []] $output; $gensym $($stuff)*); 520 | type_operators!($gensym $($rest)*); 521 | }; 522 | ($gensym:tt $(#$docs:tt)* concrete $name:ident => $output:ty { $($stuff:tt)* } $($rest:tt)*) => { 523 | $(#$docs)* 524 | pub trait $name { 525 | fn reify() -> $output; 526 | } 527 | 528 | _tlsm_concrete!([$name () []] $output; $gensym $($stuff)*); 529 | type_operators!($gensym $($rest)*); 530 | }; 531 | 532 | ($gensym:tt $(#$docs:tt)* ($alias:ident) $machine:ident ($($kind:tt)*): $out:tt where $(#$attr:tt)* { $($states:tt)* } $($rest:tt)*) => { 533 | _tlsm_machine!([$($docs)*] [$($attr)*] $alias $machine $gensym [$($kind)*] [] $out); 534 | _tlsm_states!($machine [$($attr)*] $($states)*); 535 | 536 | type_operators!($gensym $($rest)*); 537 | }; 538 | ($gensym:tt $(#$docs:tt)* ($alias:ident) $machine:ident ($($kind:tt)*): $out:tt { $($states:tt)* } $($rest:tt)*) => { 539 | _tlsm_machine!([$($docs)*] [] $alias $machine $gensym [$($kind)*] [] $out); 540 | _tlsm_states!($machine [] $($states)*); 541 | 542 | type_operators!($gensym $($rest)*); 543 | }; 544 | 545 | ($gensym:tt) => {}; 546 | } 547 | 548 | #[macro_export] 549 | macro_rules! _tlsm_parse_type { 550 | ((@ $external:ident $arg:tt $($more:tt)+)) => { 551 | <_tlsm_parse_type!($arg) as $external< $(_tlsm_parse_type!($more)),+ >>::Output 552 | }; 553 | ((@ $external:ident $arg:tt)) => { 554 | <_tlsm_parse_type!($arg) as $external>::Output 555 | }; 556 | (($parameterized:ident $($arg:tt)*)) => { 557 | $parameterized<$(_tlsm_parse_type!($arg)),*> 558 | }; 559 | ($constant:ident) => { 560 | $constant 561 | }; 562 | } 563 | 564 | #[macro_export] 565 | macro_rules! _tlsm_states { 566 | (@bounds $attrs:tt $machine:ident $implinfo:tt [$($bounds:tt)*] [$($queue:tt)*] (& $arg:tt where $($extra:tt)*)) => { 567 | _tlsm_states!(@bounds $attrs $machine $implinfo [$($bounds)* $($extra)*] [$($queue)*] $arg); 568 | }; 569 | (@bounds $attrs:tt $machine:ident $implinfo:tt $bounds:tt [$($queue:tt)*] (% $arg:tt $($more:tt)*)) => { 570 | _tlsm_states!(@bounds $attrs $machine $implinfo $bounds [$($more)* $($queue)*] $arg); 571 | }; 572 | (@bounds $attrs:tt $machine:ident $implinfo:tt [$($bounds:tt)*] [$($queue:tt)*] (# $arg:tt $($more:tt)+)) => { 573 | _tlsm_states!(@bounds $attrs $machine $implinfo 574 | [$($bounds)* (_tlsm_states!(@output $machine $arg): 575 | $machine< $(_tlsm_states!(@output $machine $more)),+ >)] [$($more)* $($queue)*] $arg); 576 | }; 577 | (@bounds $attrs:tt $machine:ident $implinfo:tt [$($bounds:tt)*] [$($queue:tt)*] (@ $external:ident $arg:tt $($more:tt)+)) => { 578 | _tlsm_states!(@bounds $attrs $machine $implinfo 579 | [$($bounds)* (_tlsm_states!(@output $machine $arg): 580 | $external< $(_tlsm_states!(@output $machine $more)),+ >)] [$($more)* $($queue)*] $arg); 581 | }; 582 | (@bounds $attrs:tt $machine:ident $implinfo:tt [$($bounds:tt)*] [$($queue:tt)*] (# $arg:tt)) => { 583 | _tlsm_states!(@bounds $attrs $machine $implinfo 584 | [$($bounds)* (_tlsm_states!(@output $machine $arg): $machine)] [$($queue)*] $arg); 585 | }; 586 | (@bounds $attrs:tt $machine:ident $implinfo:tt [$($bounds:tt)*] [$($queue:tt)*] (@ $external:ident $arg:tt)) => { 587 | _tlsm_states!(@bounds $attrs $machine $implinfo 588 | [$($bounds)* (_tlsm_states!(@output $machine $arg): $external)] [$($queue)*] $arg); 589 | }; 590 | (@bounds $attrs:tt $machine:ident $implinfo:tt $bounds:tt [$($queue:tt)*] ($parameterized:ident $arg:tt $($args:tt)*)) => { 591 | _tlsm_states!(@bounds $attrs $machine $implinfo $bounds [$($args)* $($queue)*] $arg); 592 | }; 593 | (@bounds $attrs:tt $machine:ident $implinfo:tt $bounds:tt [$next:tt $($queue:tt)*] $constant:ident) => { 594 | _tlsm_states!(@bounds $attrs $machine $implinfo $bounds [$($queue)*] $next); 595 | }; 596 | (@bounds $attrs:tt $machine:ident { $($implinfo:tt)* } $bounds:tt [] $constant:ident) => { 597 | _tlsm_states!(@implement $attrs $machine $bounds $($implinfo)*); 598 | }; 599 | (@maybedefault $attrs:tt $machine:ident $quantified:tt [$($input:tt)*] => $output:tt) => { 600 | _tlsm_states!(@bounds $attrs $machine { [] $quantified [$($input)*] => $output } [] [] $output); 601 | }; 602 | (@maybedefault $attrs:tt $machine:ident $quantified:tt {$($input:tt)*} => $output:tt) => { 603 | _tlsm_states!(@bounds $attrs $machine { [default] $quantified [$($input)*] => $output } [] [] $output); 604 | }; 605 | (@dispatchgroup $attrs:tt $machine:ident $quantified:tt $($head:tt $body:tt $tail:tt)*) => { 606 | $(_tlsm_states!(@dispatch $attrs $machine $quantified $head $body $tail);)* 607 | }; 608 | (@dispatch [$($attr:meta)*] $machine:ident $quantified:tt # [$newattr:meta] { $($head:tt $body:tt $tail:tt)* }) => { 609 | _tlsm_states!(@dispatchgroup [$($attr)* $newattr] $machine $quantified $($head $body $tail)*); 610 | }; 611 | (@dispatch $attrs:tt $machine:ident ($(($lsym:ident: $lbound:tt))*) forall ($($rsym:ident: $rbound:tt),*) { $($head:tt $body:tt $tail:tt)* }) => { 612 | _tlsm_states!(@dispatchgroup $attrs $machine ($(($lsym: $lbound))* $(($rsym: $rbound))*) $($head $body $tail)*); 613 | }; 614 | (@dispatch $attrs:tt $machine:ident $quantified:tt $input:tt => $output:tt) => { 615 | _tlsm_states!(@maybedefault $attrs $machine $quantified $input => $output); 616 | }; 617 | (@implement [$($attr:meta)*] $machine:ident [$(($($constraint:tt)*))+] [$($default:tt)*] ($(($sym:ident: $bound:ident))+) [$head:tt $(, $input:tt)+] => $output:tt) => { 618 | $(#[$attr])* 619 | impl<$($sym: $bound),+> $machine< $(_tlsm_parse_type!($input)),+ > for _tlsm_parse_type!($head) where $($($constraint)*),+ 620 | { 621 | $($default)* type Output = _tlsm_states!(@output $machine $output); 622 | } 623 | }; 624 | (@implement [$($attr:meta)*] $machine:ident [$(($($constraint:tt)*))+] [$($default:tt)*] ($(($sym:ident: $bound:ident))+) [$head:tt] => $output:tt) => { 625 | $(#[$attr])* 626 | impl<$($sym: $bound),+> $machine for _tlsm_parse_type!($head) where $($($constraint)*),+ 627 | { 628 | $($default)* type Output = _tlsm_states!(@output $machine $output); 629 | } 630 | }; 631 | (@implement [$($attr:meta)*] $machine:ident [$(($($constraint:tt)*))+] [$($default:tt)*] () [$head:tt $(, $input:tt)+] => $output:tt) => { 632 | $(#[$attr])* 633 | impl $machine< $(_tlsm_parse_type!($input)),+ > for _tlsm_parse_type!($head) where $($($constraint)*),+ 634 | { 635 | $($default)* type Output = _tlsm_states!(@output $machine $output); 636 | } 637 | }; 638 | (@implement [$($attr:meta)*] $machine:ident [$(($($constraint:tt)*))+] [$($default:tt)*] () [$head:tt] => $output:tt) => { 639 | $(#[$attr])* 640 | impl $machine for _tlsm_parse_type!($head) where $($($constraint)*),+ 641 | { 642 | $($default)* type Output = _tlsm_states!(@output $machine $output); 643 | } 644 | }; 645 | (@implement [$($attr:meta)*] $machine:ident [] [$($default:tt)*] ($(($sym:ident: $bound:ident))+) [$head:tt $(, $input:tt)+] => $output:tt) => { 646 | $(#[$attr])* 647 | impl<$($sym: $bound),+> $machine< $(_tlsm_parse_type!($input)),+ > for _tlsm_parse_type!($head) { 648 | $($default)* type Output = _tlsm_states!(@output $machine $output); 649 | } 650 | }; 651 | (@implement [$($attr:meta)*] $machine:ident [] [$($default:tt)*] ($(($sym:ident: $bound:ident))+) [$head:tt] => $output:tt) => { 652 | $(#[$attr])* 653 | impl<$($sym: $bound),+> $machine for _tlsm_parse_type!($head) { 654 | $($default)* type Output = _tlsm_states!(@output $machine $output); 655 | } 656 | }; 657 | (@implement [$($attr:meta)*] $machine:ident [] [$($default:tt)*] () [$head:tt $(, $input:tt)+] => $output:tt) => { 658 | $(#[$attr])* 659 | impl $machine< $(_tlsm_parse_type!($input)),+ > for _tlsm_parse_type!($head) { 660 | $($default)* type Output = _tlsm_states!(@output $machine $output); 661 | } 662 | }; 663 | (@implement [$($attr:meta)*] $machine:ident [] [$($default:tt)*] () [$head:tt] => $output:tt) => { 664 | $(#[$attr])* 665 | impl $machine for _tlsm_parse_type!($head) { 666 | $($default)* type Output = _tlsm_states!(@output $machine $output); 667 | } 668 | }; 669 | (@output $machine:ident (& $arg:tt $($extra:tt)*)) => { 670 | _tlsm_states!(@output $machine $arg) 671 | }; 672 | (@output $machine:ident (# $arg:tt $($more:tt)+)) => { 673 | <_tlsm_states!(@output $machine $arg) as $machine< $(_tlsm_states!(@output $machine $more)),+ >>::Output 674 | }; 675 | (@output $machine:ident (# $arg:tt)) => { 676 | <_tlsm_states!(@output $machine $arg) as $machine>::Output 677 | }; 678 | (@output $machine:ident (% $arg:tt $($more:tt)+)) => { 679 | <_tlsm_states!(@output $machine $arg) as $machine< $(_tlsm_states!(@output $machine $more)),+ >>::Output 680 | }; 681 | (@output $machine:ident (% $arg:tt)) => { 682 | <_tlsm_states!(@output $machine $arg) as $machine>::Output 683 | }; 684 | (@output $machine:ident (@ $external:ident $arg:tt $($more:tt)+)) => { 685 | <_tlsm_states!(@output $machine $arg) as $external< $(_tlsm_states!(@output $machine $more)),+ >>::Output 686 | }; 687 | (@output $machine:ident (@ $external:ident $arg:tt)) => { 688 | <_tlsm_states!(@output $machine $arg) as $external>::Output 689 | }; 690 | (@output $machine:ident ($parameterized:ident $($arg:tt)+)) => { 691 | $parameterized<$(_tlsm_states!(@output $machine $arg)),+> 692 | }; 693 | (@output $machine:ident $constant:ident) => { 694 | $constant 695 | }; 696 | (@reduceattrs [$($attr:tt)*] [$($specific:tt)*] $machine:ident $head:tt $body:tt $tail:tt) => { 697 | _tlsm_states!(@dispatch [$($attr)* $($specific)*] $machine () $head $body $tail); 698 | }; 699 | ($machine:ident $attrs:tt $($(# $specific:tt)* $head:tt $body:tt $tail:tt)*) => { 700 | $(_tlsm_states!(@reduceattrs $attrs [$($specific)*] $machine $head $body $tail);)* 701 | }; 702 | } 703 | 704 | #[macro_export] 705 | macro_rules! _tlsm_machine { 706 | ([$($docs:tt)*] $attrs:tt $alias:ident $machine:ident [$gensym:ident $(, $gensyms:ident)*] [_ , $($kinds:tt)+] [$($accum:tt)*] $out:tt) => { 707 | _tlsm_machine!(@cont [$($docs)*] $attrs $alias $machine [$($gensyms),*] [$($kinds)+] [$($accum)* ($gensym)] $out); 708 | }; 709 | (@cont $docs:tt $attrs:tt $alias:ident $machine:ident [$gensym:ident $(, $gensyms:ident)*] [_ , $($kinds:tt)+] [$($accum:tt)*] $out:tt) => { 710 | _tlsm_machine!(@cont $docs $attrs $alias $machine [$($gensyms),*] [$($kinds)+] [$($accum)* ($gensym)] $out); 711 | }; 712 | ([$($docs:tt)*] $attrs:tt $alias:ident $machine:ident [$gensym:ident $(, $gensyms:ident)*] [_] [$($accum:tt)*] $out:tt) => { 713 | _tlsm_machine!(@cont [$($docs)*] $attrs $alias $machine [$($gensyms),*] [] [$($accum)* ($gensym)] $out); 714 | }; 715 | (@cont $docs:tt $attrs:tt $alias:ident $machine:ident [$gensym:ident $(, $gensyms:ident)*] [_] [$($accum:tt)*] $out:tt) => { 716 | _tlsm_machine!(@cont $docs $attrs $alias $machine [$($gensyms),*] [] [$($accum)* ($gensym)] $out); 717 | }; 718 | ([$($docs:tt)*] $attrs:tt $alias:ident $machine:ident $gensym:tt [$ksym:ident: _ , $($kinds:tt)+] [$($accum:tt)*] $out:tt) => { 719 | First parameter cannot be named; use Self instead. 720 | }; 721 | (@cont $docs:tt $attrs:tt $alias:ident $machine:ident $gensym:tt [$ksym:ident: _ , $($kinds:tt)+] [$($accum:tt)*] $out:tt) => { 722 | _tlsm_machine!(@cont $docs $attrs $alias $machine $gensym [$($kinds)+] [$($accum)* ($ksym)] $out); 723 | }; 724 | ([$($docs:tt)*] $attrs:tt $alias:ident $machine:ident $gensym:tt [$ksym:ident: _] [$($accum:tt)*] $out:tt) => { 725 | First parameter cannot be named; use Self instead. 726 | }; 727 | (@cont $docs:tt $attrs:tt $alias:ident $machine:ident $gensym:tt [$ksym:ident: _] [$($accum:tt)*] $out:tt) => { 728 | _tlsm_machine!(@cont $docs $attrs $alias $machine $gensym [] [$($accum)* ($ksym)] $out); 729 | }; 730 | ([$($docs:tt)*] $attrs:tt $alias:ident $machine:ident $gensym:tt [$ksym:ident: $kind:tt, $($kinds:tt)+] [$($accum:tt)*] $out:tt) => { 731 | First parameter cannot be named; use Self instead. 732 | }; 733 | (@cont $docs:tt $attrs:tt $alias:ident $machine:ident $gensym:tt [$ksym:ident: $kind:tt, $($kinds:tt)+] [$($accum:tt)*] $out:tt) => { 734 | _tlsm_machine!(@cont $docs $attrs $alias $machine $gensym [$($kinds)+] [$($accum)* ($ksym: $kind)] $out); 735 | }; 736 | ([$($docs:tt)*] $attrs:tt $alias:ident $machine:ident $gensym:tt [$ksym:ident: $kind:tt] [$($accum:tt)*] $out:tt) => { 737 | First parameter cannot be named; use Self instead. 738 | }; 739 | (@cont $docs:tt $attrs:tt $alias:ident $machine:ident $gensym:tt [$ksym:ident: $kind:tt] [$($accum:tt)*] $out:tt) => { 740 | _tlsm_machine!(@cont $docs $attrs $alias $machine $gensym [] [$($accum)* ($ksym: $kind)] $out); 741 | }; 742 | ([$($docs:tt)*] $attrs:tt $alias:ident $machine:ident [$gensym:ident $(, $gensyms:ident)*] [$kind:tt , $($kinds:tt)+] [$($accum:tt)*] $out:tt) => { 743 | _tlsm_machine!(@cont [$($docs)*] $attrs $alias $machine [$($gensyms),*] [$($kinds)+] [$($accum)* ($gensym: $kind)] $out); 744 | }; 745 | (@cont $docs:tt $attrs:tt $alias:ident $machine:ident [$gensym:ident $(, $gensyms:ident)*] [$kind:tt , $($kinds:tt)+] [$($accum:tt)*] $out:tt) => { 746 | _tlsm_machine!(@cont $docs $attrs $alias $machine [$($gensyms),*] [$($kinds)+] [$($accum)* ($gensym: $kind)] $out); 747 | }; 748 | ([$($docs:tt)*] $attrs:tt $alias:ident $machine:ident [$gensym:ident $(, $gensyms:ident)*] [$kind:tt] [$($accum:tt)*] $out:tt) => { 749 | _tlsm_machine!(@cont [$($docs)*] $attrs $alias $machine [$($gensyms),*] [] [$($accum)* ($gensym: $kind)] $out); 750 | }; 751 | (@cont $docs:tt $attrs:tt $alias:ident $machine:ident [$gensym:ident $(, $gensyms:ident)*] [$kind:tt] [$($accum:tt)*] $out:tt) => { 752 | _tlsm_machine!(@cont $docs $attrs $alias $machine [$($gensyms),*] [] [$($accum)* ($gensym: $kind)] $out); 753 | }; 754 | (@cont [$($docs:tt)*] [$($attr:tt)*] $alias:ident $machine:ident $gensym:tt [] [($fsym:ident $($fbound:tt)*) $(($sym:ident $($bound:tt)*))+] _) => { 755 | $(#$docs)* 756 | $(#$attr)* 757 | pub trait $machine < $($sym $($bound)*),+ > $($fbound)* { 758 | type Output; 759 | } 760 | 761 | $(#$attr)* 762 | pub type $alias < $fsym $($fbound)* $(, $sym $($bound)*)+ > = <$fsym as $machine< $($sym),+ >>::Output; 763 | }; 764 | (@cont [$($docs:tt)*] [$($attr:tt)*] $alias:ident $machine:ident $gensym:tt [] [($fsym:ident $($fbound:tt)*)] _) => { 765 | $(#$docs)* 766 | $(#$attr)* 767 | pub trait $machine $($fbound)* { 768 | type Output; 769 | } 770 | 771 | $(#$attr)* 772 | pub type $alias < $fsym $($fbound)* > = <$fsym as $machine>::Output; 773 | }; 774 | (@cont [$($docs:tt)*] [$($attr:tt)*] $alias:ident $machine:ident $gensym:tt [] [($fsym:ident $($fbound:tt)*) $(($sym:ident $($bound:tt)*))+] ($parameterized:ident $($param:tt)*)) => { 775 | $(#$docs)* 776 | $(#$attr)* 777 | pub trait $machine < $($sym $($bound)*),+ > $($fbound)* { 778 | type Output: $parameterized<$(_tlsm_parse_type!($param)),*>; 779 | } 780 | 781 | $(#$attr)* 782 | pub type $alias < $fsym $($fbound)* $(, $sym $($bound)*)+ > = <$fsym as $machine< $($sym),+ >>::Output; 783 | }; 784 | (@cont [$($docs:tt)*] [$($attr:tt)*] $alias:ident $machine:ident $gensym:tt [] [($fsym:ident $($fbound:tt)*)] ($parameterized:ident $($param:tt)*)) => { 785 | $(#$docs)* 786 | $(#$attr)* 787 | pub trait $machine $($fbound)* { 788 | type Output: $parameterized<$(_tlsm_parse_type!($param)),*>; 789 | } 790 | 791 | $(#$attr)* 792 | pub type $alias < $fsym $($fbound)* > = <$fsym as $machine>::Output; 793 | }; 794 | (@cont [$($docs:tt)*] [$($attr:tt)*] $alias:ident $machine:ident $gensym:tt [] [($fsym:ident $($fbound:tt)*) $(($sym:ident $($bound:tt)*))+] $out:ident) => { 795 | $(#$docs)* 796 | $(#$attr)* 797 | pub trait $machine < $($sym $($bound)*),+ > $($fbound)* { 798 | type Output: $out; 799 | } 800 | 801 | $(#$attr)* 802 | pub type $alias < $fsym $($fbound)* $(, $sym $($bound)*)+ > = <$fsym as $machine< $($sym),+ >>::Output; 803 | }; 804 | (@cont [$($docs:tt)*] [$($attr:tt)*] $alias:ident $machine:ident $gensym:tt [] [($fsym:ident $($fbound:tt)*)] $out:ident) => { 805 | $(#$docs)* 806 | $(#$attr)* 807 | pub trait $machine $($fbound)* { 808 | type Output: $out; 809 | } 810 | 811 | $(#$attr)* 812 | pub type $alias < $fsym $($fbound)* > = <$fsym as $machine>::Output; 813 | }; 814 | } 815 | 816 | #[macro_export] 817 | macro_rules! _tlsm_meta_filter_struct { 818 | ([$($preceding:tt)*] #[struct: $attr:meta] $($more:tt)*) => (_tlsm_meta_filter_struct!([$($preceding)* #[$attr]] $($more)*);); 819 | ([$($preceding:tt)*] #$attr:tt $($more:tt)*) => (_tlsm_meta_filter_struct!([$($preceding)* #$attr] $($more)*);); 820 | ([$($preceding:tt)*] $($decl:tt)*) => ($($preceding)* $($decl)*); 821 | } 822 | 823 | #[macro_export] 824 | macro_rules! _tlsm_meta_filter_impl { 825 | ([$($preceding:tt)*] #[impl: $attr:meta] $($more:tt)*) => (_tlsm_meta_filter_impl!([$($preceding)* #[$attr]] $($more)*);); 826 | ($preceding:tt #[derive $traits:tt] $($more:tt)*) => (_tlsm_meta_filter_impl!($preceding $($more)*);); // Friends don't let friends derive drunk! 827 | ([$($preceding:tt)*] #$attr:tt $($more:tt)*) => (_tlsm_meta_filter_impl!([$($preceding)* #$attr] $($more)*);); 828 | ([$($preceding:tt)*] $($decl:tt)*) => ($($preceding)* $($decl)*); 829 | } 830 | 831 | #[macro_export] 832 | macro_rules! _tlsm_data { 833 | ($attrs:tt @parameterized $name:ident [$gensym:ident $(, $next:ident)*] [$($args:tt)*] [$($bounds:tt)*] [$($phantom:tt)*] _) => { 834 | _tlsm_data!($attrs @parameterized $name [$($next),*] [$($args)* ($gensym)] [$($bounds)* ($gensym)] [$($phantom)* ($gensym)]); 835 | }; 836 | ($attrs:tt @parameterized $name:ident [$gensym:ident $(, $next:ident)*] [$($args:tt)*] [$($bounds:tt)*] [$($phantom:tt)*] _ , $($rest:tt)*) => { 837 | _tlsm_data!($attrs @parameterized $name [$($next),*] [$($args)* ($gensym)] [$($bounds)* ($gensym)] [$($phantom)* ($gensym)] $($rest)*); 838 | }; 839 | ($attrs:tt @parameterized $name:ident [$gensym:ident $(, $next:ident)*] [$($args:tt)*] [$($bounds:tt)*] [$($phantom:tt)*] $kind:ident = $default:ty) => { 840 | _tlsm_data!($attrs @parameterized $name [$($next),*] [$($args)* ($gensym: $kind = $default)] [$($bounds)* ($gensym: $kind)] [$($phantom)* ($gensym)]); 841 | }; 842 | ($attrs:tt @parameterized $name:ident [$gensym:ident $(, $next:ident)*] [$($args:tt)*] [$($bounds:tt)*] [$($phantom:tt)*] $kind:ident = $default:ty , $($rest:tt)*) => { 843 | _tlsm_data!($attrs @parameterized $name [$($next),*] [$($args)* ($gensym: $kind = $default)] [$($bounds)* ($gensym: $kind)] [$($phantom)* ($gensym)] $($rest)*); 844 | }; 845 | ($attrs:tt @parameterized $name:ident [$gensym:ident $(, $next:ident)*] [$($args:tt)*] [$($bounds:tt)*] [$($phantom:tt)*] $kind:ident) => { 846 | _tlsm_data!($attrs @parameterized $name [$($next),*] [$($args)* ($gensym: $kind)] [$($bounds)* ($gensym: $kind)] [$($phantom)* ($gensym)]); 847 | }; 848 | ($attrs:tt @parameterized $name:ident [$gensym:ident $(, $next:ident)*] [$($args:tt)*] [$($bounds:tt)*] [$($phantom:tt)*] $kind:ident , $($rest:tt)*) => { 849 | _tlsm_data!($attrs @parameterized $name [$($next),*] [$($args)* ($gensym: $kind)] [$($bounds)* ($gensym: $kind)] [$($phantom)* ($gensym)] $($rest)*); 850 | }; 851 | ([$group:ident $derives:tt [$($specific:tt)*] $($attr:tt)*] @parameterized $name:ident $gensyms:tt [$(($asym:ident $($args:tt)*))*] [$(($bsym:ident $($bounds:tt)*))*] [$(($($phantom:tt)*))*]) => { 852 | _tlsm_meta_filter_struct! { [] 853 | $(#$attr)* 854 | $(#$specific)* 855 | 856 | pub struct $name < $($asym $($args)*),* >($(::std::marker::PhantomData<$($phantom)*>),*); 857 | } 858 | 859 | _tlsm_meta_filter_impl! { [] 860 | $(#$attr)* 861 | $(#$specific)* 862 | 863 | impl< $($bsym $($bounds)*),* > $group for $name<$($($phantom)*),*> {} 864 | } 865 | }; 866 | ([$group:ident $derives:tt [$($specific:tt)*] $($attr:tt)*] $gensym:tt # $nextspecific:tt $($rest:tt)*) => { 867 | _tlsm_data!([$group $derives [$($specific)* $nextspecific] $($attr)*] $gensym $($rest)*); 868 | }; 869 | ([$group:ident () [$($specific:tt)*] $($attr:tt)*] $gensym:tt DEFAULT, $($rest:tt)*) => { 870 | _tlsm_meta_filter_impl! { [] 871 | $(#$attr)* 872 | $(#$specific)* 873 | 874 | impl $group for T {} 875 | } 876 | 877 | _tlsm_data!([$group () [] $($attr)*] $gensym $($rest)*); 878 | }; 879 | ([$group:ident ($fbound:ident $(+ $bound:ident)*) [$($specific:tt)*] $($attr:tt)*] $gensym:tt DEFAULT, $($rest:tt)*) => { 880 | _tlsm_meta_filter_impl! { [] 881 | $(#$attr)* 882 | $(#$specific)* 883 | 884 | impl $group for T where T: $fbound $(+ $bound)* {} 885 | } 886 | 887 | _tlsm_data!([$group ($fbound $(+ $bound)*) [] $($attr)*] $gensym $($rest)*); 888 | }; 889 | ([$group:ident $derives:tt [$($specific:tt)*] $($attr:tt)*] $gensym:tt $name:ident, $($rest:tt)*) => { 890 | _tlsm_meta_filter_struct! { [] 891 | $(#$attr)* 892 | $(#$specific)* 893 | 894 | pub struct $name; 895 | } 896 | 897 | _tlsm_meta_filter_impl! { [] 898 | $(#$attr)* 899 | $(#$specific)* 900 | 901 | impl $group for $name {} 902 | } 903 | 904 | _tlsm_data!([$group $derives [] $($attr)*] $gensym $($rest)*); 905 | }; 906 | ([$group:ident $derives:tt [$($specific:tt)*] $($attr:tt)*] $gensym:tt $name:ident($($args:tt)*), $($rest:tt)*) => { 907 | _tlsm_data!([$group $derives [$($specific)*] $($attr)*] @parameterized $name $gensym [] [] [] $($args)*); 908 | _tlsm_data!([$group $derives [] $($attr)*] $gensym $($rest)*); 909 | }; 910 | ($attrs:tt $gensym:tt) => {}; 911 | } 912 | 913 | #[macro_export] 914 | macro_rules! _tlsm_concrete { 915 | ($attrs:tt $output:ty; @parameterized $name:ident => $value:expr; $gensym:tt [$($args:tt)*] [$($bounds:tt)*] [$($syms:ident)*] $sym:ident: $kind:ident = $default:ty) => { 916 | _tlsm_concrete!($attrs $output; @parameterized $name => $value; $gensym [$($args)* ($sym: $kind = $default)] [$($bounds)* ($sym: $kind)] [$($syms)* $sym]); 917 | }; 918 | ($attrs:tt $output:ty; @parameterized $name:ident => $value:expr; $gensym:tt [$($args:tt)*] [$($bounds:tt)*] [$($syms:ident)*] $sym:ident: $kind:ident = $default:ty , $($rest:tt)*) => { 919 | _tlsm_concrete!($attrs $output; @parameterized $name => $value; $gensym [$($args)* ($sym: $kind = $default)] [$($bounds)* ($sym: $kind)] [$($syms)* $sym] $($rest)*); 920 | }; 921 | ($attrs:tt $output:ty; @parameterized $name:ident => $value:expr; $gensym:tt [$($args:tt)*] [$($bounds:tt)*] [$($syms:ident)*] $sym:ident: $kind:ident) => { 922 | _tlsm_concrete!($attrs $output; @parameterized $name => $value; $gensym [$($args)* ($sym: $kind)] [$($bounds)* ($sym: $kind)] [$($syms)* $sym]); 923 | }; 924 | ($attrs:tt $output:ty; @parameterized $name:ident => $value:expr; $gensym:tt [$($args:tt)*] [$($bounds:tt)*] [$($syms:ident)*] $sym:ident: $kind:ident , $($rest:tt)*) => { 925 | _tlsm_concrete!($attrs $output; @parameterized $name => $value; $gensym [$($args)* ($sym: $kind)] [$($bounds)* ($sym: $kind)] [$($syms)* $sym] $($rest)*); 926 | }; 927 | ($attrs:tt $output:ty; @parameterized $name:ident => $value:expr; [$gensym:ident $(, $next:ident)*] [$($args:tt)*] [$($bounds:tt)*] $syms:tt $kind:ident = $default:ty) => { 928 | _tlsm_concrete!($attrs $output; @parameterized $name => $value; [$($next),*] [$($args)* ($gensym: $kind = $default)] [$($bounds)* ($gensym: $kind)] $syms); 929 | }; 930 | ($attrs:tt $output:ty; @parameterized $name:ident => $value:expr; [$gensym:ident $(, $next:ident)*] [$($args:tt)*] [$($bounds:tt)*] $syms:tt $kind:ident = $default:ty , $($rest:tt)*) => { 931 | _tlsm_concrete!($attrs $output; @parameterized $name => $value; [$($next),*] [$($args)* ($gensym: $kind = $default)] [$($bounds)* ($gensym: $kind)] $syms $($rest)*); 932 | }; 933 | ($attrs:tt $output:ty; @parameterized $name:ident => $value:expr; [$gensym:ident $(, $next:ident)*] [$($args:tt)*] [$($bounds:tt)*] $syms:tt $kind:ident) => { 934 | _tlsm_concrete!($attrs $output; @parameterized $name => $value; [$($next),*] [$($args)* ($gensym: $kind)] [$($bounds)* ($gensym: $kind)] $syms); 935 | }; 936 | ($attrs:tt $output:ty; @parameterized $name:ident => $value:expr; [$gensym:ident $(, $next:ident)*] [$($args:tt)*] [$($bounds:tt)*] $syms:tt $kind:ident , $($rest:tt)*) => { 937 | _tlsm_concrete!($attrs $output; @parameterized $name => $value; [$($next),*] [$($args)* ($gensym: $kind)] [$($bounds)* ($gensym: $kind)] $syms $($rest)*); 938 | }; 939 | ([$group:ident $derives:tt [$($specific:tt)*] $($attr:tt)*] $output:ty; $gensym:tt # $nextspecific:tt $($rest:tt)*) => { 940 | _tlsm_concrete!([$group $derives [$($specific)* $nextspecific] $($attr)*] $output; $gensym $($rest)*); 941 | }; 942 | ([$group:ident $derives:tt [$($specific:tt)*] $($attr:tt)*] $output:ty; @parameterized $name:ident => $value:expr; $gensyms:tt [$(($tysym:ident: $($args:tt)*))*] [$(($bsym:ident: $bound:ident))*] [$($sym:ident)*]) => { 943 | _tlsm_meta_filter_struct! { [] 944 | $(#$attr)* 945 | $(#$specific)* 946 | pub struct $name < $($tysym: $($args)*),* >($(::std::marker::PhantomData<$tysym>),*); 947 | } 948 | 949 | _tlsm_meta_filter_impl! { [] 950 | $(#$attr)* 951 | $(#$specific)* 952 | impl< $($bsym: $bound),* > $group for $name<$($bsym),*> { 953 | #[allow(non_snake_case)] 954 | fn reify() -> $output { $(let $sym = <$sym>::reify();)* $value } 955 | } 956 | } 957 | }; 958 | ([$group:ident () [$($specific:tt)*] $($attr:tt)*] $output:ty; $gensym:tt DEFAULT => $value:expr, $($rest:tt)*) => { 959 | _tlsm_meta_filter_impl! { [] 960 | $(#$attr)* 961 | $(#$specific)* 962 | impl $group for T { 963 | default fn reify() -> $output { $value } 964 | } 965 | } 966 | 967 | _tlsm_concrete!([$group () [] $($attr)*] $output; $gensym $($rest)*); 968 | }; 969 | ([$group:ident ($fbound:ident $(+ $bound:ident)*) [$($specific:tt)*] $($attr:tt)*] $output:ty; $gensym:tt DEFAULT => $value:expr, $($rest:tt)*) => { 970 | _tlsm_meta_filter_impl! { [] 971 | $(#$attr)* 972 | $(#$specific)* 973 | impl $group for T where T: $fbound $(+ $bound)* { 974 | default fn reify() -> $output { $value } 975 | } 976 | } 977 | 978 | _tlsm_concrete!([$group ($fbound $(+ $bound)*) [] $($attr)*] $output; $gensym $($rest)*); 979 | }; 980 | ([$group:ident $derives:tt [$($specific:tt)*] $($attr:tt)*] $output:ty; $gensym:tt $name:ident => $value:expr, $($rest:tt)*) => { 981 | _tlsm_meta_filter_struct! { [] 982 | $(#$attr)* 983 | $(#$specific)* 984 | pub struct $name; 985 | } 986 | 987 | _tlsm_meta_filter_impl! { [] 988 | $(#$attr)* 989 | $(#$specific)* 990 | impl $group for $name { 991 | fn reify() -> $output { $value } 992 | } 993 | } 994 | 995 | _tlsm_concrete!([$group $derives [] $($attr)*] $output; $gensym $($rest)*); 996 | }; 997 | ([$group:ident $derives:tt [$($specific:tt)*] $($attr:tt)*] $output:ty; $gensym:tt $name:ident($($args:tt)*) => $value:expr, $($rest:tt)*) => { 998 | _tlsm_concrete!([$group $derives [$($specific)*] $($attr)*] $output; @parameterized $name => $value; $gensym [] [] [] $($args)*); 999 | _tlsm_concrete!([$group $derives [] $($attr)*] $output; $gensym $($rest)*); 1000 | }; 1001 | ($attrs:tt $output:ty; $gensym:tt) => {}; 1002 | } 1003 | 1004 | 1005 | #[cfg(test)] 1006 | mod tests_1 { 1007 | use super::*; 1008 | 1009 | type_operators! { 1010 | [A, B, C, D, E] 1011 | 1012 | concrete Nat => usize { 1013 | P => 0, 1014 | I(N: Nat = P) => 1 + 2 * N, 1015 | O(N: Nat = P) => 2 * N, 1016 | Undefined => panic!("Undefined type-level arithmetic result!"), 1017 | } 1018 | // It's not just for natural numbers! Yes, we can do all sorts of logic here. However, in 1019 | // this example, `Bool` is used later on in implementations that are hidden from you due 1020 | // to their complexity. 1021 | concrete Bool => bool { 1022 | False => false, 1023 | True => true, 1024 | } 1025 | (Pred) Predecessor(Nat): Nat { 1026 | [Undefined] => Undefined 1027 | [P] => Undefined 1028 | forall (N: Nat) { 1029 | [(O N)] => (I (# N)) 1030 | [(I N)] => (O N) 1031 | } 1032 | } 1033 | (Succ) Successor(Nat): Nat { 1034 | [Undefined] => Undefined 1035 | [P] => I 1036 | forall (N: Nat) { 1037 | [(O N)] => (I N) 1038 | [(I N)] => (O (# N)) 1039 | } 1040 | } 1041 | (Sum) Adding(Nat, Nat): Nat { 1042 | [P, P] => P 1043 | forall (N: Nat) { 1044 | [(O N), P] => (O N) 1045 | [(I N), P] => (I N) 1046 | [P, (O N)] => (O N) 1047 | [P, (I N)] => (I N) 1048 | } 1049 | forall (N: Nat, M: Nat) { 1050 | [(O M), (O N)] => (O (# M N)) 1051 | [(I M), (O N)] => (I (# M N)) 1052 | [(O M), (I N)] => (I (# M N)) 1053 | [(I M), (I N)] => (O (# (# M N) I)) 1054 | } 1055 | } 1056 | (Difference) Subtracting(Nat, Nat): Nat { 1057 | forall (N: Nat) { 1058 | [N, P] => N 1059 | } 1060 | forall (N: Nat, M: Nat) { 1061 | [(O M), (O N)] => (O (# M N)) 1062 | [(I M), (O N)] => (I (# M N)) 1063 | [(O M), (I N)] => (I (# (# M N) I)) 1064 | [(I M), (I N)] => (O (# M N)) 1065 | } 1066 | } 1067 | (Product) Multiplying(Nat, Nat): Nat { 1068 | forall (N: Nat) { 1069 | [P, N] => P 1070 | } 1071 | forall (N: Nat, M: Nat) { 1072 | [(O M), N] => (# M (O N)) 1073 | [(I M), N] => (@Adding N (# M (O N))) 1074 | } 1075 | } 1076 | (If) NatIf(Bool, Nat, Nat): Nat { 1077 | forall (T: Nat, U: Nat) { 1078 | [True, T, U] => T 1079 | [False, T, U] => U 1080 | } 1081 | } 1082 | (NatIsUndef) NatIsUndefined(Nat): Bool { 1083 | [Undefined] => True 1084 | [P] => False 1085 | forall (M: Nat) { 1086 | [(O M)] => False 1087 | [(I M)] => False 1088 | } 1089 | } 1090 | (NatUndef) NatUndefined(Nat, Nat): Nat { 1091 | forall (M: Nat) { 1092 | [Undefined, M] => Undefined 1093 | [P, M] => M 1094 | } 1095 | forall (M: Nat, N: Nat) { 1096 | [(O N), M] => M 1097 | [(I N), M] => M 1098 | } 1099 | } 1100 | (TotalDifference) TotalSubtracting(Nat, Nat): Nat { 1101 | [P, P] => P 1102 | [Undefined, P] => Undefined 1103 | forall (N: Nat) { 1104 | [N, Undefined] => Undefined 1105 | [P, (O N)] => (# P N) 1106 | [P, (I N)] => Undefined 1107 | [(O N), P] => (O N) 1108 | [(I N), P] => (I N) 1109 | [Undefined, (O N)] => Undefined 1110 | [Undefined, (I N)] => Undefined 1111 | } 1112 | forall (N: Nat, M: Nat) { 1113 | [(O M), (O N)] => (@NatUndefined (# M N) (O (# M N))) 1114 | [(I M), (O N)] => (@NatUndefined (# M N) (I (# M N))) 1115 | [(O M), (I N)] => (@NatUndefined (# (# M N) I) (I (# (# M N) I))) 1116 | [(I M), (I N)] => (@NatUndefined (# M N) (O (# M N))) 1117 | } 1118 | } 1119 | (Quotient) Quotienting(Nat, Nat): Nat { 1120 | forall (D: Nat) { 1121 | [Undefined, D] => Undefined 1122 | [P, D] => (@NatIf (@NatIsUndefined (@TotalSubtracting P D)) O (@Successor (# (@TotalSubtracting P D) D))) 1123 | } 1124 | forall (N: Nat, D: Nat) { 1125 | [(O N), D] => (@NatIf (@NatIsUndefined (@TotalSubtracting (O N) D)) O (@Successor (# (@TotalSubtracting (O N) D) D))) 1126 | [(I N), D] => (@NatIf (@NatIsUndefined (@TotalSubtracting (I N) D)) O (@Successor (# (@TotalSubtracting (I N) D) D))) 1127 | } 1128 | } 1129 | (Remainder) Remaindering(Nat, Nat): Nat { 1130 | forall (D: Nat) { 1131 | [Undefined, D] => Undefined 1132 | [P, D] => (@NatIf (@NatIsUndefined (@TotalSubtracting P D)) P (# (@TotalSubtracting P D) D)) 1133 | } 1134 | forall (N: Nat, D: Nat) { 1135 | [(O N), D] => (@NatIf (@NatIsUndefined (@TotalSubtracting (O N) D)) (O N) (# (@TotalSubtracting (O N) D) D)) 1136 | [(I N), D] => (@NatIf (@NatIsUndefined (@TotalSubtracting (I N) D)) (I O) (# (@TotalSubtracting (I N) D) D)) 1137 | } 1138 | } 1139 | } 1140 | 1141 | fn invariants() { 1142 | assert_eq!( as Nat>::reify(), 3); 1143 | assert_eq!(> as Nat>::reify(), 5); 1144 | assert_eq!(>, I> as Nat>::reify(), 8); 1145 | assert_eq!(, O> as Nat>::reify(), 1); 1146 | assert_eq!(>>, I> as Nat>::reify(), 5); 1147 | assert_eq!(, I>> as Nat>::reify(), 15); 1148 | assert_eq!(, O> as Nat>::reify(), 1); 1149 | assert_eq!(>>, O>> as Nat>::reify(), 1); 1150 | } 1151 | } 1152 | 1153 | #[cfg(test)] 1154 | mod tests_2 { 1155 | use super::*; 1156 | 1157 | type_operators! { 1158 | [A, B, C, D, E] 1159 | 1160 | data Nat { 1161 | P, 1162 | I(Nat = P), 1163 | O(Nat = P), 1164 | } 1165 | } 1166 | } 1167 | -------------------------------------------------------------------------------- /tests/disable_without_specialization.rs: -------------------------------------------------------------------------------- 1 | #[macro_use] 2 | extern crate type_operators; 3 | 4 | use std::fmt::Debug; 5 | 6 | type_operators! { 7 | [A, B, C, D, E] 8 | 9 | data Nat: Default + Debug where #[derive(Default, Debug)] { 10 | P, 11 | I(Nat = P), 12 | O(Nat = P), 13 | #[cfg(features = "specialization")] 14 | Error, 15 | #[cfg(features = "specialization")] 16 | DEFAULT, 17 | } 18 | 19 | (Sum) Adding(Nat, Nat): Nat { 20 | [P, P] => P 21 | forall (N: Nat) { 22 | [(O N), P] => (O N) 23 | [(I N), P] => (I N) 24 | [P, (O N)] => (O N) 25 | [P, (I N)] => (I N) 26 | } 27 | forall (N: Nat, M: Nat) { 28 | [(O M), (O N)] => (O (# M N)) 29 | [(I M), (O N)] => (I (# M N)) 30 | [(O M), (I N)] => (I (# M N)) 31 | [(I M), (I N)] => (O (# (# M N) I)) 32 | 33 | #[cfg(features = "specialization")] { 34 | {M, N} => Error 35 | } 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /tests/doc_comments.rs: -------------------------------------------------------------------------------- 1 | #[macro_use] 2 | extern crate type_operators; 3 | 4 | use std::fmt::Debug; 5 | 6 | 7 | type_operators! { 8 | [A, B, C, D, E] 9 | 10 | /// This is a doc comment. It should be compiled into a comment *only* on the generated `Nat` 11 | /// trait. 12 | data Nat: Default + Debug where #[derive(Default, Debug)] { 13 | P, 14 | I(Nat = P), 15 | O(Nat = P), 16 | #[cfg(features = "specialization")] 17 | Error, 18 | #[cfg(features = "specialization")] 19 | DEFAULT, 20 | } 21 | 22 | /// As this is also a doc comment, it should also be compiled into a comment *only* on the 23 | /// generated `Adding` trait. 24 | (Sum) Adding(Nat, Nat): Nat { 25 | [P, P] => P 26 | forall (N: Nat) { 27 | [(O N), P] => (O N) 28 | [(I N), P] => (I N) 29 | [P, (O N)] => (O N) 30 | [P, (I N)] => (I N) 31 | } 32 | forall (N: Nat, M: Nat) { 33 | [(O M), (O N)] => (O (# M N)) 34 | [(I M), (O N)] => (I (# M N)) 35 | [(O M), (I N)] => (I (# M N)) 36 | [(I M), (I N)] => (O (# (# M N) I)) 37 | 38 | #[cfg(features = "specialization")] { 39 | {M, N} => Error 40 | } 41 | } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /tests/flexible_machines.rs: -------------------------------------------------------------------------------- 1 | #[macro_use] 2 | extern crate type_operators; 3 | use type_operators::All; 4 | 5 | pub trait Array {} 6 | 7 | type_operators! { 8 | [A, B, C, D, E] 9 | 10 | (Reify) Arrayify(_, T: _): (Array T) { 11 | 12 | } 13 | 14 | (Foo) Bar(All, All, All, All): All { 15 | 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /tests/multi_parameter_data.rs: -------------------------------------------------------------------------------- 1 | #[macro_use] 2 | extern crate type_operators; 3 | 4 | type_operators! { 5 | [A, B, C, D, E] 6 | 7 | concrete Int => isize { 8 | Term => 0, 9 | Zero(X: Int = Term) => 3 * X, 10 | Plus(X: Int = Term) => 3 * X + 1, 11 | Minus(X: Int = Term) => 3 * X - 1, 12 | Undefined => panic!("Error: This type-level Int value is undefined, and cannot be reified!"), 13 | } 14 | 15 | data IntPair { 16 | Int2(Int, Int), 17 | } 18 | 19 | (Int2First) Int2P1(IntPair): Int { 20 | forall (A: Int, B: Int) { 21 | [(Int2 A B)] => A 22 | } 23 | } 24 | 25 | (Int2Second) Int2P2(IntPair): Int { 26 | forall (A: Int, B: Int) { 27 | [(Int2 A B)] => B 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /tests/smallfsck.rs: -------------------------------------------------------------------------------- 1 | extern crate bit_vec; 2 | 3 | #[macro_use] 4 | extern crate type_operators; 5 | 6 | 7 | use bit_vec::BitVec; 8 | 9 | 10 | pub struct State { 11 | loc: usize, 12 | bits: BitVec, 13 | } 14 | 15 | 16 | type_operators! { 17 | [A, B, C, D, E] 18 | 19 | data Program { 20 | Empty, 21 | Left(Program = Empty), 22 | Right(Program = Empty), 23 | Flip(Program = Empty), 24 | Loop(Program = Empty, Program = Empty), 25 | } 26 | 27 | concrete Bit => bool { 28 | F => false, 29 | T => true, 30 | } 31 | 32 | concrete List => BitVec { 33 | Nil => BitVec::new(), 34 | Cons(B: Bit, L: List = Nil) => { let mut tail = L; tail.push(B); tail }, 35 | } 36 | 37 | concrete Smallfsck => State { 38 | St(L: List, C: Bit, R: List) => { 39 | // So, R is backwards here. That's a problem! But no worries - we 40 | // know it's a problem, so now it's less of a problem. ;) 41 | 42 | let mut bits = L; 43 | let loc = bits.len(); 44 | bits.push(C); 45 | bits.extend(R.into_iter().rev()); 46 | 47 | State { 48 | loc: loc, 49 | bits: bits, 50 | } 51 | }, 52 | } 53 | 54 | (Run) Running(Program, Smallfsck): Smallfsck { 55 | forall (P: Program, L: List, C: Bit) { 56 | [(Left P), (St L C Nil)] => (# P (St (Cons C L) F Nil)) 57 | } 58 | forall (P: Program, C: Bit, R: List) { 59 | [(Right P), (St Nil C R)] => (# P (St Nil F (Cons C R))) 60 | } 61 | forall (P: Program, L: List, C: Bit, N: Bit, R: List) { 62 | [(Left P), (St L C (Cons N R))] => (# P (St (Cons C L) N R)) 63 | [(Right P), (St (Cons N L) C R)] => (# P (St L N (Cons C R))) 64 | } 65 | forall (P: Program, L: List, R: List) { 66 | [(Flip P), (St L F R)] => (# P (St L T R)) 67 | [(Flip P), (St L T R)] => (# P (St L F R)) 68 | } 69 | forall (P: Program, Q: Program, L: List, R: List) { 70 | [(Loop P Q), (St L F R)] => (# Q (St L F R)) 71 | [(Loop P Q), (St L T R)] => (# (Loop P Q) (# P (St L T R))) 72 | } 73 | forall (S: Smallfsck) { 74 | [Empty, S] => S 75 | } 76 | } 77 | } 78 | 79 | 80 | macro_rules! sf { 81 | (< $($prog:tt)*) => { Left }; 82 | (> $($prog:tt)*) => { Right }; 83 | (* $($prog:tt)*) => { Flip }; 84 | ([$($prog:tt)*]) => { Loop }; 85 | () => { Nil }; 86 | } 87 | 88 | 89 | type Example = sf!{ 90 | > * > * > * > [ * < ] 91 | }; 92 | -------------------------------------------------------------------------------- /tests/specialization_concrete.rs: -------------------------------------------------------------------------------- 1 | #![cfg_attr(feature = "specialization", feature(specialization))] 2 | 3 | #[macro_use] 4 | extern crate type_operators; 5 | 6 | #[cfg(feature = "specialization")] 7 | mod test { 8 | type_operators! { 9 | [A, B, C, D, E] 10 | 11 | concrete Nat: Default => usize where #[derive(Debug, Default)] { 12 | P => 0, 13 | I(N: Nat = P) => 1 + 2 * N, 14 | O(N: Nat = P) => 2 * N, 15 | Undefined => panic!("Undefined type-level arithmetic result!"), 16 | Error => panic!("Error: Attempted to perform arithmetic on types which do not represent numbers!"), 17 | DEFAULT => panic!("This is not a number!"), 18 | } 19 | 20 | concrete Bool => bool { 21 | False => false, 22 | True => true, 23 | DEFAULT => panic!("This is not a boolean!"), 24 | } 25 | 26 | (Pred) Predecessor(Nat): Nat { 27 | [Undefined] => Undefined 28 | [P] => Undefined 29 | forall (N: Nat) { 30 | [(O N)] => (I (# N)) 31 | [(I N)] => (O N) 32 | {N} => Error 33 | } 34 | } 35 | 36 | (Succ) Successor(Nat): Nat { 37 | [Undefined] => Undefined 38 | [P] => I 39 | forall (N: Nat) { 40 | [(O N)] => (I N) 41 | [(I N)] => (O (# N)) 42 | {N} => Error 43 | } 44 | } 45 | 46 | (Sum) Adding(Nat, Nat): Nat { 47 | [P, P] => P 48 | forall (N: Nat) { 49 | [(O N), P] => (O N) 50 | [(I N), P] => (I N) 51 | [P, (O N)] => (O N) 52 | [P, (I N)] => (I N) 53 | } 54 | forall (N: Nat, M: Nat) { 55 | [(O M), (O N)] => (O (# M N)) 56 | [(I M), (O N)] => (I (# M N)) 57 | [(O M), (I N)] => (I (# M N)) 58 | [(I M), (I N)] => (O (# (# M N) I)) 59 | {M, N} => Error 60 | } 61 | } 62 | 63 | (Difference) Subtracting(Nat, Nat): Nat { 64 | forall (N: Nat) { 65 | [N, P] => N 66 | } 67 | forall (N: Nat, M: Nat) { 68 | [(O M), (O N)] => (O (# M N)) 69 | [(I M), (O N)] => (I (# M N)) 70 | [(O M), (I N)] => (I (# (# M N) I)) 71 | [(I M), (I N)] => (O (# M N)) 72 | {M, N} => Error 73 | } 74 | } 75 | 76 | (Product) Multiplying(Nat, Nat): Nat { 77 | forall (N: Nat) { 78 | [P, N] => P 79 | } 80 | forall (N: Nat, M: Nat) { 81 | [(O M), N] => (# M (O N)) 82 | [(I M), N] => (@Adding N (# M (O N))) 83 | {M, N} => Error 84 | } 85 | } 86 | 87 | (If) NatIf(Bool, Nat, Nat): Nat { 88 | forall (T: Nat, U: Nat) { 89 | [True, T, U] => T 90 | [False, T, U] => U 91 | } 92 | forall (B: Bool, T: Nat, U: Nat) { 93 | {B, T, U} => Error 94 | } 95 | } 96 | 97 | (NatIsUndef) NatIsUndefined(Nat): Bool { 98 | [Undefined] => True 99 | [P] => False 100 | forall (M: Nat) { 101 | [(O M)] => False 102 | [(I M)] => False 103 | {M} => Error 104 | } 105 | } 106 | 107 | (NatUndef) NatUndefined(Nat, Nat): Nat { 108 | forall (M: Nat) { 109 | [Undefined, M] => Undefined 110 | [P, M] => M 111 | } 112 | forall (M: Nat, N: Nat) { 113 | [(O N), M] => M 114 | [(I N), M] => M 115 | {M, N} => Error 116 | } 117 | } 118 | 119 | (TotalDifference) TotalSubtracting(Nat, Nat): Nat { 120 | [P, P] => P 121 | [Undefined, P] => Undefined 122 | forall (N: Nat) { 123 | [N, Undefined] => Undefined 124 | [P, (O N)] => (# P N) 125 | [P, (I N)] => Undefined 126 | [(O N), P] => (O N) 127 | [(I N), P] => (I N) 128 | [Undefined, (O N)] => Undefined 129 | [Undefined, (I N)] => Undefined 130 | } 131 | forall (N: Nat, M: Nat) { 132 | [(O M), (O N)] => (@NatUndefined (# M N) (O (# M N))) 133 | [(I M), (O N)] => (@NatUndefined (# M N) (I (# M N))) 134 | [(O M), (I N)] => (@NatUndefined (# (# M N) I) (I (# (# M N) I))) 135 | [(I M), (I N)] => (@NatUndefined (# M N) (O (# M N))) 136 | {M, N} => Error 137 | } 138 | } 139 | 140 | (Quotient) Quotienting(Nat, Nat): Nat { 141 | forall (D: Nat) { 142 | [Undefined, D] => Undefined 143 | [P, D] => (@NatIf (@NatIsUndefined (@TotalSubtracting P D)) O (@Successor (# (@TotalSubtracting P D) D))) 144 | } 145 | forall (N: Nat, D: Nat) { 146 | [(O N), D] => (@NatIf (@NatIsUndefined (@TotalSubtracting (O N) D)) O (@Successor (# (@TotalSubtracting (O N) D) D))) 147 | [(I N), D] => (@NatIf (@NatIsUndefined (@TotalSubtracting (I N) D)) O (@Successor (# (@TotalSubtracting (I N) D) D))) 148 | {N, D} => Error 149 | } 150 | } 151 | 152 | (Remainder) Remaindering(Nat, Nat): Nat { 153 | forall (D: Nat) { 154 | [Undefined, D] => Undefined 155 | [P, D] => (@NatIf (@NatIsUndefined (@TotalSubtracting P D)) P (# (@TotalSubtracting P D) D)) 156 | } 157 | forall (N: Nat, D: Nat) { 158 | [(O N), D] => (@NatIf (@NatIsUndefined (@TotalSubtracting (O N) D)) (O N) (# (@TotalSubtracting (O N) D) D)) 159 | [(I N), D] => (@NatIf (@NatIsUndefined (@TotalSubtracting (I N) D)) (I O) (# (@TotalSubtracting (I N) D) D)) 160 | {N, D} => Error 161 | } 162 | } 163 | } 164 | 165 | #[test] 166 | fn invariants() { 167 | assert_eq!( as Nat>::reify(), 3); 168 | assert_eq!(> as Nat>::reify(), 5); 169 | assert_eq!(>, I> as Nat>::reify(), 8); 170 | assert_eq!(, O> as Nat>::reify(), 1); 171 | assert_eq!(>>, I> as Nat>::reify(), 5); 172 | assert_eq!(, I>> as Nat>::reify(), 15); 173 | assert_eq!(, O> as Nat>::reify(), 1); 174 | assert_eq!(>>, O>> as Nat>::reify(), 1); 175 | } 176 | 177 | #[test] 178 | #[should_panic] 179 | fn blanketed_1() { 180 | let _ = ::reify(); 181 | } 182 | 183 | #[test] 184 | #[should_panic] 185 | fn blanketed_2() { 186 | let _ = as Nat>::reify(); 187 | } 188 | } 189 | -------------------------------------------------------------------------------- /tests/specialization_data.rs: -------------------------------------------------------------------------------- 1 | #![cfg_attr(feature = "specialization", feature(specialization))] 2 | 3 | #[macro_use] 4 | extern crate type_operators; 5 | 6 | #[cfg(feature = "specialization")] 7 | mod test { 8 | use std::default::Default; 9 | use std::fmt::Debug; 10 | 11 | type_operators! { 12 | [A, B, C, D, E] 13 | 14 | data Nat: Default + Debug where #[derive(Default, Debug)] { 15 | P, 16 | I(Nat = P), 17 | O(Nat = P), 18 | Undefined, 19 | Error, 20 | DEFAULT, 21 | } 22 | 23 | data Bool where #[derive(Default, Debug)] { 24 | False, 25 | True, 26 | DEFAULT, 27 | } 28 | 29 | (Pred) Predecessor(Nat): Nat { 30 | [Undefined] => Undefined 31 | [P] => Undefined 32 | forall (N: Nat) { 33 | [(O N)] => (I (# N)) 34 | [(I N)] => (O N) 35 | {N} => Error 36 | } 37 | } 38 | 39 | (Succ) Successor(Nat): Nat { 40 | [Undefined] => Undefined 41 | [P] => I 42 | forall (N: Nat) { 43 | [(O N)] => (I N) 44 | [(I N)] => (O (# N)) 45 | {N} => Error 46 | } 47 | } 48 | 49 | (Sum) Adding(Nat, Nat): Nat { 50 | [P, P] => P 51 | forall (N: Nat) { 52 | [(O N), P] => (O N) 53 | [(I N), P] => (I N) 54 | [P, (O N)] => (O N) 55 | [P, (I N)] => (I N) 56 | } 57 | forall (N: Nat, M: Nat) { 58 | [(O M), (O N)] => (O (# M N)) 59 | [(I M), (O N)] => (I (# M N)) 60 | [(O M), (I N)] => (I (# M N)) 61 | [(I M), (I N)] => (O (# (# M N) I)) 62 | {M, N} => Error 63 | } 64 | } 65 | 66 | (Difference) Subtracting(Nat, Nat): Nat { 67 | forall (N: Nat) { 68 | [N, P] => N 69 | } 70 | forall (N: Nat, M: Nat) { 71 | [(O M), (O N)] => (O (# M N)) 72 | [(I M), (O N)] => (I (# M N)) 73 | [(O M), (I N)] => (I (# (# M N) I)) 74 | [(I M), (I N)] => (O (# M N)) 75 | {M, N} => Error 76 | } 77 | } 78 | 79 | (Product) Multiplying(Nat, Nat): Nat { 80 | forall (N: Nat) { 81 | [P, N] => P 82 | } 83 | forall (N: Nat, M: Nat) { 84 | [(O M), N] => (# M (O N)) 85 | [(I M), N] => (@Adding N (# M (O N))) 86 | {M, N} => Error 87 | } 88 | } 89 | 90 | (If) NatIf(Bool, Nat, Nat): Nat { 91 | forall (T: Nat, U: Nat) { 92 | [True, T, U] => T 93 | [False, T, U] => U 94 | } 95 | forall (B: Bool, T: Nat, U: Nat) { 96 | {B, T, U} => Error 97 | } 98 | } 99 | 100 | (NatIsUndef) NatIsUndefined(Nat): Bool { 101 | [Undefined] => True 102 | [P] => False 103 | forall (M: Nat) { 104 | [(O M)] => False 105 | [(I M)] => False 106 | {M} => Error 107 | } 108 | } 109 | 110 | (NatUndef) NatUndefined(Nat, Nat): Nat { 111 | forall (M: Nat) { 112 | [Undefined, M] => Undefined 113 | [P, M] => M 114 | } 115 | forall (M: Nat, N: Nat) { 116 | [(O N), M] => M 117 | [(I N), M] => M 118 | {M, N} => Error 119 | } 120 | } 121 | 122 | (TotalDifference) TotalSubtracting(Nat, Nat): Nat { 123 | [P, P] => P 124 | [Undefined, P] => Undefined 125 | forall (N: Nat) { 126 | [N, Undefined] => Undefined 127 | [P, (O N)] => (# P N) 128 | [P, (I N)] => Undefined 129 | [(O N), P] => (O N) 130 | [(I N), P] => (I N) 131 | [Undefined, (O N)] => Undefined 132 | [Undefined, (I N)] => Undefined 133 | } 134 | forall (N: Nat, M: Nat) { 135 | [(O M), (O N)] => (@NatUndefined (# M N) (O (# M N))) 136 | [(I M), (O N)] => (@NatUndefined (# M N) (I (# M N))) 137 | [(O M), (I N)] => (@NatUndefined (# (# M N) I) (I (# (# M N) I))) 138 | [(I M), (I N)] => (@NatUndefined (# M N) (O (# M N))) 139 | {M, N} => Error 140 | } 141 | } 142 | 143 | (Quotient) Quotienting(Nat, Nat): Nat { 144 | forall (D: Nat) { 145 | [Undefined, D] => Undefined 146 | [P, D] => (@NatIf (@NatIsUndefined (@TotalSubtracting P D)) O (@Successor (# (@TotalSubtracting P D) D))) 147 | } 148 | forall (N: Nat, D: Nat) { 149 | [(O N), D] => (@NatIf (@NatIsUndefined (@TotalSubtracting (O N) D)) O (@Successor (# (@TotalSubtracting (O N) D) D))) 150 | [(I N), D] => (@NatIf (@NatIsUndefined (@TotalSubtracting (I N) D)) O (@Successor (# (@TotalSubtracting (I N) D) D))) 151 | {N, D} => Error 152 | } 153 | } 154 | 155 | (Remainder) Remaindering(Nat, Nat): Nat { 156 | forall (D: Nat) { 157 | [Undefined, D] => Undefined 158 | [P, D] => (@NatIf (@NatIsUndefined (@TotalSubtracting P D)) P (# (@TotalSubtracting P D) D)) 159 | } 160 | forall (N: Nat, D: Nat) { 161 | [(O N), D] => (@NatIf (@NatIsUndefined (@TotalSubtracting (O N) D)) (O N) (# (@TotalSubtracting (O N) D) D)) 162 | [(I N), D] => (@NatIf (@NatIsUndefined (@TotalSubtracting (I N) D)) (I O) (# (@TotalSubtracting (I N) D) D)) 163 | {N, D} => Error 164 | } 165 | } 166 | } 167 | 168 | #[test] 169 | fn invariants() { 170 | let _ = as Default>::default(); 171 | let _ = > as Default>::default(); 172 | let _ = >, I> as Default>::default(); 173 | let _ = , O> as Default>::default(); 174 | let _ = >>, I> as Default>::default(); 175 | let _ = , I>> as Default>::default(); 176 | let _ = , O> as Default>::default(); 177 | let _ = >>, O>> as Default>::default(); 178 | } 179 | } 180 | -------------------------------------------------------------------------------- /tests/specific_attrs.rs: -------------------------------------------------------------------------------- 1 | #[macro_use] 2 | extern crate type_operators; 3 | 4 | mod concrete { 5 | type_operators! { 6 | [A, B, C, D, E] 7 | 8 | concrete Nat: Default => usize { 9 | #[derive(Default)] 10 | Z => 0, 11 | #[derive(Default)] 12 | S(N: Nat) => 1 + N, 13 | } 14 | } 15 | } 16 | 17 | mod data { 18 | type_operators! { 19 | [A, B, C, D, E] 20 | 21 | data Nat: Default { 22 | #[derive(Default)] 23 | Z, 24 | #[derive(Default)] 25 | S(Nat), 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /tests/unbounded_parameters.rs: -------------------------------------------------------------------------------- 1 | #[macro_use] 2 | extern crate type_operators; 3 | 4 | type_operators! { 5 | [A, B, C, D, E] 6 | 7 | data List { 8 | Nil, 9 | Cons(_, List), 10 | } 11 | } 12 | --------------------------------------------------------------------------------